6) Définir des propriétés
Last updated
forall(terrain contenant des galinettes, groupe de chasseurs avec chacun-e a minima 1 balle)
La partie de chasse doit démarrer avec succèsforall(terrain sans galinettes, groupe de chasseurs avec au moins 1 chasseur sans balle)
La partie de chasse ne démarre pas car "pas de galinettes sur le terrain"dotnet add package FsCheck.xUnit[Property] // Annotation pour xUnit
public Property Sur1TerrainAvecGalinettesEtAuMoins1ChasseurAvecTousDesBalles() =>
Prop.ForAll(
null,
(terrain, chasseurs) => true
);private static Arbitrary<(string nom, int nbGalinettes)> terrainGenerator()
=> (from nom in Arb.Generate<string>()
// A minima 1 galinette sur le terrain
from nbGalinette in Gen.Choose(1, int.MaxValue)
select (nom, nbGalinette)).ToArbitrary();private static Arbitrary<(string nom, int nbBalles)> chasseurGenerator()
=> (from nom in Arb.Generate<string>()
// A minima 1 balle
from nbBalles in Gen.Choose(1, int.MaxValue)
select (nom, nbBalles)).ToArbitrary();private static Arbitrary<FSharpList<(string nom, int nbBalles)>> groupeDeChasseursGenerator()
=> // On définit le nombre de chasseurs dans le groupe [1; 1000]
(from nbChasseurs in Gen.Choose(1, 1_000)
// On utilise le nombre de chasseurs pour générer le bon nombre de chasseurs
select chasseurGenerator().Generator.Sample(1, nbChasseurs)).ToArbitrary();[Property]
public Property Sur1TerrainAvecGalinettesEtAuMoins1ChasseurAvecTousDesBalles() =>
Prop.ForAll(
terrainGenerator(),
groupeDeChasseursGenerator(),
(terrain, chasseurs) =>
{
var savedId = PartieDeChasseService.Demarrer(
terrain,
chasseurs.ToList()
);
return Repository.SavedPartieDeChasse()!.Id == savedId;
}
);private static Arbitrary<(string nom, int nbGalinettes)> terrainGenerator()
=> (from nom in Arb.Generate<string>()
from nbGalinette in Gen.Choose(1, int.MaxValue)
select (nom, nbGalinette)).ToArbitrary();
private static Arbitrary<(string nom, int nbBalles)> chasseurGenerator()
=> (from nom in Arb.Generate<string>()
from nbBalles in Gen.Choose(1, int.MaxValue)
select (nom, nbBalles)).ToArbitrary();
private static Arbitrary<FSharpList<(string nom, int nbBalles)>> groupeDeChasseursGenerator()
=> (from nbChasseurs in Gen.Choose(1, 1_000)
select chasseurGenerator().Generator.Sample(1, nbChasseurs)).ToArbitrary();
[Property]
public Property Sur1TerrainAvecGalinettesEtAuMoins1ChasseurAvecTousDesBalles() =>
Prop.ForAll(
terrainGenerator(),
groupeDeChasseursGenerator(),
(terrain, chasseurs) => DémarreLaPartieAvecSuccès(terrain, chasseurs));
private bool DémarreLaPartieAvecSuccès((string nom, int nbGalinettes) terrain,
IEnumerable<(string nom, int nbBalles)> chasseurs)
=> PartieDeChasseService.Demarrer(
terrain,
chasseurs.ToList()) == Repository.SavedPartieDeChasse()!.Id;[Fact]
public void SansChasseurs()
=> ExecuteAndAssertThrow<ImpossibleDeDémarrerUnePartieSansChasseur>(
s => s.Demarrer(("Pitibon sur Sauldre", 3), new List<(string, int)>()),
p => p.Should().BeNull()
);[Property]
public Property SansChasseursSurNimporteQuelTerrainRicheEnGalinette()
=> Prop.ForAll(
// On réutilise le générateur de terrains riches en galinettes
terrainGenerator(),
terrain =>
{
// On va refactorer pour réutiliser cette logique
try
{
PartieDeChasseService.Demarrer(
terrain,
new List<(string, int)>());
return false;
}
catch (ImpossibleDeDémarrerUnePartieSansChasseur)
{
return Repository.SavedPartieDeChasse() == null;
}
});protected bool MustFailWith<TException>(Action action, Func<PartieDeChasse?, bool>? assert = null)
where TException : Exception
{
try
{
action();
return false;
}
catch (TException)
{
return assert?.Invoke(SavedPartieDeChasse()) ?? true;
}
}
private bool EchoueAvec<TException>(
(string nom, int nbGalinettes) terrain,
IEnumerable<(string nom, int nbBalles)> chasseurs,
Func<PartieDeChasse?, bool>? assert = null) where TException : Exception
=> MustFailWith<TException>(() => PartieDeChasseService.Demarrer(terrain, chasseurs.ToList()), assert);
[Property]
public Property SansChasseursSurNimporteQuelTerrainRicheEnGalinette()
=> ForAll(
terrainRicheEnGalinettesGenerator(),
terrain =>
EchoueAvec<ImpossibleDeDémarrerUnePartieSansChasseur>(
terrain,
PasDeChasseurs,
savedPartieDeChasse => savedPartieDeChasse == null)