Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Projet Calculateur
#1
Bon, mon projet prenant de l'ampleur, je décide d'ouvrir une discussion.

Rappel:
Code Source:

https://bitbucket.org/philippegibault/ca.../src/main/
Reply
#2
Je suis dans les règles.

Donc classique, j'ai implémenté les marines.
Grâce à un service REST:
Code:
curl -XPOST -v -d '{"langage":"fr","idCamp":"1","idFaction":"1","idSousFaction":"1","idSousSousFaction":"1"}' -H "Content-type: application/json" http://localhost:8080/regles/parRecherche

On vérifie:
Code:
[{
    "factory": "com.calculateur.warhammer.data.regles.factory.factory.general.RegleArmureOfContentFactory",
    "ressource": {
        "id": 1,
        "ressource": "com.calculateur.warhammer.dto.regles.faction.general.general"
    },
    "donnees": [],
    "description": "Réduit la PA adverse de 1. La figurine ne doit pas être équipé d\u0027un Bouclier Tempête.",
    "id": 1,
    "nom": "Armure of Content",
    "cleTraduction": "regle.armure.of.content",
    "libelle": "Armure of Content"
}, {
    "factory": "com.calculateur.warhammer.data.regles.factory.factory.space.marine.RegleEtIlsNeConnaitronsPasLaPeurFactory",
    "ressource": {
        "id": 11000,
        "ressource": "com.calculateur.warhammer.dto.regles.faction.space_marine.space_marine"
    },
    "donnees": [],
    "description": "Ignore les malus aux tests d\u0027attrition.",
    "id": 11000,
    "nom": "Et ils ne connaîtrons pas la peur",
    "cleTraduction": "regle.et.il.ne.connaitront.pas.la.peur",
    "libelle": "Et ils ne connaîtrons pas la peur"
}, {
    "factory": "com.calculateur.warhammer.data.regles.factory.factory.space.marine.RegleDisciplineBolterFactory",
    "ressource": {
        "id": 11000,
        "ressource": "com.calculateur.warhammer.dto.regles.faction.space_marine.space_marine"
    },
    "donnees": [],
    "description": "Permet de tirer 2 fois en tir rapide à longue portée si l\u0027arme est un bolter.",
    "id": 11001,
    "nom": "Discipline du Bolter",
    "cleTraduction": "regle.discipline.bolter",
    "libelle": "Discipline du Bolter"
}, {
    "factory": "com.calculateur.warhammer.data.regles.factory.factory.space.marine.RegleAssautPercutantFactory",
    "ressource": {
        "id": 11000,
        "ressource": "com.calculateur.warhammer.dto.regles.faction.space_marine.space_marine"
    },
    "donnees": [],
    "description": "+1 Attaque si l\u0027unité a chargé ou a été chargé ce tour-ci.",
    "id": 11002,
    "nom": "Assaut Percutant",
    "cleTraduction": "regle.assaut.percutant",
    "libelle": "Assaut Percutant"
}, {
    "factory": "com.calculateur.warhammer.data.regles.factory.factory.space.marine.RegleDoctrineTactiqueFactory",
    "ressource": {
        "id": 11000,
        "ressource": "com.calculateur.warhammer.dto.regles.faction.space_marine.space_marine"
    },
    "donnees": [{
        "url": "/spaceMarine/doctrine",
        "ressources": {
            "id": 11000,
            "ressource": "com.calculateur.warhammer.dto.regles.faction.space_marine.space_marine"
        },
        "description": "Les tactiques Space Marine (Dévastator, Tactique et Assaut).",
        "id": 11000,
        "nom": "doctrine.tactique.space.marine",
        "cleTraduction": "donnee.doctrine.tactique",
        "libelle": "Doctrine Tactique"
    }],
    "description": "Les tactiques Space Marine (Dévastator, Tactique et Assaut).",
    "id": 11003,
    "nom": "Doctrine Space Marine",
    "cleTraduction": "donnee.doctrine.tactique",
    "libelle": "Doctrine Tactique"
}] *
Connection #0 to host localhost left intact

J'ai aussi fait l'adepta sororitas:
Code:
[{
    "factory": "com.calculateur.warhammer.data.regles.factory.factory.general.RegleArmureOfContentFactory",
    "ressource": {
        "id": 1,
        "ressource": "com.calculateur.warhammer.dto.regles.faction.general.general"
    },
    "donnees": [],
    "description": "Réduit la PA adverse de 1. La figurine ne doit pas être équipé d\u0027un Bouclier Tempête.",
    "id": 1,
    "nom": "Armure of Content",
    "cleTraduction": "regle.armure.of.content",
    "libelle": "Armure of Content"
}, {
    "factory": "com.calculateur.warhammer.data.regles.factory.factory.adepta.sororitas.RegleBouclierDeLaFoiFactory",
    "ressource": {
        "id": 12000,
        "ressource": "com.calculateur.warhammer.dto.regles.faction.adepta_sororitas.adepta_sororitas"
    },
    "donnees": [],
    "description": "Sauvegarde invulnérable de 6+, sissipe un pouvoir psychique sur 6+.",
    "id": 12000,
    "nom": "Bouclier de la Foi",
    "cleTraduction": "regle.bouclier.foi",
    "libelle": "Bouclier de Foi"
}, {
    "factory": "com.calculateur.warhammer.data.regles.factory.factory.adepta.sororitas.RegleZeloteFactory",
    "ressource": {
        "id": 12000,
        "ressource": "com.calculateur.warhammer.dto.regles.faction.adepta_sororitas.adepta_sororitas"
    },
    "donnees": [],
    "description": "Relance les jets de touche au corps à corps après une charge, avoir été chargé ou après une intervention héroïque.",
    "id": 12001,
    "nom": "Zélote",
    "cleTraduction": "regle.zelote",
    "libelle": "Zélote"
}, {
    "factory": "com.calculateur.warhammer.data.regles.factory.factory.adepta.sororitas.RegleRiteSacreFactory",
    "ressource": {
        "id": 12000,
        "ressource": "com.calculateur.warhammer.dto.regles.faction.adepta_sororitas.adepta_sororitas"
    },
    "donnees": [{
        "url": "/adeptaSororitas/rite",
        "ressources": {
            "id": 12000,
            "ressource": "com.calculateur.warhammer.dto.regles.faction.adepta_sororitas.adepta_sororitas"
        },
        "description": "Liste des rites sacrés de l\u0027adepta sororitas.",
        "id": 12000,
        "nom": "adepta.sororitas.rite",
        "cleTraduction": "donnee.rite.sacre",
        "libelle": "Rites sacrés"
    }],
    "description": "L\u0027enssemble des règle pour les rites sacrés de l\u0027adapta sororitas.",
    "id": 12002,
    "nom": "Rite Sacré",
    "cleTraduction": "regle.rite.sacre",
    "libelle": "Rite sacré"
}]
Reply
#3
Délire, après un décompte, je fais 314 tests.

Dont 136 pour la fabrication des règles/auras.
Enfin du sérieux (pas comme l'endroit chez les ploucs où j'étais avant). Doom
Reply
#4
On continue par une armée (qui pue à tous les sens du terme) à Mamar: La Death Guard.

Et on commence par l'aura Contagion de Nurgle.

Car avec les démon, j'ai ajouté les auras.

Pour commencer, on vérifie que la Death Guard a l'aura en BDD:

Code:
curl -XPOST -v -d '{"langage":"fr","idCamp":"2","idFaction":"4","idSousFaction":"1","idSousSousFaction":"1"}' -H "Content-type: application/json" http://localhost:8080/aura/parRecherch

Code:
[
   {
      "aireEffet":1,
      "isAuraUnite":true,
      "profils":[
        
      ],
      "factory":"com.calculateur.warhammer.data.regles.factory.factory.death.guard.AuraContagionNurgleFactory",
      "ressource":{
         "id":24000,
         "ressource":"com.calculateur.warhammer.dto.aura.death_guard.death_guard"
      },
      "donnees":[
        
      ],
      "description":"-1 à l\u0027endurance de la cible. La portée est de 1ps au tour 1, 3ps au tour 2, 6ps au tour 3 et 9ps au tour 4+.",
      "id":24000,
      "nom":"id.aura.contagion.nurgle",
      "cleTraduction":"aura.death.guard.contagion.nurgle",
      "libelle":"Contagion de Nurgle"
   }
]

Évidement, la règle s'implémente facilement:
Code:
package com.calculateur.warhammer.data.regles.regle.death.guard;

import com.calculateur.warhammer.data.regles.IRegleAttaque;

/**
* Aura Contagion de Nurgle.
* @author phili
*
*/
public class AuraContagionNurgle implements IRegleAttaque{
    
    public static final String ID_AURA_CONTAGION_NURGLE = "id.aura.contagion.nurgle";
    
    @Override
    public Integer getMalusEndurance() {
        return -1;
    }
}

Chez moi, les règles sont fabriquées par le Design Pattern Factory:
Code:
package com.calculateur.warhammer.data.regles.factory.factory.death.guard;

import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.data.identifiable.IAura;
import com.calculateur.warhammer.data.regles.IRegleAttaque;
import com.calculateur.warhammer.data.regles.IRegleDefense;
import com.calculateur.warhammer.data.regles.IUpdateAura;
import com.calculateur.warhammer.data.regles.factory.donnees.IDonneeFactory;
import com.calculateur.warhammer.data.regles.factory.regle.AbstractAuraRegleFactory;
import com.calculateur.warhammer.data.regles.regle.death.guard.AuraContagionNurgle;

/**
* Factory pour l'aura Contagion de Nurgle
*
* @author phili
*
*/
public class AuraContagionNurgleFactory extends AbstractAuraRegleFactory implements IUpdateAura {

    @Override
    public IRegleAttaque getRegleAttaque(IDonneeFactory donnees) throws FunctionnalExeption {
        updateAura(donnees);
        return super.getRegleAttaque(donnees);
    }

    @Override
    protected IRegleAttaque getRegleAttaqueAura() {
        return new AuraContagionNurgle();
    }
    
    @Override
    protected IRegleDefense getRegleDefenseAura() {
        return null;
    }

    @Override
    protected String getKeyAura() {
        return AuraContagionNurgle.ID_AURA_CONTAGION_NURGLE;
    }

    @Override
    public void updateAura(IDonneeFactory donnees) {
        IAura aura = donnees.getContexteAction().getAurasAttaquant().get(getKeyAura());
        if(aura != null) {
            updateAuraSelonNumeroTour(donnees.getContexteAction().getNumeroTour(), aura);
        }
    }

    private void updateAuraSelonNumeroTour(Integer numeroTour, IAura aura) {
        switch (numeroTour) {
            case 1:
                aura.setBonusAireEffet(0);
                break;
            case 2:
                aura.setBonusAireEffet(2);
                break;
            case 3:
                aura.setBonusAireEffet(5);
                break;
            default:
                aura.setBonusAireEffet(8);
        }
    }
}

Et contrairement à des Ploucs qui codent l'application critique de l'entreprise, il y a des TU, sur la Factory ici:
Code:
package com.calculateur.warhammer.data.regles.factory.factory.death.guard;

import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.any;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.data.identifiable.IAura;
import com.calculateur.warhammer.data.regles.IRegleAttaque;
import com.calculateur.warhammer.data.regles.factory.regle.AbstractFactoryRegleTest;
import com.calculateur.warhammer.data.regles.regle.death.guard.AuraContagionNurgle;

@Execution(ExecutionMode.SAME_THREAD)
@ExtendWith(MockitoExtension.class)
public class AuraContagionNurgleFactoryTest extends AbstractFactoryRegleTest{

    private static final Integer PORTEE_TOUR_1 = 1;
    private static final Integer PORTEE_TOUR_2 = 3;
    private static final Integer PORTEE_TOUR_3 = 6;
    private static final Integer PORTEE_TOUR_4 = 9;
    
    private static final Integer TOUR_MAXIMUM = 5;
    
    private static final Integer DISTANCE_MAXIMUM_TEST = 15;
    
    @Mock
    private IAura aura;
    
    public AuraContagionNurgleFactoryTest() {
        super(new AuraContagionNurgleFactory());
    }

    @Override
    protected boolean isRegleAttaqueAttendu() {
        return true;
    }

    @Override
    protected boolean isRegleDefenseAttendu() {
        return false;
    }

    @Test
    public void testAuraAbsente() {
        try {
            Mockito.when(donnees.getContexteAction()).thenReturn(contexteAction);
            Mockito.when(contexteAction.getAurasAttaquant()).thenReturn(Collections.emptyMap());
            factoryRegle.getRegleAttaque(donnees);
            fail();
        }catch(FunctionnalExeption ex) {
            validateFunctionnalException(ex);
        }
    }
    
    @Test
    public void testAura() throws FunctionnalExeption{
        for(Integer numeroTour = 1; numeroTour <= TOUR_MAXIMUM;numeroTour++) {
            for(Integer distanceBelligerant = 1; distanceBelligerant < DISTANCE_MAXIMUM_TEST; distanceBelligerant++) {
                initMocks(numeroTour, distanceBelligerant);
                IRegleAttaque regle = factoryRegle.getRegleAttaque(donnees);
                validateRegle(regle, numeroTour, distanceBelligerant);
            }
        }
    }
    
    private void initMocks(Integer numeroTour,Integer distanceEntreBeligerants) {
        Mockito.when(donnees.getContexteAction()).thenReturn(contexteAction);
        
        Mockito.when(contexteAction.getNumeroTour()).thenReturn(numeroTour);
        Map<String, IAura> mapAura = new HashMap<>();
        mapAura.put(AuraContagionNurgle.ID_AURA_CONTAGION_NURGLE, aura);
        Mockito.when(contexteAction.getAurasAttaquant()).thenReturn(mapAura);
        Mockito.when(contexteAction.getDistanceEntreBelligerant()).thenReturn(distanceEntreBeligerants.doubleValue());
        
        Mockito.when(aura.isAuraUnite()).thenReturn(true);
        Mockito.doAnswer(invocation -> {
            Integer bon = (Integer)invocation.getArgument(0);
            Integer portee = 1;
            Mockito.when(aura.getApplicationAura()).thenReturn(portee + bon);
            return null;
        }).when(aura).setBonusAireEffet(any());
    }
    
    private void validateRegle(IRegleAttaque regle,Integer numeroTour,Integer distanceEntreBeligerants) {
        Integer porteeAura = getPorteeAura(numeroTour);
        boolean isRegle = distanceEntreBeligerants <= porteeAura;
        if(isRegle) {
            Assertions.assertThat(regle.getMalusEndurance()).isEqualTo(-1);
        }else {
            Assertions.assertThat(regle).isNull();
        }
    }
    
    private Integer getPorteeAura(Integer numeroTour) {
        Integer portee;    
        switch (numeroTour) {
            case 1:
                portee = PORTEE_TOUR_1;
                break;
            case 2:
                portee = PORTEE_TOUR_2;
                break;
            case 3:
                portee = PORTEE_TOUR_3;
                break;
            default:
                portee = PORTEE_TOUR_4;
        }
        return portee;
    }
}
Reply
#5
Et terminé pour la Death Guard.

Code:
curl -XPOST -v -d '{"langage":"fr","idCamp":"2","idFaction":"4","idSousFaction":"1","idSousSousFaction":"1"}' -H "Content-type: application/json" http://localhost:8080/regles/parRecherche

Code:
[
   {
      "factory":"com.calculateur.warhammer.data.regles.factory.factory.general.RegleArmureOfContentFactory",
      "ressource":{
         "id":1,
         "ressource":"com.calculateur.warhammer.dto.regles.faction.general.general"
      },
      "donnees":[
         
      ],
      "description":"Réduit la PA adverse de 1. La figurine ne doit pas être équipé d\u0027un Bouclier Tempête.",
      "id":1,
      "nom":"Armure of Content",
      "cleTraduction":"regle.armure.of.content",
      "libelle":"Armure of Content"
   },
   {
      "factory":"com.calculateur.warhammer.data.regles.factory.factory.death.guard.RegleImplacableFactory",
      "ressource":{
         "id":24000,
         "ressource":"com.calculateur.warhammer.dto.regles.faction.death_guard.death_guard"
      },
      "donnees":[
         
      ],
      "description":"Ignore les malus aux tests d\u0027attrition.",
      "id":24000,
      "nom":"Implacable",
      "cleTraduction":"regle.death.guard.implacable",
      "libelle":"Implacable"
   },
   {
      "factory":"com.calculateur.warhammer.data.regles.factory.factory.death.guard.RegleSalveMalveillanteFactory",
      "ressource":{
         "id":24000,
         "ressource":"com.calculateur.warhammer.dto.regles.faction.death_guard.death_guard"
      },
      "donnees":[
         
      ],
      "description":"Tir 2 fois pour les armes à tir rapide de type Bolt. La figurine doit être une infanterie ou un terminator.",
      "id":24001,
      "nom":"Salve Malveillante",
      "cleTraduction":"regle.death.guard.salve.malveillante",
      "libelle":"Salve Malveillante"
   },
   {
      "factory":"com.calculateur.warhammer.data.regles.factory.factory.death.guard.RegleAffreusementResistantFactory",
      "ressource":{
         "id":24000,
         "ressource":"com.calculateur.warhammer.dto.regles.faction.death_guard.death_guard"
      },
      "donnees":[
         
      ],
      "description":"Réduit les dégâts des armes de 1.",
      "id":24002,
      "nom":"Affreusement Résistant",
      "cleTraduction":"regle.death.guard.affreusement.resistant",
      "libelle":"Affreusement Résistant"
   }
]

Pour la règle Implacable:
Code:
package com.calculateur.warhammer.data.regles.regle.death.guard;

import com.calculateur.warhammer.data.regles.IRegleDefense;

/**
* Règle Implcable de la Death Guard
* @author phili
*
*/
public class RegleImplacable implements IRegleDefense{

    @Override
    public boolean isIgnoreMalusAttrition() {
        return true;
    }
}

Code:
package com.calculateur.warhammer.data.regles.factory.factory.death.guard;

import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.data.regles.IRegleAttaque;
import com.calculateur.warhammer.data.regles.IRegleDefense;
import com.calculateur.warhammer.data.regles.factory.donnees.IDonneeFactory;
import com.calculateur.warhammer.data.regles.factory.regle.IFactoryRegle;
import com.calculateur.warhammer.data.regles.regle.death.guard.RegleImplacable;

/**
* Factory Règle Implacable
* @author phili
*
*/
public class RegleImplacableFactory implements IFactoryRegle{

    @Override
    public IRegleAttaque getRegleAttaque(IDonneeFactory donnees) throws FunctionnalExeption {
        return null;
    }

    @Override
    public IRegleDefense getRegleDefense(IDonneeFactory donnees) throws FunctionnalExeption {
        return new RegleImplacable();
    }

    @Override
    public boolean isRegleApplicableAttaque() {
        return false;
    }

    @Override
    public boolean isRegleApplicableDefense() {
        return true;
    }

}

Code:
package com.calculateur.warhammer.data.regles.factory.factory.death.guard;

import static org.junit.jupiter.api.Assertions.fail;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;
import org.mockito.junit.jupiter.MockitoExtension;

import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.data.regles.factory.regle.AbstractFactoryRegleTest;

@Execution(ExecutionMode.SAME_THREAD)
@ExtendWith(MockitoExtension.class)
public class RegleImplacableFactoryTest extends AbstractFactoryRegleTest{

    public RegleImplacableFactoryTest() {
        super(new RegleImplacableFactory());
    }

    @Override
    protected boolean isRegleAttaqueAttendu() {
        return false;
    }

    @Override
    protected boolean isRegleDefenseAttendu() {
        return true;
    }

    @Test
    public void testRegleImplacable() {
        try {
            Assertions.assertThat(factoryRegle.getRegleDefense(donnees).isIgnoreMalusAttrition()).isTrue();
        }catch(FunctionnalExeption e) {
            fail(e);
        }
    }
}

Règle Salves Malveillantes:
Code:
package com.calculateur.warhammer.data.regles.regle.death.guard;

import java.util.Set;

import com.calculateur.warhammer.data.enumeration.EArme;
import com.calculateur.warhammer.data.enumeration.EArmeMotCle;
import com.calculateur.warhammer.data.enumeration.EProfil;
import com.calculateur.warhammer.data.enumeration.EProfilMotCle;
import com.calculateur.warhammer.data.regles.IRegleAttaque;
import com.calculateur.warhammer.data.regles.factory.donnees.IDonneeFactory;

/**
* Règle salve malveillante de la Death Guard
* @author phili
*
*/
public class RegleSalveMalveillante implements IRegleAttaque{

    private final EArme typeArme;
    
    private final Set<EArmeMotCle> motsClesArmes;
    
    private final Set<EProfil> typesProfils;
    
    private final Set<EProfilMotCle> profilsMotsCles;
    
    public RegleSalveMalveillante(IDonneeFactory donnees) {
        typeArme = donnees.getAttaquant().getArme().getType();
        motsClesArmes = donnees.getAttaquant().getArme().getMotsCles();
        typesProfils = donnees.getAttaquant().getProfil().getTypesProfils();
        profilsMotsCles = donnees.getAttaquant().getProfil().getMotsCles();
    }
    
    @Override
    public boolean isMaitriseArmeTirRapide() {
        return isRegleApplicable() && isRegleAppliquee();
    }
    
    private boolean isRegleApplicable() {
        return typeArme == EArme.TIR_RAPIDE && motsClesArmes.contains(EArmeMotCle.BOLT);
    }
    
    private boolean isRegleAppliquee() {
        return typesProfils.contains(EProfil.INFANTERIE) || profilsMotsCles.contains(EProfilMotCle.TERMINATOR);
    }
}

Code:
package com.calculateur.warhammer.data.regles.factory.factory.death.guard;

import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.data.regles.IRegleAttaque;
import com.calculateur.warhammer.data.regles.IRegleDefense;
import com.calculateur.warhammer.data.regles.factory.donnees.IDonneeFactory;
import com.calculateur.warhammer.data.regles.factory.regle.IFactoryRegle;
import com.calculateur.warhammer.data.regles.regle.death.guard.RegleSalveMalveillante;

/**
* Factory Règle Salve Malveillante de la Death Guard
* @author phili
*
*/
public class RegleSalveMalveillanteFactory implements IFactoryRegle{

    @Override
    public IRegleAttaque getRegleAttaque(IDonneeFactory donnees) throws FunctionnalExeption {
        return new RegleSalveMalveillante(donnees);
    }

    @Override
    public IRegleDefense getRegleDefense(IDonneeFactory donnees) throws FunctionnalExeption {
        return null;
    }

    @Override
    public boolean isRegleApplicableAttaque() {
        return true;
    }

    @Override
    public boolean isRegleApplicableDefense() {
        return false;
    }

}

Code:
package com.calculateur.warhammer.data.regles.factory.factory.death.guard;

import static org.junit.jupiter.api.Assertions.fail;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.data.enumeration.EArme;
import com.calculateur.warhammer.data.enumeration.EArmeMotCle;
import com.calculateur.warhammer.data.enumeration.EProfil;
import com.calculateur.warhammer.data.enumeration.EProfilMotCle;
import com.calculateur.warhammer.data.regles.IRegleAttaque;
import com.calculateur.warhammer.data.regles.factory.regle.AbstractFactoryRegleTest;

@Execution(ExecutionMode.SAME_THREAD)
@ExtendWith(MockitoExtension.class)
public class RegleSalveMalveillanteFactoryTest extends AbstractFactoryRegleTest{

    public RegleSalveMalveillanteFactoryTest() {
        super(new RegleSalveMalveillanteFactory());
    }

    @Override
    protected boolean isRegleAttaqueAttendu() {
        return true;
    }

    @Override
    protected boolean isRegleDefenseAttendu() {
        return false;
    }

    @Test
    public void testInfanterieBoltTirRapide() {
        testRegle(EProfil.INFANTERIE, null, EArme.TIR_RAPIDE, EArmeMotCle.BOLT, true);
    }
    
    @Test
    public void testInfanterieNonBoltTirRapide() {
        testRegle(EProfil.INFANTERIE, null, EArme.TIR_RAPIDE, null, false);
    }
    
    @Test
    public void testInfanterieBoltLourd() {
        testRegle(EProfil.INFANTERIE, null, EArme.LOURDE, EArmeMotCle.BOLT, false);
    }
    
    @Test
    public void testVehiculeBoltTirRapide() {
        testRegle(EProfil.VEHICULE, null, EArme.TIR_RAPIDE, EArmeMotCle.BOLT, false);
    }
    
    @Test
    public void testVehiculeNonBoltTirRapide() {
        testRegle(EProfil.VEHICULE, null, EArme.TIR_RAPIDE, null, false);
    }
    
    @Test
    public void testVehiculeBoltLouud() {
        testRegle(EProfil.VEHICULE, null, EArme.LOURDE, EArmeMotCle.BOLT, false);
    }
    
    @Test
    public void testTerminatorBoltTirRapide() {
        testRegle(EProfil.PERSONNAGE, EProfilMotCle.TERMINATOR, EArme.TIR_RAPIDE, EArmeMotCle.BOLT, true);
    }
    
    @Test
    public void testTerminatorNonBoltTirRapide() {
        testRegle(EProfil.PERSONNAGE, EProfilMotCle.TERMINATOR, EArme.TIR_RAPIDE, null, false);
    }
    
    @Test
    public void testTerminatorBoltLourd() {
        testRegle(EProfil.PERSONNAGE, EProfilMotCle.TERMINATOR, EArme.LOURDE, EArmeMotCle.BOLT, false);
    }
    
    private void testRegle(EProfil typeProfil,EProfilMotCle profilMotCle,EArme typeArme,EArmeMotCle armeMotCle,boolean attendu) {
        initMocks(typeProfil, profilMotCle, typeArme, armeMotCle);
        try {
            IRegleAttaque regle = factoryRegle.getRegleAttaque(donnees);
            Assertions.assertThat(regle.isMaitriseArmeTirRapide()).isEqualTo(attendu);
        }catch(FunctionnalExeption e) {
            fail(e);
        }
    }
    
    private void initMocks(EProfil typeProfil,EProfilMotCle profilMotCle,EArme typeArme,EArmeMotCle armeMotCle) {
        Mockito.when(donnees.getAttaquant()).thenReturn(attaquant);
        
        Set<EProfil> typesProfils = new HashSet<>(Arrays.asList(typeProfil));
        Set<EProfilMotCle> profilsMotsCles = new HashSet<>();
        if(profilMotCle != null) {
            profilsMotsCles.add(profilMotCle);
        }
        Mockito.when(attaquant.getProfil()).thenReturn(profil);
        Mockito.when(profil.getTypesProfils()).thenReturn(typesProfils);
        Mockito.when(profil.getMotsCles()).thenReturn(profilsMotsCles);
        
        Set<EArmeMotCle> motsClesArmes = new HashSet<>();
        if(armeMotCle != null) {
            motsClesArmes.add(armeMotCle);
        }
        Mockito.when(attaquant.getArme()).thenReturn(arme);
        Mockito.when(arme.getType()).thenReturn(typeArme);
        Mockito.when(arme.getMotsCles()).thenReturn(motsClesArmes);
    }
}

Et la règle Affreusement Résistant:
Code:
package com.calculateur.warhammer.data.regles.regle.death.guard;

import com.calculateur.warhammer.data.regles.IRegleDefense;

/**
* Règle affreusement résistant (réduit les dégâts de 1, minimum 1).
* @author phili
*
*/
public class RegleAffreusementResistant implements IRegleDefense{

    @Override
    public Integer getMalusDegat() {
        return -1;
    }
}

Code:
package com.calculateur.warhammer.data.regles.factory.factory.death.guard;

import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.data.regles.IRegleAttaque;
import com.calculateur.warhammer.data.regles.IRegleDefense;
import com.calculateur.warhammer.data.regles.factory.donnees.IDonneeFactory;
import com.calculateur.warhammer.data.regles.factory.regle.IFactoryRegle;
import com.calculateur.warhammer.data.regles.regle.death.guard.RegleAffreusementResistant;

/**
* Factory pour la règle Affreusement résistant
* @author phili
*
*/
public class RegleAffreusementResistantFactory implements IFactoryRegle{

    @Override
    public IRegleAttaque getRegleAttaque(IDonneeFactory donnees) throws FunctionnalExeption {
        return null;
    }

    @Override
    public IRegleDefense getRegleDefense(IDonneeFactory donnees) throws FunctionnalExeption {
        return new RegleAffreusementResistant();
    }

    @Override
    public boolean isRegleApplicableAttaque() {
        return false;
    }

    @Override
    public boolean isRegleApplicableDefense() {
        return true;
    }

}

Code:
package com.calculateur.warhammer.data.regles.factory.factory.death.guard;

import static org.junit.jupiter.api.Assertions.fail;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;
import org.mockito.junit.jupiter.MockitoExtension;

import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.data.regles.IRegleDefense;
import com.calculateur.warhammer.data.regles.factory.regle.AbstractFactoryRegleTest;

@Execution(ExecutionMode.SAME_THREAD)
@ExtendWith(MockitoExtension.class)
public class RegleAffreusementResistantFactoryTest extends AbstractFactoryRegleTest{

    public RegleAffreusementResistantFactoryTest() {
        super(new RegleAffreusementResistantFactory());
    }

    @Override
    protected boolean isRegleAttaqueAttendu() {
        return false;
    }

    @Override
    protected boolean isRegleDefenseAttendu() {
        return true;
    }

    @Test
    public void testRegle() {
        try {
            IRegleDefense regle = factoryRegle.getRegleDefense(donnees);
            Assertions.assertThat(regle.getMalusDegat()).isEqualTo(-1);
        }catch(FunctionnalExeption e) {
            fail(e);
        }
    }
}
Reply
#6
Et une armée de Fredo: Les Drukhari.

Je n'ai fais que ce qui est général à la faction. pas les sous factions (qui différentie kabalite, culte et gorgone).

Code:
curl -XPOST -v -d '{"langage":"fr","idCamp":"3","idFaction":"2","idSousFaction":"1","idSousSousFaction":"1"}' -H "Content-type: application/json" http://localhost:8080/regles/parRecherche

Code:
[
   {
      "factory":"com.calculateur.warhammer.data.regles.factory.drukhari.ReglePuissanceParLaSouffranceFactory",
      "ressource":{
         "id":32000,
         "ressource":"com.calculateur.warhammer.dto.regles.faction.drukhari.drukhari"
      },
      "donnees":[
         
      ],
      "description":"Tour 1: invulnérable 6+. Tour 2: Peut déclarer une charge au tour ou elle a advance. Tour 3: -1 au jet de touche et ignore à portée d\u0027engagement les malus des armes lourdes pour les véhicules et les monstres. Tour 4: Invulnérable à 5+. Tour 5: Ignore les tests de moral et est considéré comme ayant le double de PV pour les profils dégressifs.",
      "id":32000,
      "nom":"Puissance par la souffrance",
      "cleTraduction":"regle.puissance.souffrance",
      "libelle":"La Puissance Par La Souffrance"
   },
   {
      "factory":"com.calculateur.warhammer.data.regles.factory.drukhari.RegleArtisteDeLaLameFactory",
      "ressource":{
         "id":32000,
         "ressource":"com.calculateur.warhammer.dto.regles.faction.drukhari.drukhari"
      },
      "donnees":[
         
      ],
      "description":"Au corps à corps, tout jet naturel de 6 pour blesser améliore la PA de 1.",
      "id":32001,
      "nom":"Artiste des lames",
      "cleTraduction":"regle.artiste.lame",
      "libelle":"Artiste de la lame"
   }
]

règle puissance par la Souffrance:
Code:
package com.calculateur.warhammer.data.regles.regle.drukhari;

import java.util.Set;

import com.calculateur.warhammer.data.enumeration.EArme;
import com.calculateur.warhammer.data.enumeration.EProfil;
import com.calculateur.warhammer.data.regles.IRegleAttaque;
import com.calculateur.warhammer.data.regles.factory.donnees.IDonneeFactory;

/**
* Implémentation règle la puissance par la souffrance en attaque
* @author phili
*
*/
public class ReglePuissanceParLaSouffranceAttaque implements IRegleAttaque{

    private static final Integer TOUR_3 = 3;

    private final boolean isPorteeEngagement;
    private final Set<EProfil> typesProfils;
    private final boolean isTour3;
    
    public ReglePuissanceParLaSouffranceAttaque(IDonneeFactory donnees) {
        isPorteeEngagement = donnees.getContexteAction().isZoneEngagement();
        typesProfils = donnees.getAttaquant().getProfil().getTypesProfils();
        isTour3 = donnees.getContexteAction().getNumeroTour() >= TOUR_3;
    }
    
    @Override
    public Integer getBonusJetTouche() {
        return isTour3?-1:0;
    }
    
    @Override
    public boolean isIgnoreMalusArme(EArme arme) {
        return isTour3 && isPorteeEngagement
                && arme == EArme.LOURDE
                    && (typesProfils.contains(EProfil.VEHICULE) || typesProfils.contains(EProfil.MONSTRE));
    }
}

Code:
package com.calculateur.warhammer.data.regles.regle.drukhari;

import com.calculateur.warhammer.data.regles.IRegleDefense;

/**
* La règle Puissance par la Souffrance en Défense
* @author phili
*
*/
public class ReglePuissanceParLaSouffranceDefense implements IRegleDefense{

    private static final Integer TOUR_1 = 1;
    private static final Integer TOUR_4 = 4;
    private static final Integer TOUR_5 = 5;
    
    private final Integer numeroTour;
    
    public ReglePuissanceParLaSouffranceDefense(Integer numeroTour) {
        this.numeroTour = numeroTour;
    }
    
    @Override
    public Integer getSauvegardeInvulnerable() {
        Integer sauvegardeInvulnerable;
        if(TOUR_1 <= numeroTour && numeroTour < TOUR_4) {
            sauvegardeInvulnerable = 6;
        }else {
            sauvegardeInvulnerable = 5;
        }
        return sauvegardeInvulnerable;
    }
    
    @Override
    public boolean isIgnoreTestCommandement() {
        return numeroTour >= TOUR_5;
    }
}

Code:
package com.calculateur.warhammer.data.regles.regle.drukhari;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import com.calculateur.warhammer.data.enumeration.EProfil;
import com.calculateur.warhammer.data.regles.IRegleAttaque;

/**
* Implémentation Règle Artiste de la Lame
* @author phili
*
*/
public class RegleArtisteDeLaLame implements IRegleAttaque{

    private final Set<EProfil> profils;
    
    public RegleArtisteDeLaLame(Set<EProfil> profils) {
        this.profils = profils;
    }
    
    @Override
    public Map<Integer, Integer> getMapJetBlessureBonusPA() {
        Map<Integer, Integer> mapReturn = new HashMap<>();
        if(!profils.contains(EProfil.BETE) && !profils.contains(EProfil.AERODYNE)) {
            mapReturn.put(6, -1);
        }
        return mapReturn;
    }
}

Code:
package com.calculateur.warhammer.data.regles.factory.drukhari;

import static org.junit.jupiter.api.Assertions.fail;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.data.enumeration.EArme;
import com.calculateur.warhammer.data.enumeration.EProfil;
import com.calculateur.warhammer.data.regles.IRegleAttaque;
import com.calculateur.warhammer.data.regles.IRegleDefense;
import com.calculateur.warhammer.data.regles.factory.regle.AbstractFactoryRegleTest;

@Execution(ExecutionMode.SAME_THREAD)
@ExtendWith(MockitoExtension.class)
public class ReglePuissanceParLaSouffranceFactoryTest extends AbstractFactoryRegleTest{
        
    private final Integer TOUR_MAX = 5;
    
    public ReglePuissanceParLaSouffranceFactoryTest() {
        super(new ReglePuissanceParLaSouffranceFactory());
    }

    @Override
    protected boolean isRegleAttaqueAttendu() {
        return true;
    }

    @Override
    protected boolean isRegleDefenseAttendu() {
        return true;
    }
    
    @Test
    public void tesRegleAttaqueEngagementInfanterie() {
        doTestAttaque(true, EProfil.INFANTERIE);
    }
    
    @Test
    public void tesRegleAttaqueTirInfanterie() {
        doTestAttaque(false, EProfil.INFANTERIE);
    }
    
    @Test
    public void tesRegleAttaqueEngagementMonstre() {
        doTestAttaque(true, EProfil.MONSTRE);
    }
    
    @Test
    public void tesRegleAttaqueTirMonstre() {
        doTestAttaque(false, EProfil.MONSTRE);
    }
    
    @Test
    public void tesRegleAttaqueEngagementVehicule() {
        doTestAttaque(true, EProfil.VEHICULE);
    }
    
    @Test
    public void tesRegleAttaqueTirVehicule() {
        doTestAttaque(false, EProfil.VEHICULE);
    }
    
    private void doTestAttaque(boolean isZoneEngagement,EProfil typeProfil) {
        try {
            for(Integer numeroTour = 1; numeroTour < 6; numeroTour++) {
                initMockAttaque(numeroTour, isZoneEngagement, typeProfil);
                IRegleAttaque regle = factoryRegle.getRegleAttaque(donnees);
                for(EArme typeArme:EArme.values()) {
                    valideRegleAttaque(numeroTour, regle, typeProfil, typeArme);
                }
            }
        }catch(FunctionnalExeption e) {
            fail(e);
        }
    }
    
    private void initMockAttaque(Integer numeroTour,boolean isZoneEngagement,EProfil typeProfil) {
        Mockito.when(donnees.getContexteAction()).thenReturn(contexteAction);
        
        Mockito.when(contexteAction.isZoneEngagement()).thenReturn(isZoneEngagement);
        Mockito.when(contexteAction.getNumeroTour()).thenReturn(numeroTour);
        
        Mockito.when(donnees.getAttaquant()).thenReturn(attaquant);
        Mockito.when(attaquant.getProfil()).thenReturn(profil);
        Set<EProfil> profils = new HashSet<>(Arrays.asList(typeProfil));
        Mockito.when(profil.getTypesProfils()).thenReturn(profils);
    }
    
    private void valideRegleAttaque(Integer numeroTour,IRegleAttaque regle,EProfil typeProfil,EArme type) {
        boolean isRegle = numeroTour >= 3;
        
        Integer bonusTouche = isRegle?-1:0;
        boolean isIgnoreMalus = isRegle && contexteAction.isZoneEngagement() && type == EArme.LOURDE && (typeProfil == EProfil.VEHICULE || typeProfil == EProfil.MONSTRE);
        
        Assertions.assertThat(regle.getBonusJetTouche()).isEqualTo(bonusTouche);
        Assertions.assertThat(regle.isIgnoreMalusArme(type)).isEqualTo(isIgnoreMalus);
    }
    
    @Test
    public void testRegleDefense() {
        try {
            IRegleDefense regle;
            for(Integer numeroTour = 1; numeroTour <= TOUR_MAX; numeroTour++) {
                initMockDefense(numeroTour);
                regle = factoryRegle.getRegleDefense(donnees);
                testRegleDefense(regle, numeroTour);
            }
        }catch(FunctionnalExeption e) {
            fail(e);
        }
    }
    
    private void initMockDefense(Integer numeroTour) {
        Mockito.when(donnees.getContexteAction()).thenReturn(contexteAction);
        Mockito.when(contexteAction.getNumeroTour()).thenReturn(numeroTour);
    }
    
    private void testRegleDefense(IRegleDefense regle,Integer numeroTour) {
        Integer sauvegardeInvulnerable;
        if(1 <= numeroTour && numeroTour < 4) {
            sauvegardeInvulnerable = 6;
        }else{
            sauvegardeInvulnerable = 5;
        }
        
        boolean isIgnoreTestCommandement = numeroTour >= 5;
        
        Assertions.assertThat(regle.getSauvegardeInvulnerable()).isEqualTo(sauvegardeInvulnerable);
        Assertions.assertThat(regle.isIgnoreTestCommandement()).isEqualTo(isIgnoreTestCommandement);
    }
}

Règle Artiste de la lame
Code:
package com.calculateur.warhammer.data.regles.regle.drukhari;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import com.calculateur.warhammer.data.enumeration.EProfil;
import com.calculateur.warhammer.data.regles.IRegleAttaque;

/**
* Implémentation Règle Artiste de la Lame
* @author phili
*
*/
public class RegleArtisteDeLaLame implements IRegleAttaque{

    private final Set<EProfil> profils;
    
    public RegleArtisteDeLaLame(Set<EProfil> profils) {
        this.profils = profils;
    }
    
    @Override
    public Map<Integer, Integer> getMapJetBlessureBonusPA() {
        Map<Integer, Integer> mapReturn = new HashMap<>();
        if(!profils.contains(EProfil.BETE) && !profils.contains(EProfil.AERODYNE)) {
            mapReturn.put(6, -1);
        }
        return mapReturn;
    }
}

Code:
package com.calculateur.warhammer.data.regles.factory.drukhari;

import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.data.regles.IRegleAttaque;
import com.calculateur.warhammer.data.regles.IRegleDefense;
import com.calculateur.warhammer.data.regles.factory.donnees.IDonneeFactory;
import com.calculateur.warhammer.data.regles.factory.regle.IFactoryRegle;
import com.calculateur.warhammer.data.regles.regle.drukhari.RegleArtisteDeLaLame;

/**
* Factory de la règle Artiste de la lame.
* @author phili
*
*/
public class RegleArtisteDeLaLameFactory implements IFactoryRegle{

    @Override
    public IRegleAttaque getRegleAttaque(IDonneeFactory donnees) throws FunctionnalExeption {
        return new RegleArtisteDeLaLame(donnees.getAttaquant().getProfil().getTypesProfils());
    }

    @Override
    public IRegleDefense getRegleDefense(IDonneeFactory donnees) throws FunctionnalExeption {
        return null;
    }

    @Override
    public boolean isRegleApplicableAttaque() {
        return true;
    }

    @Override
    public boolean isRegleApplicableDefense() {
        return false;
    }

}

Code:
package com.calculateur.warhammer.data.regles.factory.drukhari;

import static org.junit.jupiter.api.Assertions.fail;

import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.data.enumeration.EProfil;
import com.calculateur.warhammer.data.regles.IRegleAttaque;
import com.calculateur.warhammer.data.regles.factory.regle.AbstractFactoryRegleTest;

@Execution(ExecutionMode.SAME_THREAD)
@ExtendWith(MockitoExtension.class)
public class RegleArtisteDeLaLameFactoryTest extends AbstractFactoryRegleTest{

    public RegleArtisteDeLaLameFactoryTest() {
        super(new RegleArtisteDeLaLameFactory());
    }

    @Override
    protected boolean isRegleAttaqueAttendu() {
        return true;
    }

    @Override
    protected boolean isRegleDefenseAttendu() {
        return false;
    }

    @Test
    public void testRegle() {
        try {
            IRegleAttaque regle;
            for(EProfil typeProfil:EProfil.values()) {
                initMock(typeProfil);
                regle = factoryRegle.getRegleAttaque(donnees);
                valideRegle(regle, typeProfil);
            }
        }catch(FunctionnalExeption e) {
            fail(e);
        }
    }
    
    private void initMock(EProfil typeProfil) {
        Mockito.when(donnees.getAttaquant()).thenReturn(attaquant);
        Mockito.when(attaquant.getProfil()).thenReturn(profil);
        Set<EProfil> profils = new HashSet<>();
        profils.add(typeProfil);
        Mockito.when(profil.getTypesProfils()).thenReturn(profils);
    }
    
    private void valideRegle(IRegleAttaque regle,EProfil typeProfil) {
        Map<Integer,Integer> map;
        if(typeProfil == EProfil.AERODYNE || typeProfil == EProfil.BETE) {
            map = Collections.emptyMap();
        }else {
            map = new HashMap<>();
            map.put(6, -1);
        }
        
        Assertions.assertThat(regle.getMapJetBlessureBonusPA()).isEqualTo(map);
    }
}
Reply
#7
Fini les Nécrons. Et ça a été long.

Pour commencer, il faut choisir le protocole de commandement:

Quote:curl -H "Content-type: application/json" http:/localhost:8080/necron/protocole/all/fr

Ce qui donne:
Code:
[
   {
      "protocoleCommandementNecron":"PROTOCOLE_GARDIEN_ETERNEL",
      "libelle":"Protocole du Gardien Eternel",
      "directive1":"Chaque fois qu\u0027une attaque est faite contre cette unité, si cette dernière n\u0027a pas fait de mouvement normal, avancé ou battu en retraite, cette unité a le bénéfice du couvert.",
      "directive2":"Chaque fois que l\u0027oin déclare une charge contre cette unité, celle ci peut tenir bon ou préparer sa défense si elle n\u0027est pas en zone d\u0027engagement. Si elle tient bon, alors le tir d\u0027état d\u0027alerte touche sur 5+. Si elle prépare sa défense, alors on ajoute 1 au jet de touche de l\u0027attaque."
   },
   {
      "protocoleCommandementNecron":"PROTOCOLE_TEMPETE_SOUDAINE",
      "libelle":"Protocole de la Tempête Soudaine",
      "directive1":"Ajouter 1ps à la caractéristique de mouvement.",
      "directive2":"Si cette unité fait une action, elle peut tirer sans faire échouer l\u0027action."
   },
   {
      "protocoleCommandementNecron":"PROTOCOLE_ASTRES_VENGEURS",
      "libelle":"Protocole des Astres Vengeurs",
      "directive1":"Chaque fois qu\u0027une unité fait une attaque de tir, sur un jet non modifié de 6, amélioré la pénétration d\u0027armure de 1.",
      "directive2":"Chaque fois qu\u0027une unité tire sur une cible à mi-portée, alors la cible ne bénéficie pas du couvert"
   },
   {
      "protocoleCommandementNecron":"PROTOCOLE_NEANT_AVIDE",
      "libelle":"Protocole du Néant Avide",
      "directive1":"Si la figurine fait une attaque de mêlée, un jet de touche de 6 non modifié ajoute -1 à la pénétration d\u0027armure.",
      "directive2":"Si la figurine fait une attaque de mêlée, et a chargé, été chargé ou effectué une intervention héroîque, ajouter 1 à la force de l\u0027attaque."
   },
   {
      "protocoleCommandementNecron":"PROCOTOLE_LEGIONS_IMPERISSABLES",
      "libelle":"Protocole des légions impérissables",
      "directive1":"Si la figurine utilise métal organique, récupéré 1 PV en plus.",
      "directive2":"Pour un jet de protocole de réanimation, relancé 1 Dé."
   },
   {
      "protocoleCommandementNecron":"PROTOCOLE_TYRAN_CONQUERANT",
      "libelle":"Protocole du Tyran Conquérant ",
      "directive1":"Ajouté 3 ps à la portée des aptitude d\u0027aura (maximum 12ps).",
      "directive2":"Cette unité peut tirer si elle a battu en retraite."
   }
]
Et la directive:
Code:
curl -H "Content-type: application/json" http:/localhost:8080/necron/protocole/applique/all/fr

Code:
[
   {
      "protocoleApplique":"AUCUN",
      "description":"Aucune directive n\u0027est appliquée.",
      "libelle":"Aucun"
   },
   {
      "protocoleApplique":"DIRECTIVE_1",
      "description":"La directive 1 est appliquée.",
      "libelle":"Directive 1"
   },
   {
      "protocoleApplique":"DIRECTIVE_2",
      "description":"La directive 2 est appliquée.",
      "libelle":"Directive 2"
   },
   {
      "protocoleApplique":"LES_DEUX",
      "description":"Les deux directive sont appliquées.",
      "libelle":"Les deux"
   }
]

On arrive à:
Code:
curl -XPOST -v -d '{"langage":"fr","idCamp":"3","idFaction":"5","idSousFaction":"1","idSousSousFaction":"1"}' -H "Content-type: application/json" http://localhost:8080/regles/parRecherche

Code:
[
   {
      "factory":"com.calculateur.warhammer.data.regles.factory.necron.RegleProtocoleReanimationFactory",
      "ressource":{
         "id":35000,
         "ressource":"com.calculateur.warhammer.dto.regles.faction.necron.necron"
      },
      "donnees":[
         
      ],
      "description":"Si on a x figurines mortes avec n points de vies chacune, on lance x * n dés. Sur 5+, on a une réussite. si on a r réussites, on relève r/n (arrondit à l\u0027inférieur) figurines. On peut modifier ce jet entre +1 et -1. ",
      "id":35000,
      "nom":"Protocole Réanimation Nécron",
      "cleTraduction":"regle.protocole.reanimation.necron",
      "libelle":"Protocole de réanimation"
   },
   {
      "factory":"com.calculateur.warhammer.data.regles.factory.necron.RegleProtocoleCommandementNecronFactory",
      "ressource":{
         "id":35000,
         "ressource":"com.calculateur.warhammer.dto.regles.faction.necron.necron"
      },
      "donnees":[
         {
            "url":"/necron/protocole",
            "ressources":{
               "id":35000,
               "ressource":"com.calculateur.warhammer.dto.regles.faction.necron.necron"
            },
            "description":"Le protocole de Commandement nécron sélectionné pour ce tour.",
            "id":35000,
            "nom":"protocole.commandement.necron",
            "cleTraduction":"donnee.protocole.necron",
            "libelle":"Protocole Nécron"
         },
         {
            "url":"/necron/protocole/applique",
            "ressources":{
               "id":35000,
               "ressource":"com.calculateur.warhammer.dto.regles.faction.necron.necron"
            },
            "description":"La directive appliquée pour le protocole Nécron.",
            "id":35001,
            "nom":"protocole.commandement.necron.applique",
            "cleTraduction":"donnee.directive.necron",
            "libelle":"Directive"
         }
      ],
      "description":"Les Protocoles de commandement Nécron.",
      "id":35001,
      "nom":"Protocole Commandement Nécron",
      "cleTraduction":"regle.protocole.commandement.necron",
      "libelle":"Protocole de commandement Nécron"
   }
]
Protocole de réanimation:
La règle:
Code:
package com.calculateur.warhammer.data.regles.regle.necron;

import java.util.HashSet;
import java.util.Set;

import com.calculateur.warhammer.data.enumeration.EProfilMotCle;
import com.calculateur.warhammer.data.regles.IRegleDefense;

/**
* Implémentation de la règle protocole de réanimation
* @author phili
*
*/
public class RegleProtocoleReanimation implements IRegleDefense{

    private final Set<EProfilMotCle> motsCles;
    
    public RegleProtocoleReanimation(Set<EProfilMotCle> motsCles) {
        this.motsCles = motsCles;
    }
    
    @Override
    public Integer getJetSeReleve() {
        return 5;
    }
    
    @Override
    public Set<Integer> getRelancesSeReleve() {
        Set<Integer> sReturn = new HashSet<>();
        if(motsCles.contains(EProfilMotCle.GUERRIER_NECRON)) {
            sReturn.add(1);
        }
        return sReturn;
    }
}
La factory:
Code:
package com.calculateur.warhammer.data.regles.factory.necron;

import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.data.regles.IRegleAttaque;
import com.calculateur.warhammer.data.regles.IRegleDefense;
import com.calculateur.warhammer.data.regles.factory.donnees.IDonneeFactory;
import com.calculateur.warhammer.data.regles.factory.regle.IFactoryRegle;
import com.calculateur.warhammer.data.regles.regle.necron.RegleProtocoleReanimation;

/**
* Factory de la règle protocole de réanimation
* @author phili
*
*/
public class RegleProtocoleReanimationFactory implements IFactoryRegle{

    @Override
    public IRegleAttaque getRegleAttaque(IDonneeFactory donnees) throws FunctionnalExeption {
        return null;
    }

    @Override
    public IRegleDefense getRegleDefense(IDonneeFactory donnees) throws FunctionnalExeption {
        return new RegleProtocoleReanimation(donnees.getDefenseur().getProfil().getMotsCles());
    }

    @Override
    public boolean isRegleApplicableAttaque() {
        return false;
    }

    @Override
    public boolean isRegleApplicableDefense() {
        return true;
    }
}
Et le test:
Code:
package com.calculateur.warhammer.data.regles.factory.necron;

import static org.junit.jupiter.api.Assertions.fail;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.data.enumeration.EProfilMotCle;
import com.calculateur.warhammer.data.regles.IRegleDefense;
import com.calculateur.warhammer.data.regles.factory.regle.AbstractFactoryRegleTest;

@Execution(ExecutionMode.SAME_THREAD)
@ExtendWith(MockitoExtension.class)
public class RegleProtocoleReanimationFactoryTest extends AbstractFactoryRegleTest{

    public RegleProtocoleReanimationFactoryTest() {
        super(new RegleProtocoleReanimationFactory());
    }

    @Override
    protected boolean isRegleAttaqueAttendu() {
        return false;
    }

    @Override
    protected boolean isRegleDefenseAttendu() {
        return true;
    }

    @Test
    public void testRegleGuerrierNecron() {
        testRegle(true);
    }
    
    @Test
    public void testRegleNecronGeneral() {
        testRegle(false);
    }
    
    private void testRegle(boolean isGuerrierNecron) {
        try {
            initMock(isGuerrierNecron);
            IRegleDefense regle = factoryRegle.getRegleDefense(donnees);
            validateRegle(regle, isGuerrierNecron);
        }catch(FunctionnalExeption e) {
            fail(e);
        }
    }
    
    private void initMock(boolean isGuerrierNecron) {
        Mockito.when(donnees.getDefenseur()).thenReturn(defenseur);
        Mockito.when(defenseur.getProfil()).thenReturn(profil);
        Set<EProfilMotCle> motsCles = new HashSet<>();
        if(isGuerrierNecron) {
            motsCles.add(EProfilMotCle.GUERRIER_NECRON);
        }
        Mockito.when(profil.getMotsCles()).thenReturn(motsCles);
    }
    
    private void validateRegle(IRegleDefense regle, boolean isGuerrierNecron) {
        Assertions.assertThat(regle.getJetSeReleve()).isEqualTo(5);
        if(isGuerrierNecron) {
            Set<Integer> set = new HashSet<>(Arrays.asList(1));
            Assertions.assertThat(regle.getRelancesSeReleve()).isEqualTo(set);
        }else {
            Assertions.assertThat(regle.getRelancesSeReleve()).isEmpty();
        }
    }
}

Règle Protocole de commandement:
Là, c'est le début des emmerdes. Il y en a trop redaface2 .
Pour commencer, on met la logique dans l'énumération:
Code:
package com.calculateur.warhammer.data.regles.regle.necron;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.data.enumeration.EMouvement;
import com.calculateur.warhammer.data.enumeration.ESimule;
import com.calculateur.warhammer.data.identifiable.ArmeUtils;
import com.calculateur.warhammer.data.identifiable.IArmeDeTir;
import com.calculateur.warhammer.data.regles.IRegleAttaque;
import com.calculateur.warhammer.data.regles.IRegleDefense;
import com.calculateur.warhammer.data.regles.factory.donnees.IDonneeFactory;
import com.calculateur.warhammer.data.regles.factory.regle.IFactoryRegle;

public enum EProtocoleCommandementNecron implements IFactoryRegle{

    PROTOCOLE_GARDIEN_ETERNEL(1){
        @Override
        public IRegleAttaque getRegleAttaque(IDonneeFactory donnees) throws FunctionnalExeption {
            return new IRegleAttaque() {
                @Override
                public Integer getJetToucheTirContreCharge() {
                    return isDirective2(donnees, true)?5:6;
                }
                
                @Override
                public Integer getBonusJetTouche() {
                    boolean isBonus = isDirective2(donnees, true) && !donnees.getContexteAction().isAttaquantAFaitTirDeContreCharge()
                            && donnees.getContexteAction().getSimule() == ESimule.CORPS_A_CORPS_APRES_CHARGE;
                    return isBonus?-1:0;
                }
            };
        }
        
        @Override
        public IRegleDefense getRegleDefense(IDonneeFactory donnees) throws FunctionnalExeption {
            return new IRegleDefense() {
                @Override
                public boolean isSauvegardeCouvert() {
                    return isDirective1(donnees,false) && donnees.getContexteAction().getMouvementDefenseur() == EMouvement.IMMOBILE;
                }
            };
        }
    },
    PROTOCOLE_TEMPETE_SOUDAINE(2){
        @Override
        public IRegleAttaque getRegleAttaque(IDonneeFactory donnees) throws FunctionnalExeption {
            return new IRegleAttaque() {
                @Override
                public Integer getBonusMouvement() {
                    return isDirective1(donnees, true)?1:0;
                }
            };
        }
        
        @Override
        public IRegleDefense getRegleDefense(IDonneeFactory donnees) throws FunctionnalExeption {
            return new IRegleDefense() {};
        }
    },
    PROTOCOLE_ASTRES_VENGEURS(3){
        @Override
        public IRegleAttaque getRegleAttaque(IDonneeFactory donnees) throws FunctionnalExeption {
            return new IRegleAttaque() {
                @Override
                public Map<Integer,Integer> getMapJetBlessureBonusPA() {
                    Map<Integer, Integer> mapReturn = new HashMap<>();
                    if(isDirective1(donnees,true) && donnees.getContexteAction().getSimule().isActionTir()) {
                        mapReturn.put(6, -1);
                    }
                    return mapReturn;
                }
                
                @Override
                public boolean isIgnoreSauvegardeCouvert() {
                    boolean isDirective2 = isDirective2(donnees, true);
                    boolean isMiPortee = false;
                    if(ArmeUtils.isArmeTir(donnees.getAttaquant().getArme())) {
                        IArmeDeTir armeTir = ArmeUtils.getArmeDeTir(donnees.getAttaquant().getArme());
                        isMiPortee = donnees.getContexteAction().getDistanceEntreBelligerant().intValue() <= (armeTir.getPorteeMaximale() / 2);
                    }
                    return isDirective2 && isMiPortee;
                }
            };
        }
        
        @Override
        public IRegleDefense getRegleDefense(IDonneeFactory donnees) throws FunctionnalExeption {
            return new IRegleDefense() {};
        }
    },
    PROTOCOLE_NEANT_AVIDE(4){
        @Override
        public IRegleAttaque getRegleAttaque(IDonneeFactory donnees) throws FunctionnalExeption {
            return new IRegleAttaque() {
                @Override
                public Map<Integer,Integer> getMapJetBlessureBonusPA() {
                    Map<Integer, Integer> mapReturn = new HashMap<>();
                    if(isDirective1(donnees,true) && donnees.getContexteAction().getSimule().isActionCorpACorp()) {
                        mapReturn.put(6, -1);
                    }
                    return mapReturn;
                }
                
                @Override
                public Integer getBonusForceAttaque() {
                    return isDirective2(donnees,true) &&
                            donnees.getContexteAction().getSimule().isAChargeOuSubbitCharge()?1:0;
                }
            };
        }
        
        @Override
        public IRegleDefense getRegleDefense(IDonneeFactory donnees) throws FunctionnalExeption {
            return new IRegleDefense() {};
        }
    },
    PROCOTOLE_LEGIONS_IMPERISSABLES(5){
        @Override
        public IRegleAttaque getRegleAttaque(IDonneeFactory donnees) throws FunctionnalExeption {
            return new IRegleAttaque() {};
        }
        
        @Override
        public IRegleDefense getRegleDefense(IDonneeFactory donnees) throws FunctionnalExeption {
            return new IRegleDefense() {};
        }
    },
    PROTOCOLE_TYRAN_CONQUERANT(6){
        @Override
        public IRegleAttaque getRegleAttaque(IDonneeFactory donnees) throws FunctionnalExeption {
            return new IRegleAttaque() {
                @Override
                public boolean isPeutTirerApresRetraite() {
                    return isDirective2(donnees, true);
                }
                
                @Override
                public  Integer getBonusJetTouche() {
                    //Certes, il peut tirer quand il fait un mouvement de retraite, mais il a un malus de +1 au jet.
                    boolean isDirective2 = isDirective2(donnees, true);
                    boolean isMouvementRetraite = donnees.getContexteAction().getMouvementAttaquant() == EMouvement.RETRAITE;
                    boolean isTir = donnees.getContexteAction().getSimule() == ESimule.TIR_PHASE_TIR;
                    boolean isRegle = isDirective2 && isMouvementRetraite && isTir;
                    return isRegle?1:0;
                }
            };
        }
        
        @Override
        public IRegleDefense getRegleDefense(IDonneeFactory donnees) throws FunctionnalExeption {
            return new IRegleDefense() {};
        }
    };
    
    public static final String ID_MAP_PROTOCOLE_COMMANDEMENT = "protocole.commandement.necron";
    
    private final Integer idProtocole;
    
    private EProtocoleCommandementNecron(Integer idProtocole) {
        this.idProtocole = idProtocole;
    }
    
    public Integer getIdProtocole() {
        return idProtocole;
    }
    
    public static EProtocoleCommandementNecron getById(Integer id) {
        Optional<EProtocoleCommandementNecron> o = Arrays.asList(EProtocoleCommandementNecron.values()).stream().filter(p -> p.getIdProtocole().equals(id)).findFirst();
        return o.isPresent()?o.get():null;
    }
    
    @Override
    public boolean isRegleApplicableAttaque() {
        return true;
    }
    
    @Override
    public boolean isRegleApplicableDefense() {
        return true;
    }
    
    private static boolean isDirective1(IDonneeFactory donnee,boolean isAttaquant) {
        EProtocoleCommandementNecronApplique protocoleApplique= getProtocoleApplique(donnee,isAttaquant);
        return protocoleApplique == EProtocoleCommandementNecronApplique.DIRECTIVE_1 || protocoleApplique == EProtocoleCommandementNecronApplique.LES_DEUX;
    }
    
    private static boolean isDirective2(IDonneeFactory donnee,boolean isAttaquant) {
        EProtocoleCommandementNecronApplique protocoleApplique= getProtocoleApplique(donnee,isAttaquant);
        return protocoleApplique == EProtocoleCommandementNecronApplique.DIRECTIVE_2 || protocoleApplique == EProtocoleCommandementNecronApplique.LES_DEUX;
    }
    
    private static EProtocoleCommandementNecronApplique getProtocoleApplique(IDonneeFactory donnee,boolean isAttaquant) {
        return isAttaquant?
                EProtocoleCommandementNecronApplique.getById(donnee.getDonneesAttaquant().get(EProtocoleCommandementNecronApplique.ID_MAP_PROTOCOLE_COMMANDEMENT_APPLIQUE)):
                    EProtocoleCommandementNecronApplique.getById(donnee.getDonneesDefenseur().get(EProtocoleCommandementNecronApplique.ID_MAP_PROTOCOLE_COMMANDEMENT_APPLIQUE));
    }
}

La factory devient donc un décorateur:
Code:
package com.calculateur.warhammer.data.regles.factory.necron;

import java.util.Arrays;
import java.util.Map;

import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.data.regles.IRegleAttaque;
import com.calculateur.warhammer.data.regles.IRegleDefense;
import com.calculateur.warhammer.data.regles.factory.donnees.IDonneeFactory;
import com.calculateur.warhammer.data.regles.factory.regle.IFactoryRegle;
import com.calculateur.warhammer.data.regles.regle.necron.EProtocoleCommandementNecron;
import com.calculateur.warhammer.data.regles.regle.necron.EProtocoleCommandementNecronApplique;

/**
* Factory de la règle Protocole de commandement Nécron
* @author phili
*
*/
public class RegleProtocoleCommandementNecronFactory implements IFactoryRegle{
    
    private static final String RES = "com.calculateur.warhammer.data.regles.factory.regle.necron.necron";
    
    @Override
    public IRegleAttaque getRegleAttaque(IDonneeFactory donnees) throws FunctionnalExeption {
        return getProtocole(donnees.getDonneesAttaquant()).getRegleAttaque(donnees);
    }

    @Override
    public IRegleDefense getRegleDefense(IDonneeFactory donnees) throws FunctionnalExeption {
        return getProtocole(donnees.getDonneesDefenseur()).getRegleDefense(donnees);
    }

    @Override
    public boolean isRegleApplicableAttaque() {
        return true;
    }

    @Override
    public boolean isRegleApplicableDefense() {
        return true;
    }
    
    private EProtocoleCommandementNecron getProtocole(Map<String, Integer> mapDonnees) throws FunctionnalExeption{
        if(!mapDonnees.containsKey(EProtocoleCommandementNecron.ID_MAP_PROTOCOLE_COMMANDEMENT)) {
            throw new FunctionnalExeption(Arrays.asList("necron.protocol.presence"), RES);
        }
        EProtocoleCommandementNecron protocole =EProtocoleCommandementNecron.getById(mapDonnees.get(EProtocoleCommandementNecron.ID_MAP_PROTOCOLE_COMMANDEMENT));
        if(protocole == null) {
            throw new FunctionnalExeption(Arrays.asList("necron.protocol.null"), RES);
        }
        if(!mapDonnees.containsKey(EProtocoleCommandementNecronApplique.ID_MAP_PROTOCOLE_COMMANDEMENT_APPLIQUE)) {
            throw new FunctionnalExeption(Arrays.asList("necron.protocol.appliquee.presence"), RES);
        }
        EProtocoleCommandementNecronApplique directive = EProtocoleCommandementNecronApplique.getById(mapDonnees.get(
                EProtocoleCommandementNecronApplique.ID_MAP_PROTOCOLE_COMMANDEMENT_APPLIQUE));
        if(directive == null) {
            throw new FunctionnalExeption(Arrays.asList("necron.protocol.applique.null"), RES);
        }
        return protocole;
    }
}
Ce qui donne ce TU imbittable:
Code:
package com.calculateur.warhammer.data.regles.factory.necron;

import static org.junit.jupiter.api.Assertions.fail;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.data.enumeration.EMouvement;
import com.calculateur.warhammer.data.enumeration.ESimule;
import com.calculateur.warhammer.data.identifiable.IArmeDeCorpsACorps;
import com.calculateur.warhammer.data.identifiable.IArmeDeTir;
import com.calculateur.warhammer.data.regles.IRegleAttaque;
import com.calculateur.warhammer.data.regles.IRegleDefense;
import com.calculateur.warhammer.data.regles.factory.regle.AbstractFactoryRegleTest;
import com.calculateur.warhammer.data.regles.regle.necron.EProtocoleCommandementNecron;
import com.calculateur.warhammer.data.regles.regle.necron.EProtocoleCommandementNecronApplique;

@Execution(ExecutionMode.SAME_THREAD)
@ExtendWith(MockitoExtension.class)
public class RegleProtocoleCommandementNecronFactoryTest extends AbstractFactoryRegleTest{

    @Mock
    private IArmeDeTir armeDeTir;
    
    @Mock
    private IArmeDeCorpsACorps armeMelee;
    
    public RegleProtocoleCommandementNecronFactoryTest() {
        super(new RegleProtocoleCommandementNecronFactory());
    }

    @Override
    protected boolean isRegleAttaqueAttendu() {
        return true;
    }

    @Override
    protected boolean isRegleDefenseAttendu() {
        return true;
    }

    @Test
    public void testProtocoleMauvaisAttaque() {
        try {
            parameters.clear();
            parameters.put(EProtocoleCommandementNecron.ID_MAP_PROTOCOLE_COMMANDEMENT, -1);
            Mockito.when(donnees.getDonneesAttaquant()).thenReturn(parameters);
            factoryRegle.getRegleAttaque(donnees);
            fail();
        }catch(FunctionnalExeption e) {
            validateFunctionnalException(e);
        }
    }
    
    @Test
    public void testProtocoleAbsentAttaque() {
        try {
            parameters.clear();
            Mockito.when(donnees.getDonneesAttaquant()).thenReturn(parameters);
            factoryRegle.getRegleAttaque(donnees);
            fail();
        }catch(FunctionnalExeption e) {
            validateFunctionnalException(e);
        }
    }
    
    @Test
    public void testProtocoleAppliqueMauvaisAttaque() {
        try {
            parameters.clear();
            parameters.put(EProtocoleCommandementNecron.ID_MAP_PROTOCOLE_COMMANDEMENT, EProtocoleCommandementNecron.PROCOTOLE_LEGIONS_IMPERISSABLES.getIdProtocole());
            parameters.put(EProtocoleCommandementNecronApplique.ID_MAP_PROTOCOLE_COMMANDEMENT_APPLIQUE, -1);
            Mockito.when(donnees.getDonneesAttaquant()).thenReturn(parameters);
            factoryRegle.getRegleAttaque(donnees);
            fail();
        }catch(FunctionnalExeption e) {
            validateFunctionnalException(e);
        }
    }
    
    @Test
    public void testProtocoleAppliqueAbsentAttaque() {
        try {
            parameters.clear();
            parameters.put(EProtocoleCommandementNecron.ID_MAP_PROTOCOLE_COMMANDEMENT, EProtocoleCommandementNecron.PROCOTOLE_LEGIONS_IMPERISSABLES.getIdProtocole());
            Mockito.when(donnees.getDonneesAttaquant()).thenReturn(parameters);
            factoryRegle.getRegleAttaque(donnees);
            fail();
        }catch(FunctionnalExeption e) {
            validateFunctionnalException(e);
        }
    }
    
    public void testProtocoleMauvaisDefense() {
        try {
            parameters.clear();
            parameters.put(EProtocoleCommandementNecron.ID_MAP_PROTOCOLE_COMMANDEMENT, -1);
            Mockito.when(donnees.getDonneesDefenseur()).thenReturn(parameters);
            factoryRegle.getRegleDefense(donnees);
            fail();
        }catch(FunctionnalExeption e) {
            validateFunctionnalException(e);
        }
    }
    
    @Test
    public void testProtocoleAbsentDefense() {
        try {
            parameters.clear();
            Mockito.when(donnees.getDonneesDefenseur()).thenReturn(parameters);
            factoryRegle.getRegleDefense(donnees);
            fail();
        }catch(FunctionnalExeption e) {
            validateFunctionnalException(e);
        }
    }
    
    @Test
    public void testProtocoleAppliqueAbsentDefense() {
        try {
            parameters.put(EProtocoleCommandementNecron.ID_MAP_PROTOCOLE_COMMANDEMENT, EProtocoleCommandementNecron.PROCOTOLE_LEGIONS_IMPERISSABLES.getIdProtocole());
            parameters.clear();
            Mockito.when(donnees.getDonneesDefenseur()).thenReturn(parameters);
            factoryRegle.getRegleDefense(donnees);
            fail();
        }catch(FunctionnalExeption e) {
            validateFunctionnalException(e);
        }
    }
    
    public void testProtocoleAppliqueMauvaisDefense() {
        try {
            parameters.clear();
            parameters.put(EProtocoleCommandementNecron.ID_MAP_PROTOCOLE_COMMANDEMENT, EProtocoleCommandementNecron.PROCOTOLE_LEGIONS_IMPERISSABLES.getIdProtocole());
            parameters.put(EProtocoleCommandementNecron.ID_MAP_PROTOCOLE_COMMANDEMENT, EProtocoleCommandementNecron.PROCOTOLE_LEGIONS_IMPERISSABLES.getIdProtocole());
            Mockito.when(donnees.getDonneesDefenseur()).thenReturn(parameters);
            factoryRegle.getRegleDefense(donnees);
            fail();
        }catch(FunctionnalExeption e) {
            validateFunctionnalException(e);
        }
    }
    
    //Règle en Attaque
    @Test
    public void testRegleAttaqueProtocoleGardienEternelDirective1Tir() throws FunctionnalExeption{
        for(EProtocoleCommandementNecronApplique directive:getListDirective1()) {
            initMockAttaque(EProtocoleCommandementNecron.PROTOCOLE_GARDIEN_ETERNEL, directive);
            IRegleAttaque regle = factoryRegle.getRegleAttaque(donnees);
            boolean isDirective2 = directive == EProtocoleCommandementNecronApplique.LES_DEUX;
            Assertions.assertThat(regle.getJetToucheTirContreCharge()).isEqualTo(isDirective2?5:6);
        }
    }
    
    @Test
    public void testRegleAttaqueProtocoleGardienEternelDirective2Tir() throws FunctionnalExeption{
        for(EProtocoleCommandementNecronApplique directive:getListDirective2()) {
            initMockAttaque(EProtocoleCommandementNecron.PROTOCOLE_GARDIEN_ETERNEL, directive);
            IRegleAttaque regle = factoryRegle.getRegleAttaque(donnees);
            Assertions.assertThat(regle.getJetToucheTirContreCharge()).isEqualTo(5);
        }
    }
    
    @Test
    public void testRegleAttaqueProtocoleGardienEternelDirective1Melee() throws FunctionnalExeption{
        for(EProtocoleCommandementNecronApplique directive:getListDirective1()) {
            for(ESimule simule:ESimule.values()) {
                initMockAttaque(EProtocoleCommandementNecron.PROTOCOLE_GARDIEN_ETERNEL, directive);
                Mockito.when(donnees.getContexteAction()).thenReturn(contexteAction);
                Mockito.when(contexteAction.getSimule()).thenReturn(simule);
                Mockito.when(contexteAction.isAttaquantAFaitTirDeContreCharge()).thenReturn(false);
                IRegleAttaque regle = factoryRegle.getRegleAttaque(donnees);
                boolean isDirective2 = directive == EProtocoleCommandementNecronApplique.LES_DEUX;
                boolean isReponseCharge = simule == ESimule.CORPS_A_CORPS_APRES_CHARGE;
                Assertions.assertThat(regle.getBonusJetTouche())
                    .isEqualTo((isDirective2 && isReponseCharge)?-1:0);
                
                initMockAttaque(EProtocoleCommandementNecron.PROTOCOLE_GARDIEN_ETERNEL, directive);
                Mockito.when(donnees.getContexteAction()).thenReturn(contexteAction);
                Mockito.when(contexteAction.isAttaquantAFaitTirDeContreCharge()).thenReturn(true);
                regle = factoryRegle.getRegleAttaque(donnees);
                Assertions.assertThat(regle.getBonusJetTouche()).isZero();
            }
        }
    }
    
    @Test
    public void testRegleAttaqueProtocoleGardienEternelDirective2Melee() throws FunctionnalExeption{
        for(EProtocoleCommandementNecronApplique directive:getListDirective2()) {
            for(ESimule simule:ESimule.values()) {
                initMockAttaque(EProtocoleCommandementNecron.PROTOCOLE_GARDIEN_ETERNEL, directive);
                Mockito.when(donnees.getContexteAction()).thenReturn(contexteAction);
                Mockito.when(contexteAction.getSimule()).thenReturn(simule);
                Mockito.when(contexteAction.isAttaquantAFaitTirDeContreCharge()).thenReturn(false);
                IRegleAttaque regle = factoryRegle.getRegleAttaque(donnees);
                boolean isReponseCharge = simule == ESimule.CORPS_A_CORPS_APRES_CHARGE;
                Assertions.assertThat(regle.getBonusJetTouche()).isEqualTo((isReponseCharge)?-1:0);
                
                initMockAttaque(EProtocoleCommandementNecron.PROTOCOLE_GARDIEN_ETERNEL, directive);
                Mockito.when(donnees.getContexteAction()).thenReturn(contexteAction);
                Mockito.when(contexteAction.isAttaquantAFaitTirDeContreCharge()).thenReturn(true);
                regle = factoryRegle.getRegleAttaque(donnees);
                Assertions.assertThat(regle.getBonusJetTouche()).isZero();
            }
        }
    }

    @Test
    public void testRegleDefenseProtocoleGardienEternelDirective1Immobile() throws FunctionnalExeption {
        for(EProtocoleCommandementNecronApplique directive:getListDirective1()) {
            initMockDefense(EProtocoleCommandementNecron.PROTOCOLE_GARDIEN_ETERNEL, directive);
            Mockito.when(donnees.getContexteAction()).thenReturn(contexteAction);
            Mockito.when(contexteAction.getMouvementDefenseur()).thenReturn(EMouvement.IMMOBILE);
            IRegleDefense regle = factoryRegle.getRegleDefense(donnees);
            Assertions.assertThat(regle.isSauvegardeCouvert()).isTrue();
        }
    }
    
    @Test
    public void testRegleDefenseProtocoleGardienEternelDirective1Mouvement() throws FunctionnalExeption {
        for(EProtocoleCommandementNecronApplique directive:getListDirective1()) {
            initMockDefense(EProtocoleCommandementNecron.PROTOCOLE_GARDIEN_ETERNEL, directive);
            Mockito.when(donnees.getContexteAction()).thenReturn(contexteAction);
            Mockito.when(contexteAction.getMouvementDefenseur()).thenReturn(EMouvement.NORMAL);
            IRegleDefense regle = factoryRegle.getRegleDefense(donnees);
            Assertions.assertThat(regle.isSauvegardeCouvert()).isFalse();
        }
    }
    
    @Test
    public void testRegleAttaqueProtocoleTempeteSoudaineDirective1() throws FunctionnalExeption{
        for(EProtocoleCommandementNecronApplique directive:getListDirective1()) {
            initMockAttaque(EProtocoleCommandementNecron.PROTOCOLE_TEMPETE_SOUDAINE, directive);
            IRegleAttaque regle = factoryRegle.getRegleAttaque(donnees);
            Assertions.assertThat(regle.getBonusMouvement()).isEqualTo(1);
        }
    }
    
    @Test
    public void testRegleAttaqueProtocoleTempeteSoudaineDirective2() throws FunctionnalExeption{
        for(EProtocoleCommandementNecronApplique directive:getListDirective2()) {
            initMockAttaque(EProtocoleCommandementNecron.PROTOCOLE_TEMPETE_SOUDAINE, directive);
            IRegleAttaque regle = factoryRegle.getRegleAttaque(donnees);
            Assertions.assertThat(regle.getBonusMouvement())
                .isEqualTo((directive == EProtocoleCommandementNecronApplique.LES_DEUX)?
                        1:0);
        }
    }
    
    @Test
    public void testRegleProtocoleAstreVengeurDirective1AmeliorationPA() throws FunctionnalExeption {
        for(EProtocoleCommandementNecronApplique directive:getListDirective1()) {
            for(ESimule simule:ESimule.values()) {
                initMockAttaque(EProtocoleCommandementNecron.PROTOCOLE_ASTRES_VENGEURS, directive);
                Mockito.when(donnees.getContexteAction()).thenReturn(contexteAction);
                Mockito.when(contexteAction.getSimule()).thenReturn(simule);
                IRegleAttaque regle = factoryRegle.getRegleAttaque(donnees);
                Map<Integer, Integer> mapAmeliorationPA = new HashMap<>();
                if(simule.isActionTir()) {
                    mapAmeliorationPA.put(6, -1);
                }
                Assertions.assertThat(regle.getMapJetBlessureBonusPA()).isEqualTo(mapAmeliorationPA);
            }
        }
    }
    
    @Test
    public void testRegleProtocoleAstreVengeurDirective2AmeliorationPA() throws FunctionnalExeption {
        for(EProtocoleCommandementNecronApplique directive:getListDirective2()) {
            for(ESimule simule:ESimule.values()) {
                initMockAttaque(EProtocoleCommandementNecron.PROTOCOLE_ASTRES_VENGEURS, directive);
                Mockito.when(donnees.getContexteAction()).thenReturn(contexteAction);
                Mockito.when(contexteAction.getSimule()).thenReturn(simule);
                IRegleAttaque regle = factoryRegle.getRegleAttaque(donnees);
                Map<Integer, Integer> mapAmeliorationPA = new HashMap<>();
                if(simule.isActionTir() && directive == EProtocoleCommandementNecronApplique.LES_DEUX) {
                    mapAmeliorationPA.put(6, -1);
                }
                Assertions.assertThat(regle.getMapJetBlessureBonusPA()).isEqualTo(mapAmeliorationPA);
            }
        }
    }
    
    @Test
    public void testRegleProtocoleAstreVengeurDirective1IgnoreSauvegardeCouvertMelee() throws FunctionnalExeption{
        for(EProtocoleCommandementNecronApplique directive:getListDirective1()) {
            initMockAttaque(EProtocoleCommandementNecron.PROTOCOLE_ASTRES_VENGEURS, directive);
            Mockito.when(donnees.getAttaquant()).thenReturn(attaquant);
            Mockito.when(attaquant.getArme()).thenReturn(armeMelee);
            IRegleAttaque regle = factoryRegle.getRegleAttaque(donnees);
            Assertions.assertThat(regle.isIgnoreSauvegardeCouvert()).isFalse();
        }
    }
    
    @Test
    public void testRegleProtocoleAstreVengeurDirective2IgnoreSauvegardeCouvertMelee() throws FunctionnalExeption{
        for(EProtocoleCommandementNecronApplique directive:getListDirective2()) {
            initMockAttaque(EProtocoleCommandementNecron.PROTOCOLE_ASTRES_VENGEURS, directive);
            Mockito.when(donnees.getAttaquant()).thenReturn(attaquant);
            Mockito.when(attaquant.getArme()).thenReturn(armeMelee);
            IRegleAttaque regle = factoryRegle.getRegleAttaque(donnees);
            Assertions.assertThat(regle.isIgnoreSauvegardeCouvert()).isFalse();
        }
    }
    
    @Test
    public void testRegleProtocoleAstreVengeurDirective1IgnoreSauvegardeCouvertTirLonguePortee()throws FunctionnalExeption{
        for(EProtocoleCommandementNecronApplique directive:getListDirective1()) {
            initMockAttaque(EProtocoleCommandementNecron.PROTOCOLE_ASTRES_VENGEURS, directive);
            Mockito.when(donnees.getContexteAction()).thenReturn(contexteAction);
            Mockito.when(contexteAction.getDistanceEntreBelligerant()).thenReturn(17.0);
            Mockito.when(donnees.getAttaquant()).thenReturn(attaquant);
            Mockito.when(attaquant.getArme()).thenReturn(armeDeTir);
            Mockito.when(armeDeTir.getPorteeMaximale()).thenReturn(30);
            IRegleAttaque regle = factoryRegle.getRegleAttaque(donnees);
            Assertions.assertThat(regle.isIgnoreSauvegardeCouvert()).isFalse();
        }
    }
    
    @Test
    public void testRegleProtocoleAstreVengeurDirective2IgnoreSauvegardeCouvertTirLonguePortee()throws FunctionnalExeption{
        for(EProtocoleCommandementNecronApplique directive:getListDirective2()) {
            initMockAttaque(EProtocoleCommandementNecron.PROTOCOLE_ASTRES_VENGEURS, directive);
            Mockito.when(donnees.getContexteAction()).thenReturn(contexteAction);
            Mockito.when(contexteAction.getDistanceEntreBelligerant()).thenReturn(17.0);
            Mockito.when(donnees.getAttaquant()).thenReturn(attaquant);
            Mockito.when(attaquant.getArme()).thenReturn(armeDeTir);
            Mockito.when(armeDeTir.getPorteeMaximale()).thenReturn(30);
            IRegleAttaque regle = factoryRegle.getRegleAttaque(donnees);
            Assertions.assertThat(regle.isIgnoreSauvegardeCouvert()).isFalse();
        }
    }
    
    @Test
    public void testRegleProtocoleAstreVengeurDirective1IgnoreSauvegardeCouvertTirMiPortee()throws FunctionnalExeption{
        for(EProtocoleCommandementNecronApplique directive:getListDirective1()) {
            initMockAttaque(EProtocoleCommandementNecron.PROTOCOLE_ASTRES_VENGEURS, directive);
            Mockito.when(donnees.getContexteAction()).thenReturn(contexteAction);
            Mockito.when(contexteAction.getDistanceEntreBelligerant()).thenReturn(8.0);
            Mockito.when(donnees.getAttaquant()).thenReturn(attaquant);
            Mockito.when(attaquant.getArme()).thenReturn(armeDeTir);
            Mockito.when(armeDeTir.getPorteeMaximale()).thenReturn(30);
            IRegleAttaque regle = factoryRegle.getRegleAttaque(donnees);
            Assertions.assertThat(regle.isIgnoreSauvegardeCouvert())
                .isEqualTo(directive == EProtocoleCommandementNecronApplique.LES_DEUX);
        }
    }
    
    @Test
    public void testRegleProtocoleAstreVengeurDirective2IgnoreSauvegardeCouvertTirMiPortee()throws FunctionnalExeption{
        for(EProtocoleCommandementNecronApplique directive:getListDirective2()) {
            initMockAttaque(EProtocoleCommandementNecron.PROTOCOLE_ASTRES_VENGEURS, directive);
            Mockito.when(donnees.getContexteAction()).thenReturn(contexteAction);
            Mockito.when(contexteAction.getDistanceEntreBelligerant()).thenReturn(8.0);
            Mockito.when(donnees.getAttaquant()).thenReturn(attaquant);
            Mockito.when(attaquant.getArme()).thenReturn(armeDeTir);
            Mockito.when(armeDeTir.getPorteeMaximale()).thenReturn(30);
            IRegleAttaque regle = factoryRegle.getRegleAttaque(donnees);
            Assertions.assertThat(regle.isIgnoreSauvegardeCouvert()).isTrue();
        }
    }
    
    @Test
    public void testRegleProtocoleNeantAvideDirective1AmeliorationPA() throws FunctionnalExeption {
        for(EProtocoleCommandementNecronApplique directive:getListDirective1()) {
            for(ESimule simule:ESimule.values()) {
                initMockAttaque(EProtocoleCommandementNecron.PROTOCOLE_NEANT_AVIDE, directive);
                Mockito.when(donnees.getContexteAction()).thenReturn(contexteAction);
                Mockito.when(contexteAction.getSimule()).thenReturn(simule);
                IRegleAttaque regle = factoryRegle.getRegleAttaque(donnees);
                Map<Integer, Integer> mapAmeliorationPA = new HashMap<>();
                if(simule.isActionCorpACorp()) {
                    mapAmeliorationPA.put(6, -1);
                }
                Assertions.assertThat(regle.getMapJetBlessureBonusPA()).isEqualTo(mapAmeliorationPA);
            }
        }
    }
    
    @Test
    public void testRegleProtocoleNeantAvideDirective2AmeliorationPA() throws FunctionnalExeption {
        for(EProtocoleCommandementNecronApplique directive:getListDirective2()) {
            for(ESimule simule:ESimule.values()) {
                initMockAttaque(EProtocoleCommandementNecron.PROTOCOLE_NEANT_AVIDE, directive);
                Mockito.when(donnees.getContexteAction()).thenReturn(contexteAction);
                Mockito.when(contexteAction.getSimule()).thenReturn(simule);
                IRegleAttaque regle = factoryRegle.getRegleAttaque(donnees);
                Map<Integer, Integer> mapAmeliorationPA = new HashMap<>();
                if(simule.isActionCorpACorp() && directive == EProtocoleCommandementNecronApplique.LES_DEUX) {
                    mapAmeliorationPA.put(6, -1);
                }
                Assertions.assertThat(regle.getMapJetBlessureBonusPA()).isEqualTo(mapAmeliorationPA);
            }
        }
    }
    
    @Test
    public void testRegleProtocoleNeantAvideDirective1()throws FunctionnalExeption{
        for(EProtocoleCommandementNecronApplique directive:getListDirective1()) {
            for(ESimule simule:ESimule.values()) {
                initMockAttaque(EProtocoleCommandementNecron.PROTOCOLE_NEANT_AVIDE, directive);
                Mockito.when(donnees.getContexteAction()).thenReturn(contexteAction);
                Mockito.when(contexteAction.getSimule()).thenReturn(simule);
                IRegleAttaque regle = factoryRegle.getRegleAttaque(donnees);
                boolean isCharge = simule.isAChargeOuSubbitCharge();
                boolean isDirective2 = directive == EProtocoleCommandementNecronApplique.LES_DEUX;
                Integer bonusForce = (isCharge && isDirective2)?1:0;
                Assertions.assertThat(regle.getBonusForceAttaque()).isEqualTo(bonusForce);
            }            
        }
    }
    
    @Test
    public void testRegleProtocoleNeantAvideDirective2()throws FunctionnalExeption{
        for(EProtocoleCommandementNecronApplique directive:getListDirective2()) {
            for(ESimule simule:ESimule.values()) {
                initMockAttaque(EProtocoleCommandementNecron.PROTOCOLE_NEANT_AVIDE, directive);
                Mockito.when(donnees.getContexteAction()).thenReturn(contexteAction);
                Mockito.when(contexteAction.getSimule()).thenReturn(simule);
                IRegleAttaque regle = factoryRegle.getRegleAttaque(donnees);
                boolean isCharge = simule.isAChargeOuSubbitCharge();
                Integer bonusForce = (isCharge)?1:0;
                Assertions.assertThat(regle.getBonusForceAttaque()).isEqualTo(bonusForce);
            }            
        }
    }
    
    @Test
    public void testRegleTyranConquerantDirective1() throws FunctionnalExeption {
        for(EProtocoleCommandementNecronApplique directive:getListDirective1()) {
            for(EMouvement mouvement:EMouvement.values()) {
                for(ESimule simule:ESimule.values()) {
                    initMockAttaque(EProtocoleCommandementNecron.PROTOCOLE_TYRAN_CONQUERANT, directive);
                    Mockito.when(donnees.getContexteAction()).thenReturn(contexteAction);
                    Mockito.when(contexteAction.getMouvementAttaquant()).thenReturn(mouvement);
                    Mockito.when(contexteAction.getSimule()).thenReturn(simule);
                    boolean isDirective2 = directive == EProtocoleCommandementNecronApplique.LES_DEUX;
                    boolean isTirApresRetraite = mouvement == EMouvement.RETRAITE;
                    boolean isRegle = isDirective2 && isTirApresRetraite && simule == ESimule.TIR_PHASE_TIR;
                    IRegleAttaque regle = factoryRegle.getRegleAttaque(donnees);
                    Assertions.assertThat(regle.isPeutTirerApresRetraite()).isEqualTo(isDirective2);
                    Assertions.assertThat(regle.getBonusJetTouche()).isEqualTo(isRegle?1:0);
                }
            }
        }
    }
    
    @Test
    public void testRegleTyranConquerantDirective2() throws FunctionnalExeption {
        for(EProtocoleCommandementNecronApplique directive:getListDirective2()) {
            for(EMouvement mouvement:EMouvement.values()) {
                for(ESimule simule:ESimule.values()) {
                    initMockAttaque(EProtocoleCommandementNecron.PROTOCOLE_TYRAN_CONQUERANT, directive);
                    Mockito.when(donnees.getContexteAction()).thenReturn(contexteAction);
                    Mockito.when(contexteAction.getMouvementAttaquant()).thenReturn(mouvement);
                    Mockito.when(contexteAction.getSimule()).thenReturn(simule);
                    boolean isTirApresRetraite = mouvement == EMouvement.RETRAITE;
                    boolean isRegle = isTirApresRetraite && simule == ESimule.TIR_PHASE_TIR;
                    IRegleAttaque regle = factoryRegle.getRegleAttaque(donnees);
                    Assertions.assertThat(regle.isPeutTirerApresRetraite()).isTrue();
                    Assertions.assertThat(regle.getBonusJetTouche()).isEqualTo(isRegle?1:0);
                }
            }
        }
    }
    
    private void initMockAttaque(EProtocoleCommandementNecron protocole,EProtocoleCommandementNecronApplique directive) {
        parameters.clear();
        parameters.put(EProtocoleCommandementNecron.ID_MAP_PROTOCOLE_COMMANDEMENT, protocole.getIdProtocole());
        parameters.put(EProtocoleCommandementNecronApplique.ID_MAP_PROTOCOLE_COMMANDEMENT_APPLIQUE, directive.getIdProtocoleApplique());
        Mockito.when(donnees.getDonneesAttaquant()).thenReturn(parameters);        
    }
    
    private void initMockDefense(EProtocoleCommandementNecron protocole,EProtocoleCommandementNecronApplique directive) {
        parameters.clear();
        parameters.put(EProtocoleCommandementNecron.ID_MAP_PROTOCOLE_COMMANDEMENT, protocole.getIdProtocole());
        parameters.put(EProtocoleCommandementNecronApplique.ID_MAP_PROTOCOLE_COMMANDEMENT_APPLIQUE, directive.getIdProtocoleApplique());
        Mockito.when(donnees.getDonneesDefenseur()).thenReturn(parameters);
    }
    
    private List<EProtocoleCommandementNecronApplique> getListDirective1(){
        return Arrays.asList(EProtocoleCommandementNecronApplique.DIRECTIVE_1,EProtocoleCommandementNecronApplique.LES_DEUX);
    }
    
    private List<EProtocoleCommandementNecronApplique> getListDirective2(){
        return Arrays.asList(EProtocoleCommandementNecronApplique.DIRECTIVE_2,EProtocoleCommandementNecronApplique.LES_DEUX);
    }
    
}
Reply
#8
Finit les Orks. Et avec la dernière FAQ.
J'ai même innové. Pour les règles, j'ai fait les tests avant l'implémentation (TDD).


Code:
curl -XPOST -v -d '{"langage":"fr","idCamp":"3","idFaction":"8","idSousFaction":"1","idSousSousFaction":"1"}' -H "Content-type: application/json" http://localhost:8080/regles/parRecherche

Code:
[
   {
      "factory":"com.calculateur.warhammer.data.regles.factory.ork.RegleAttaqueOrkFactory",
      "ressource":{
         "id":38000,
         "ressource":"com.calculateur.warhammer.dto.regles.faction.ork.ork"
      },
      "donnees":[
         {
            "url":"/ork/attaque",
            "ressources":{
               "id":38000,
               "ressource":"com.calculateur.warhammer.dto.regles.faction.ork.ork"
            },
            "description":"A choisir entre WAAAAGH,ZIWAAAGH et rien.",
            "id":38000,
            "nom":"attaque.ork",
            "cleTraduction":"donnee.attaque.ork",
            "libelle":"Le type d\u0027attaque Ork en cours"
         },
         {
            "url":"/ork/attaque",
            "ressources":{
               "id":38000,
               "ressource":"com.calculateur.warhammer.dto.regles.faction.ork.ork"
            },
            "description":"A choisir entre le stade 1 ou 2.",
            "id":38001,
            "nom":"phase.attaque.ork",
            "cleTraduction":"donnee.phase.attaque.ork",
            "libelle":"Stade de l\u0027attaque Ork."
         }
      ],
      "description":"A choisir entre WAAAAGH,ZIWAAAGH et rien.",
      "id":38000,
      "nom":"WAAAGH/ZYWAAAGH Ork",
      "cleTraduction":"regle.attaque.ork",
      "libelle":"Le type d\u0027attaque Ork en cours"
   },
   {
      "factory":"com.calculateur.warhammer.data.regles.factory.ork.RegleBrinquebalantFactory",
      "ressource":{
         "id":38000,
         "ressource":"com.calculateur.warhammer.dto.regles.faction.ork.ork"
      },
      "donnees":[
         
      ],
      "description":"Les véhicule Ork réduisent les dégâts de 1 (minimum 1).",
      "id":38001,
      "nom":"Brinquelant",
      "cleTraduction":"regle.brinquebalant",
      "libelle":"Brinquebalant"
   },
   {
      "factory":"com.calculateur.warhammer.data.regles.factory.ork.RegleAlpagueurFactory",
      "ressource":{
         "id":38000,
         "ressource":"com.calculateur.warhammer.dto.regles.faction.ork.ork"
      },
      "donnees":[
         
      ],
      "description":"Ajoutez 1 au jet de touche contre les véhicule ou les monstres. Sauvegarde invulnérable de 6+.",
      "id":38002,
      "nom":"Alpagueur",
      "cleTraduction":"regle.alpagueur",
      "libelle":"Alpagueur"
   }
]

Pour Brinquebalant:
Code:
package com.calculateur.warhammer.data.regles.regle.ork;

import java.util.Set;

import com.calculateur.warhammer.data.enumeration.EProfil;
import com.calculateur.warhammer.data.regles.IRegleDefense;

/**
* Implémentation règle Brinquebalant (-1 aux dégâts pour les véhicule non titanesque)
* @author phili
*
*/
public class RegleBrinquebalant implements IRegleDefense{

    
    private final Set<EProfil> typesProfils;

    public RegleBrinquebalant(Set<EProfil> typesProfils) {
        super();
        this.typesProfils = typesProfils;
    }
    
    @Override
    public Integer getMalusDegat() {
        return (typesProfils.contains(EProfil.VEHICULE) && !typesProfils.contains(EProfil.TITANESQUE))?-1:0 ;
    }
    
}


Code:
package com.calculateur.warhammer.data.regles.factory.ork;

import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.data.regles.IRegleAttaque;
import com.calculateur.warhammer.data.regles.IRegleDefense;
import com.calculateur.warhammer.data.regles.factory.donnees.IDonneeFactory;
import com.calculateur.warhammer.data.regles.factory.regle.IFactoryRegle;
import com.calculateur.warhammer.data.regles.regle.ork.RegleBrinquebalant;

/**
* Factory de la règle Brinquelant
* @author phili
*
*/
public class RegleBrinquebalantFactory implements IFactoryRegle{

    @Override
    public IRegleAttaque getRegleAttaque(IDonneeFactory donnees) throws FunctionnalExeption {
        return null;
    }

    @Override
    public IRegleDefense getRegleDefense(IDonneeFactory donnees) throws FunctionnalExeption {
        return new RegleBrinquebalant(donnees.getDefenseur().getProfil().getTypesProfils());
    }

    @Override
    public boolean isRegleApplicableAttaque() {
        return false;
    }

    @Override
    public boolean isRegleApplicableDefense() {
        return true;
    }

}

Code:
package com.calculateur.warhammer.data.regles.factory.ork;

import static org.junit.jupiter.api.Assertions.fail;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.data.enumeration.EProfil;
import com.calculateur.warhammer.data.regles.IRegleDefense;
import com.calculateur.warhammer.data.regles.factory.regle.AbstractFactoryRegleTest;

@Execution(ExecutionMode.SAME_THREAD)
@ExtendWith(MockitoExtension.class)
public class RegleBrinquebalantFactoryTest extends AbstractFactoryRegleTest{

    public RegleBrinquebalantFactoryTest() {
        super(new RegleBrinquebalantFactory());
    }

    @Override
    protected boolean isRegleAttaqueAttendu() {
        return false;
    }

    @Override
    protected boolean isRegleDefenseAttendu() {
        return true;
    }

    @Test
    public void testRegleInfanterie() {
        testRegleDefense(Arrays.asList(EProfil.INFANTERIE));
    }
    
    @Test
    public void testRegleVehicule() {
        testRegleDefense(Arrays.asList(EProfil.VEHICULE));
    }
    
    @Test
    public void testRegleVehiculeTitanesque() {
        testRegleDefense(Arrays.asList(EProfil.VEHICULE,EProfil.TITANESQUE));
    }
    
    private void testRegleDefense(List<EProfil> typesProfils) {
        try {
            initMockDefense(typesProfils);
            IRegleDefense regle = factoryRegle.getRegleDefense(donnees);
            validateRegleDefense(regle, typesProfils);
        }catch(FunctionnalExeption e) {
            fail(e);
        }
    }
    
    private void initMockDefense(List<EProfil> typesProfils) {
        Mockito.when(donnees.getDefenseur()).thenReturn(defenseur);
        Mockito.when(defenseur.getProfil()).thenReturn(profil);
        Mockito.when(profil.getTypesProfils()).thenReturn(new HashSet<>(typesProfils));
    }
    
    private void validateRegleDefense(IRegleDefense regle,List<EProfil> typesProfils) {
        Integer reductionDegats = (typesProfils.contains(EProfil.VEHICULE) && !typesProfils.contains(EProfil.TITANESQUE))?
                -1:0;
        Assertions.assertThat(regle.getMalusDegat()).isEqualTo(reductionDegats);
    }
}


Pour Alpagueur:
Un peu plus difficile, il y en a en défense et en attaque.
Code:
package com.calculateur.warhammer.data.regles.regle.ork;

import com.calculateur.warhammer.data.regles.IRegleAttaque;

/**
* La règle Alpagueur en Attaque. En l'occurence, +1 au jet de touche si la cible est un véhicule ou un monstre
* @author phili
*
*/
public class RegleAlpagueurAttaque implements IRegleAttaque{

    private final boolean isRegleApplicable;
    
    public RegleAlpagueurAttaque(boolean isAlpagueur,boolean isVehiculeOuMonstre) {
        isRegleApplicable = isAlpagueur && isVehiculeOuMonstre;
    }
    
    @Override
    public Integer getBonusJetTouche() {
        return isRegleApplicable?-1:0;
    }
}

Code:
package com.calculateur.warhammer.data.regles.regle.ork;

import com.calculateur.warhammer.data.regles.IRegleDefense;

/**
* Règle Alpagueur en défense, à savoir sauvegarde invulnérable à 6+.
* @author phili
*
*/
public class RegleAlpagueurDefense implements IRegleDefense{

    private final boolean isAlpagueur;
    
    public RegleAlpagueurDefense(boolean isAlpagueur) {
        this.isAlpagueur = isAlpagueur;
    }
    
    @Override
    public Integer getSauvegardeInvulnerable() {
        return isAlpagueur?6:0;
    }
}

Code:
package com.calculateur.warhammer.data.regles.factory.ork;

import java.util.Set;

import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.data.enumeration.EProfil;
import com.calculateur.warhammer.data.enumeration.EProfilMotCle;
import com.calculateur.warhammer.data.regles.IRegleAttaque;
import com.calculateur.warhammer.data.regles.IRegleDefense;
import com.calculateur.warhammer.data.regles.factory.donnees.IDonneeFactory;
import com.calculateur.warhammer.data.regles.factory.regle.IFactoryRegle;
import com.calculateur.warhammer.data.regles.regle.ork.RegleAlpagueurAttaque;
import com.calculateur.warhammer.data.regles.regle.ork.RegleAlpagueurDefense;

/**
* Factory de la règle Alpagueur
* @author phili
*
*/
public class RegleAlpagueurFactory implements IFactoryRegle{

    @Override
    public IRegleAttaque getRegleAttaque(IDonneeFactory donnees) throws FunctionnalExeption {
        return new RegleAlpagueurAttaque(
                isAlpagueur(donnees.getAttaquant().getProfil().getMotsCles()),
                    isVehiculeOuMonstre(donnees.getDefenseur().getProfil().getTypesProfils()));
    }

    @Override
    public IRegleDefense getRegleDefense(IDonneeFactory donnees) throws FunctionnalExeption {
        return new RegleAlpagueurDefense(isAlpagueur(donnees.getDefenseur().getProfil().getMotsCles()));
    }

    @Override
    public boolean isRegleApplicableAttaque() {
        return true;
    }

    @Override
    public boolean isRegleApplicableDefense() {
        return true;
    }
    
    private boolean isAlpagueur(Set<EProfilMotCle> motsCles) {
        return motsCles.contains(EProfilMotCle.ALPAGUEUR);
    }

    private boolean isVehiculeOuMonstre(Set<EProfil> types) {
        return types.contains(EProfil.VEHICULE) || types.contains(EProfil.MONSTRE);
    }
}

Pour la WAAAGH:
Là, ça a été complexe. J'ai même innové en utilisant les classes scellé, qui énumèrent les classes filles attendues.
Il n'y a que la WAAAGH et la ZYWAAAGH.

Pour l'attaque:
Code:
package com.calculateur.warhammer.data.regles.regle.ork;

import com.calculateur.warhammer.data.regles.IRegleAttaque;

/**
* Une classe pour touts les assauts Orks
* @author phili
*
*/
public sealed class RegleAttaqueOrkAttaque implements IRegleAttaque permits RegleWaaaghAttaque,RegleZywaaaghAttaque{

    protected final EPhaseAttaqueOrk stade;

    public RegleAttaqueOrkAttaque(EPhaseAttaqueOrk stade) {
        this.stade = stade;
    }
}

Code:
package com.calculateur.warhammer.data.regles.regle.ork;

import com.calculateur.warhammer.data.enumeration.EMouvement;

/**
* Règle d'attaque pour une WAAAGH Ork
* @author phili
*
*/
public final class RegleWaaaghAttaque extends RegleAttaqueOrkAttaque{

    private final boolean isBaseOuPersonnage;
    
    public RegleWaaaghAttaque(EPhaseAttaqueOrk stade,boolean isBaseOuPersonnage) {
        super(stade);
        this.isBaseOuPersonnage = isBaseOuPersonnage;
    }
    
    @Override
    public boolean isChargeApresTypeMouvement(EMouvement mouvement) {
        return super.isChargeApresTypeMouvement(mouvement)
                || (stade == EPhaseAttaqueOrk.PHASE_1 && mouvement == EMouvement.ADVANCE && isBaseOuPersonnage);
    }
    
    @Override
    public Integer getBonusForce() {
        return 1;
    }
    
    @Override
    public Integer getBonusNombreAttaque() {
        return 1;
    }
}

Code:
package com.calculateur.warhammer.data.regles.regle.ork;

import com.calculateur.warhammer.data.enumeration.EArme;
import com.calculateur.warhammer.data.enumeration.EMouvement;

/**
* Classe pour la règle Zywaaagh
* @author phili
*
*/
public final class RegleZywaaaghAttaque extends RegleAttaqueOrkAttaque{

    private final boolean isVehiculeOuMoto;
    private final EArme typeArme;
    
    public RegleZywaaaghAttaque(EPhaseAttaqueOrk stade,boolean isVehiculeOuMoto,EArme typeArme) {
        super(stade);
        this.isVehiculeOuMoto = isVehiculeOuMoto;
        this.typeArme = typeArme;
    }

    @Override
    public boolean isIgnoreMalusMouvementAuTir(EMouvement mouvement) {
        return super.isIgnoreMalusMouvementAuTir(mouvement) ||
                (mouvement == EMouvement.ADVANCE && stade ==  EPhaseAttaqueOrk.PHASE_1 && typeArme == EArme.ASSAUT);
    }
    
    @Override
    public Integer getBonusAttaqueArme(EArme aTypeArme) {
        return (stade == EPhaseAttaqueOrk.PHASE_1 && isVehiculeOuMoto && aTypeArme == EArme.DAKA)?1:0;
    }
    
    @Override
    public Integer getBonusPA() {
        return (isVehiculeOuMoto && typeArme != EArme.CORPS_A_CORPS)?-1:0;
    }
}
Heuresement qu'en défense, il n'y a que WAAAGH:
Code:
package com.calculateur.warhammer.data.regles.regle.ork;

import com.calculateur.warhammer.data.regles.IRegleDefense;

/**
* Règle Waaagh en défense
* @author phili
*
*/
public class RegleWaaaghDefense implements IRegleDefense{
    
    private final EPhaseAttaqueOrk stade;

    public RegleWaaaghDefense(EPhaseAttaqueOrk stade) {
        super();
        this.stade = stade;
    }
    
    @Override
    public Integer getSauvegardeInvulnerable() {
        return stade == EPhaseAttaqueOrk.PHASE_1?5:6;
    }
}
Soit la Factory:
Code:
package com.calculateur.warhammer.data.regles.factory.ork;

import java.util.Arrays;
import java.util.Map;
import java.util.Set;

import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.data.enumeration.EProfil;
import com.calculateur.warhammer.data.regles.IRegleAttaque;
import com.calculateur.warhammer.data.regles.IRegleDefense;
import com.calculateur.warhammer.data.regles.factory.donnees.IDonneeFactory;
import com.calculateur.warhammer.data.regles.factory.regle.IFactoryRegle;
import com.calculateur.warhammer.data.regles.regle.ork.EAttaqueOrk;
import com.calculateur.warhammer.data.regles.regle.ork.EPhaseAttaqueOrk;
import com.calculateur.warhammer.data.regles.regle.ork.RegleWaaaghAttaque;
import com.calculateur.warhammer.data.regles.regle.ork.RegleWaaaghDefense;
import com.calculateur.warhammer.data.regles.regle.ork.RegleZywaaaghAttaque;

/**
* Une factory pour les différentes WAAAGH des orks
* @author phili
*
*/
public class RegleAttaqueOrkFactory implements IFactoryRegle{

    private static final String RES = "com.calculateur.warhammer.data.regles.factory.regle.ork.ork";
    
    private static final String KEY_ERROR_ATTAQUE_NULL = "attaque.ork.null";
    private static final String KEY_ERROR_ATTAQUE_INEXISTANT = "attaque.ork.inexistant";
    
    private static final String KEY_ERROR_PHASE_ATTAQUE_NULL = "phase.attaque.ork.null";
    private static final String KEY_ERROR_PHASE_ATTAQUE_INEXISTANT = "phase.attaque.ork.inexistant";
    
    @Override
    public IRegleAttaque getRegleAttaque(IDonneeFactory donnees) throws FunctionnalExeption {
        Map<String,Integer> map = donnees.getDonneesAttaquant();
        EAttaqueOrk typeWaaagh = getAttaqueOrk(map);
        EPhaseAttaqueOrk stade = getStade(map);
        
        Set<EProfil> profils = donnees.getAttaquant().getProfil().getTypesProfils();
        boolean isBaseOuPersonnage = profils.contains(EProfil.BASE) || profils.contains(EProfil.PERSONNAGE);
        boolean isVehiculeOuMoto = profils.contains(EProfil.VEHICULE) || profils.contains(EProfil.MOTO);
        return switch (typeWaaagh) {
            case WAAAGH: yield new RegleWaaaghAttaque(stade, isBaseOuPersonnage);
            case ZYWAAAGH: yield new RegleZywaaaghAttaque(stade, isVehiculeOuMoto, donnees.getAttaquant().getArme().getType());
            default: yield new IRegleAttaque() {};
        };
    }

    @Override
    public IRegleDefense getRegleDefense(IDonneeFactory donnees) throws FunctionnalExeption {
        Map<String,Integer> map = donnees.getDonneesDefenseur();
        EAttaqueOrk typeWaaagh = getAttaqueOrk(map);
        EPhaseAttaqueOrk stade = getStade(map);
        return switch (typeWaaagh) {
            case WAAAGH: yield new RegleWaaaghDefense(stade);
            default: yield new IRegleDefense() {};
        };
    }

    @Override
    public boolean isRegleApplicableAttaque() {
        return true;
    }

    @Override
    public boolean isRegleApplicableDefense() {
        return true;
    }

    private EAttaqueOrk getAttaqueOrk(Map<String,Integer> map) throws FunctionnalExeption{
        if(!map.containsKey(EAttaqueOrk.ID_MAP_ATTAQUE_ORK)) {
            throw new FunctionnalExeption(Arrays.asList(KEY_ERROR_ATTAQUE_NULL), RES);
        }
        EAttaqueOrk aReturn = EAttaqueOrk.getById(map.get(EAttaqueOrk.ID_MAP_ATTAQUE_ORK));
        if(aReturn == null) {
            throw new FunctionnalExeption(Arrays.asList(KEY_ERROR_ATTAQUE_INEXISTANT), RES);
        }
        return aReturn;
    }
    
    private EPhaseAttaqueOrk getStade(Map<String,Integer> map)throws FunctionnalExeption{
        if(!map.containsKey(EPhaseAttaqueOrk.ID_MAP_PHASE_ATTAQUE_ORK)) {
            throw new FunctionnalExeption(Arrays.asList(KEY_ERROR_PHASE_ATTAQUE_NULL), RES);
        }
        EPhaseAttaqueOrk sReturn = EPhaseAttaqueOrk.getById(map.get(EPhaseAttaqueOrk.ID_MAP_PHASE_ATTAQUE_ORK));
        if(sReturn == null) {
            throw new FunctionnalExeption(Arrays.asList(KEY_ERROR_PHASE_ATTAQUE_INEXISTANT), RES);
        }
        return sReturn;
    }
}
Et le test suivant:
Code:
package com.calculateur.warhammer.data.regles.factory.ork;

import static org.junit.jupiter.api.Assertions.fail;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.data.enumeration.EArme;
import com.calculateur.warhammer.data.enumeration.EMouvement;
import com.calculateur.warhammer.data.enumeration.EProfil;
import com.calculateur.warhammer.data.regles.IRegleAttaque;
import com.calculateur.warhammer.data.regles.IRegleDefense;
import com.calculateur.warhammer.data.regles.factory.regle.AbstractFactoryRegleTest;
import com.calculateur.warhammer.data.regles.regle.ork.EAttaqueOrk;
import com.calculateur.warhammer.data.regles.regle.ork.EPhaseAttaqueOrk;

@Execution(ExecutionMode.SAME_THREAD)
@ExtendWith(MockitoExtension.class)
public class RegleAttaqueOrkFactoryTest extends AbstractFactoryRegleTest{

    public RegleAttaqueOrkFactoryTest() {
        super(new RegleAttaqueOrkFactory());
    }

    @Override
    protected boolean isRegleAttaqueAttendu() {
        return true;
    }

    @Override
    protected boolean isRegleDefenseAttendu() {
        return true;
    }

    @Test
    public void testAttaqueOrkAbsentPourAttaque() {
        try {
            parameters.clear();
            Mockito.when(donnees.getDonneesAttaquant()).thenReturn(parameters);
            factoryRegle.getRegleAttaque(donnees);
            fail();
        }catch(FunctionnalExeption e) {
            validateFunctionnalException(e);
        }
    }
    
    @Test
    public void testAttaqueOrkInexistantePourAttaque() {
        try {
            parameters.clear();
            parameters.put(EAttaqueOrk.ID_MAP_ATTAQUE_ORK, -1);
            Mockito.when(donnees.getDonneesAttaquant()).thenReturn(parameters);
            factoryRegle.getRegleAttaque(donnees);
            fail();
        }catch(FunctionnalExeption e) {
            validateFunctionnalException(e);
        }
    }
    
    @Test
    public void testStadeAttaqueOrkAbsentEnAttaque() {
        try {
            parameters.clear();
            parameters.put(EAttaqueOrk.ID_MAP_ATTAQUE_ORK, EAttaqueOrk.WAAAGH.getIdAttaqueOrk());
            Mockito.when(donnees.getDonneesAttaquant()).thenReturn(parameters);
            factoryRegle.getRegleAttaque(donnees);
            fail();
        }catch(FunctionnalExeption e) {
            validateFunctionnalException(e);
        }
    }
    
    @Test
    public void testStadeAttaqueOrkInexistantEnAttaque() {
        try {
            parameters.clear();
            parameters.put(EAttaqueOrk.ID_MAP_ATTAQUE_ORK, EAttaqueOrk.WAAAGH.getIdAttaqueOrk());
            parameters.put(EPhaseAttaqueOrk.ID_MAP_PHASE_ATTAQUE_ORK, -1);
            Mockito.when(donnees.getDonneesAttaquant()).thenReturn(parameters);
            factoryRegle.getRegleAttaque(donnees);
            fail();
        }catch(FunctionnalExeption e) {
            validateFunctionnalException(e);
        }
    }
    
    @Test
    public void testAttaqueOrkAbsentPourDefense() {
        try {
            parameters.clear();
            Mockito.when(donnees.getDonneesDefenseur()).thenReturn(parameters);
            factoryRegle.getRegleDefense(donnees);
            fail();
        }catch(FunctionnalExeption e) {
            validateFunctionnalException(e);
        }
    }
    
    @Test
    public void testAttaqueOrkInexistantePourDefense() {
        try {
            parameters.clear();
            parameters.put(EAttaqueOrk.ID_MAP_ATTAQUE_ORK, -1);
            Mockito.when(donnees.getDonneesDefenseur()).thenReturn(parameters);
            factoryRegle.getRegleDefense(donnees);
            fail();
        }catch(FunctionnalExeption e) {
            validateFunctionnalException(e);
        }
    }
    
    @Test
    public void testStadeAttaqueOrkAbsentEnDefense() {
        try {
            parameters.clear();
            parameters.put(EAttaqueOrk.ID_MAP_ATTAQUE_ORK, EAttaqueOrk.WAAAGH.getIdAttaqueOrk());
            Mockito.when(donnees.getDonneesDefenseur()).thenReturn(parameters);
            factoryRegle.getRegleDefense(donnees);
            fail();
        }catch(FunctionnalExeption e) {
            validateFunctionnalException(e);
        }
    }
    
    @Test
    public void testStadeAttaqueOrkInexistantEnDefense() {
        try {
            parameters.clear();
            parameters.put(EAttaqueOrk.ID_MAP_ATTAQUE_ORK, EAttaqueOrk.WAAAGH.getIdAttaqueOrk());
            parameters.put(EPhaseAttaqueOrk.ID_MAP_PHASE_ATTAQUE_ORK, -1);
            Mockito.when(donnees.getDonneesDefenseur()).thenReturn(parameters);
            factoryRegle.getRegleDefense(donnees);
            fail();
        }catch(FunctionnalExeption e) {
            validateFunctionnalException(e);
        }
    }
    
    @Test
    public void testRegleAttaqueChargeApresMouvement() throws FunctionnalExeption{
        for(EMouvement mouvement:EMouvement.values()) {
            for(EProfil typeProfil:EProfil.values()) {
                testRegleAttaqueChargeApresMouvement(mouvement, typeProfil);
            }
        }
    }
    
    private void testRegleAttaqueChargeApresMouvement(EMouvement mouvement,EProfil typeProfil) throws FunctionnalExeption{
        boolean isChargeApresMouvement = Arrays.asList(EMouvement.IMMOBILE,EMouvement.NORMAL).contains(mouvement);
        boolean isChargeApresAdvance;
        IRegleAttaque regle;
        for(EAttaqueOrk typeWaaagh:EAttaqueOrk.values()) {
            for(EPhaseAttaqueOrk stade:EPhaseAttaqueOrk.values()) {
                initMockAttaque(typeWaaagh, stade, typeProfil);
                regle = factoryRegle.getRegleAttaque(donnees);
                isChargeApresAdvance = typeWaaagh == EAttaqueOrk.WAAAGH
                        && stade == EPhaseAttaqueOrk.PHASE_1
                            &&mouvement == EMouvement.ADVANCE
                                && Arrays.asList(EProfil.BASE,EProfil.PERSONNAGE).contains(typeProfil);
                Assertions.assertThat(regle.isChargeApresTypeMouvement(mouvement)).isEqualTo(
                        isChargeApresMouvement || isChargeApresAdvance);
            }
        }
    }
    
    @Test
    public void testBonusAttaqueEtForce() throws FunctionnalExeption{
        for(EProfil typeProfil:EProfil.values()) {
            testBonusAttaqueEtForce(typeProfil);
        }
    }
    
    private void testBonusAttaqueEtForce(EProfil typeProfil) throws FunctionnalExeption{
        boolean isBonus;
        Integer bonus;
        IRegleAttaque regle;
        for(EAttaqueOrk typeWaaagh:EAttaqueOrk.values()) {
            for(EPhaseAttaqueOrk stade:EPhaseAttaqueOrk.values()) {
                initMockAttaque(typeWaaagh, stade, typeProfil);
                regle = factoryRegle.getRegleAttaque(donnees);
                isBonus = typeWaaagh == EAttaqueOrk.WAAAGH;
                bonus = isBonus?1:0;
                Assertions.assertThat(regle.getBonusNombreAttaque()).isEqualTo(bonus);
                Assertions.assertThat(regle.getBonusForce()).isEqualTo(bonus);
            }
        }
    }
    
    @Test
    public void testRegleIgnoreMalusAvecArmeAssaut()throws FunctionnalExeption{
        for(EArme typeArme:EArme.values()) {
            for(EProfil typeProfil: EProfil.values()) {
                testRegleIgnoreMalusAvecArmeAssaut(typeArme, typeProfil);
            }
        }
    }
    
    private void testRegleIgnoreMalusAvecArmeAssaut(EArme typeArme,EProfil typeProfil)throws FunctionnalExeption{
        IRegleAttaque regle;
        boolean isIgnoreMalusAdvance;
        for(EAttaqueOrk typeWaaagh:EAttaqueOrk.values()) {
            for(EPhaseAttaqueOrk stade:EPhaseAttaqueOrk.values()) {
                initMockAttaque(typeWaaagh, stade, typeProfil);
                if(typeWaaagh == EAttaqueOrk.ZYWAAAGH) {
                    Mockito.when(arme.getType()).thenReturn(typeArme);
                }
                
                regle = factoryRegle.getRegleAttaque(donnees);
                
                isIgnoreMalusAdvance = typeWaaagh == EAttaqueOrk.ZYWAAAGH
                        && stade == EPhaseAttaqueOrk.PHASE_1
                            && typeArme == EArme.ASSAUT;
                
                Assertions.assertThat(regle.isIgnoreMalusMouvementAuTir(EMouvement.ADVANCE)).isEqualTo(isIgnoreMalusAdvance);
            }
        }        
    }
    
    @Test
    public void testRegleBonusAttaque() throws FunctionnalExeption{
        for(EArme typeArme:EArme.values()) {
            for(EProfil typeProfil:EProfil.values()) {
                testRegleBonusAttaque(typeArme, typeProfil);
            }
        }
    }
    
    private void testRegleBonusAttaque(EArme typeArme,EProfil typeProfil) throws FunctionnalExeption{
        IRegleAttaque regle;
        boolean isBonus;
        Integer bonus;
        for(EAttaqueOrk typeWaaagh:EAttaqueOrk.values()) {
            for(EPhaseAttaqueOrk stade:EPhaseAttaqueOrk.values()) {
                initMockAttaque(typeWaaagh, stade, typeProfil);
                if(typeWaaagh == EAttaqueOrk.ZYWAAAGH) {
                    Mockito.when(arme.getType()).thenReturn(typeArme);
                }
                
                regle = factoryRegle.getRegleAttaque(donnees);
                
                isBonus = typeWaaagh == EAttaqueOrk.ZYWAAAGH
                            && stade == EPhaseAttaqueOrk.PHASE_1
                                && typeArme == EArme.DAKA
                                    && Arrays.asList(EProfil.VEHICULE,EProfil.MOTO).contains(typeProfil);
                
                bonus = isBonus?1:0;
                Assertions.assertThat(regle.getBonusAttaqueArme(typeArme)).isEqualTo(bonus);
            }
        }
    }
    
    @Test
    public void testRegleBonusPA() throws FunctionnalExeption{
        for(EArme typeArme:EArme.values()) {
            for(EProfil typeProfil:EProfil.values()) {
                testRegleBonusPA(typeArme, typeProfil);
            }
        }
    }
    
    private void testRegleBonusPA(EArme typeArme,EProfil typeProfil) throws FunctionnalExeption{
        IRegleAttaque regle;
        boolean isBonus;
        Integer bonus;
        for(EAttaqueOrk typeWaaagh:EAttaqueOrk.values()) {
            for(EPhaseAttaqueOrk stade:EPhaseAttaqueOrk.values()) {
                initMockAttaque(typeWaaagh, stade, typeProfil);
                if(typeWaaagh == EAttaqueOrk.ZYWAAAGH) {
                    Mockito.when(arme.getType()).thenReturn(typeArme);
                }
                
                regle = factoryRegle.getRegleAttaque(donnees);
                isBonus = typeWaaagh == EAttaqueOrk.ZYWAAAGH
                        && typeArme != EArme.CORPS_A_CORPS
                            && Arrays.asList(EProfil.VEHICULE,EProfil.MOTO).contains(typeProfil);
                bonus = isBonus?-1:0;
                
                Assertions.assertThat(regle.getBonusPA()).isEqualTo(bonus);
            }
        }
    }
    
    private void initMockAttaque(EAttaqueOrk typeWaaagh,EPhaseAttaqueOrk stade,EProfil typeProfil) {
        parameters.clear();
        parameters.put(EAttaqueOrk.ID_MAP_ATTAQUE_ORK, typeWaaagh.getIdAttaqueOrk());
        parameters.put(EPhaseAttaqueOrk.ID_MAP_PHASE_ATTAQUE_ORK, stade.getIdPhase());
        Mockito.when(donnees.getDonneesAttaquant()).thenReturn(parameters);
        
        Mockito.when(donnees.getAttaquant()).thenReturn(attaquant);
        Mockito.when(attaquant.getProfil()).thenReturn(profil);
        Set<EProfil> types = new HashSet<>(Arrays.asList(typeProfil));
        Mockito.when(profil.getTypesProfils()).thenReturn(types);
        
        if(typeWaaagh != EAttaqueOrk.AUCUN) {
            Mockito.when(attaquant.getArme()).thenReturn(arme);
        }
    }
    
    @Test
    public void testSauvegardeInvulnerable() throws FunctionnalExeption{
        for(EAttaqueOrk typeWaaagh:EAttaqueOrk.values()) {
            for(EPhaseAttaqueOrk stade:EPhaseAttaqueOrk.values()) {
                testSauvegardeInvulnerable(typeWaaagh, stade);
            }
        }
    }
    
    private void testSauvegardeInvulnerable(EAttaqueOrk typeWaaagh,EPhaseAttaqueOrk stade) throws FunctionnalExeption{
        initMockDefense(typeWaaagh, stade);
        IRegleDefense regle = factoryRegle.getRegleDefense(donnees);
        Integer sauvegarde;
        if(typeWaaagh == EAttaqueOrk.WAAAGH) {
            sauvegarde = stade == EPhaseAttaqueOrk.PHASE_1?5:6;
        }else {
            sauvegarde = 0;
        }
        Assertions.assertThat(regle.getSauvegardeInvulnerable()).isEqualTo(sauvegarde);
    }
    
    private void initMockDefense(EAttaqueOrk typeWaaagh,EPhaseAttaqueOrk stade) {
        parameters.clear();
        parameters.put(EAttaqueOrk.ID_MAP_ATTAQUE_ORK, typeWaaagh.getIdAttaqueOrk());
        parameters.put(EPhaseAttaqueOrk.ID_MAP_PHASE_ATTAQUE_ORK, stade.getIdPhase());
        Mockito.when(donnees.getDonneesDefenseur()).thenReturn(parameters);
    }
}
Reply
#9
Pour l'instant, j'étais sur une BDD H2 (BDD réduite sur un fichier écrit en Java).

Mais j'ai du installé dernièrement Docker.

De fait, j'en ai profité pour pouvoir lancer un serveur tapant dans une vraie BDD, en l’occurrence POSTGRESQL.

Ne vous moquez pas, Mamar utilise pour son forum une fausse BDD, en l'occurence MYSQL.
https://sqlpro.developpez.com/tutoriel/d...l-mariadb/
Reply
#10
Quelqu'un qui utilise MariaDB en entreprise est un inconscient, quelqu'un qui se dit qu'il a besoin d'un Oracle RAC pour faire tourner un forum privé de 6 personnes est un dément redaface2

Bref, à chaque usage ses outils  Boidleau
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)