1 Commits

Author SHA1 Message Date
e918b26d6c ajout d'un peu de couverture de code
Some checks failed
check main state / build (8.0.x) (push) Failing after 1m17s
Main Build Process / Build & Test (pull_request) Failing after 1m44s
2024-08-29 23:49:14 +02:00
20 changed files with 55 additions and 251 deletions

View File

@@ -8,14 +8,14 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
dotnet-version: [ '10.0.x' ]
dotnet-version: [ '8.0.x' ]
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- name: Setup dotnet
uses: actions/setup-dotnet@v3
with:
dotnet-version: '10.0.x'
dotnet-version: '8.0.x'
- name: Install dependencies
run: dotnet restore ./src/LittleTown.sln
- name: Build

View File

@@ -24,45 +24,28 @@ jobs:
steps:
- name: Check out the code
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
10.x
8.x
- name: "Restore/Build/Test"
run: |
dotnet test ./src/LittleTown.sln --configuration Release --verbosity normal --logger trx --collect:"XPlat Code Coverage" --logger:"trx;LogFileName=test_results.xml"
- name: Combine Coverage Reports # This is because one report is produced per project, and we want one result for all of them.
uses: danielpalme/ReportGenerator-GitHub-Action@v5.5.1
uses: danielpalme/ReportGenerator-GitHub-Action@5.3.8
with:
reports: "**/*.cobertura.xml" # REQUIRED # The coverage reports that should be parsed (separated by semicolon). Globbing is supported.
targetdir: "coverage-report" # REQUIRED # The directory where the generated report should be saved.
reporttypes: "Html;MarkdownSummary;Cobertura" # The output formats and scope (separated by semicolon) Values: Badges, Clover, Cobertura, CsvSummary, Html, Html_Dark, Html_Light, Html_BlueRed, HtmlChart, HtmlInline, HtmlInline_AzurePipelines, HtmlInline_AzurePipelines_Dark, HtmlInline_AzurePipelines_Light, HtmlSummary, JsonSummary, Latex, LatexSummary, lcov, MarkdownSummary, MarkdownSummaryGithub, MarkdownDeltaSummary, MHtml, PngChart, SonarQube, TeamCitySummary, TextSummary, TextDeltaSummary, Xml, XmlSummary
targetdir: "${{ github.workspace }}" # REQUIRED # The directory where the generated report should be saved.
reporttypes: "Cobertura" # The output formats and scope (separated by semicolon) Values: Badges, Clover, Cobertura, CsvSummary, Html, Html_Dark, Html_Light, Html_BlueRed, HtmlChart, HtmlInline, HtmlInline_AzurePipelines, HtmlInline_AzurePipelines_Dark, HtmlInline_AzurePipelines_Light, HtmlSummary, JsonSummary, Latex, LatexSummary, lcov, MarkdownSummary, MarkdownSummaryGithub, MarkdownDeltaSummary, MHtml, PngChart, SonarQube, TeamCitySummary, TextSummary, TextDeltaSummary, Xml, XmlSummary
verbosity: "Info" # The verbosity level of the log messages. Values: Verbose, Info, Warning, Error, Off
title: "Code Coverage" # Optional title.
tag: "${{ github.run_number }}_${{ github.run_id }}" # Optional tag or build version.
customSettings: "" # Optional custom settings (separated by semicolon). See: https://github.com/danielpalme/ReportGenerator/wiki/Settings.
toolpath: "reportgeneratortool" # Default directory for installing the dotnet tool.
- name: Upload coverage report (debug)
uses: actions/upload-artifact@v3
with:
name: coverage-report
path: coverage-report/
if-no-files-found: error
- name: Publish coverage to pages
run: ls coverage-report
- name: Upload coverage via SSH
uses: appleboy/scp-action@v1
with:
host: "192.168.1.103"
username: "gitea"
password: "password"
port: 2222
source: "coverage-report/*"
target: "/config/test"
- name: Upload Combined Coverage XML
uses: actions/upload-artifact@v3
with:

View File

@@ -1,16 +0,0 @@
{
"extends": [
"config:base"
],
"packageRules": [
{
"updateTypes": [
"minor",
"patch",
"pin",
"digest"
],
"automerge": false
}
]
}

View File

@@ -1,15 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.2" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.9.0" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>
</Project>

View File

@@ -1,4 +1,6 @@
using System.Reflection;
using System.Text.Json;
using LittleTown.Core.Exceptions;
using LittleTown.StaticDataAcces;
namespace LittleTown.Core.Tests;
@@ -15,4 +17,21 @@ public class ExceptionTesting
Assert.Throws<JsonException>(() => getter.GetObjectives());
Assert.Throws<JsonException>(() => getter.GetBuildings());
}
[Fact]
public void NombreDeJoueurMauvaisDansMatch()
{
StaticDataGetter getter = new();
Match match2Player = new Match(getter);
match2Player.AddPlayer("Player1");
match2Player.AddPlayer("Player2");
Type type = match2Player.GetType();
PropertyInfo? prop = type?.BaseType?.GetProperty("_players");
prop?.SetValue(match2Player, new Dictionary<string, PlayerZone>(), null);
Assert.Throws<MatchConfigException>(() => match2Player.Init());
}
}

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
@@ -10,16 +10,16 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AutoMapper" Version="16.0.0" />
<PackageReference Include="Microsoft.CodeCoverage" Version="17.14.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="AutoMapper" Version="13.0.1" />
<PackageReference Include="Microsoft.CodeCoverage" Version="17.11.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.4">
<PackageReference Include="coverlet.collector" Version="6.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>

View File

@@ -17,7 +17,6 @@ public class MatchTesting
Match match2 = new Match(getter);
match2.AddPlayer("Player1");
match2.AddPlayer("Player2");
Assert.Throws<MatchConfigException>(() => match2.AddPlayer("Player2"));
match2.Init();
Match match3 = new Match(getter);
@@ -52,23 +51,10 @@ public class MatchTesting
PlayerZone player1 = match.GetPlayerZone("Player1");
PlayerZone player1_3 = match.GetPlayerZone("Player2");
Assert.Equal(3, player1.Ressources[Enums.ResourceType.Piece]);
player1.AddRessources(ResourceType.Piece, 1);
Assert.Equal(3, player1_3.Ressources[Enums.ResourceType.Piece]);
Assert.Equal(4, player1.Objectives.Count);
}
[Fact]
public void MatchGetters()
{
StaticDataGetter getter = new();
Match match = new Match(getter);
match.AddPlayer("Player1");
match.AddPlayer("Player2");
match.Init();
Assert.Throws<ArgumentException>(() => match.GetPlayerZone("UnknownPlayer"));
}
}

View File

@@ -1,34 +0,0 @@
using LittleTown.Core.Actions;
using LittleTown.Core.Exceptions;
using LittleTown.StaticDataAcces;
namespace LittleTown.Core.Tests;
public class MatchWorkflowTesting
{
[Fact]
public void Simple2PlayerGame()
{
StaticDataGetter getter = new StaticDataGetter();
Match match = new Match(getter);
match.AddPlayer("Player1");
match.AddPlayer("Player2");
match.Init();
int count = 0;
while (!match.IsDone)
{
EmptyAction action = new EmptyAction();
match.ExecuteAction(action);
count++;
if (count > 40)
{
Assert.Fail("Trop d'action pour une partie vide");
}
}
Assert.Throws<MatchFinishedException>(() => match.ExecuteAction(new EmptyAction()));
}
}

View File

@@ -1,21 +0,0 @@
namespace LittleTown.Core.Exceptions;
/// <summary>
/// Exception levee quand on essais d'executer une actin dans un match terminé
/// </summary>
public class MatchFinishedException : Exception
{
/// <summary> constructeur de base </summary>
public MatchFinishedException() : base() { }
/// <summary> Constructeur avec un message d'erreur </summary>
/// <param name="message">le message decrivant l'exception en detail</param>
public MatchFinishedException(string message) : base(message) { }
/// <summary>
/// Constructeur avec un message et une exception interne
/// </summary>
/// <param name="message">Le message de l'erreur</param>
/// <param name="innerException">l'exception encapsulée</param>
public MatchFinishedException(string message, Exception innerException) : base(message, innerException) { }
}

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
@@ -9,6 +9,8 @@
<EnableNETAnalyzers>true</EnableNETAnalyzers>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<AnalysisMode>All</AnalysisMode>
<DebugType>full</DebugType>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
</Project>

View File

@@ -1,4 +1,3 @@
using LittleTown.Core.Actions;
using LittleTown.Core.Exceptions;
using LittleTown.Core.Ports;
@@ -9,18 +8,6 @@ namespace LittleTown.Core;
/// </summary>
public class Match
{
/// <summary> LE numero du tour en cours (Partant de 1) </summary>
public int CurrentTurn { get; private set; } = 1;
/// <summary> l'id du joueur a qui c'est le tour de jouer</summary>
public string CurrentPlayer { get => _players[_playerTurnsOrder[_currentPlayerIndex]].PlayerName; }
/// <summary> Indique si le match est terminé </summary>
public bool IsDone { get; private set; }
/// <summary>la liste indiquant l'ordre des joueurs, _playerTurnsOrder[0] donne l'index du 1er joueur, _playerTurnsOrder[1] du second..... </summary>
private List<int> _playerTurnsOrder = new List<int>();
private const int _minPlayerCount = 2;
private const int _maxPlayerCount = 4;
@@ -33,12 +20,18 @@ public class Match
private Random _random = new Random();
private List<PlayerZone> _players = new();
private int _currentPlayerIndex;
private Dictionary<string, PlayerZone> _players = new();
/// <summary> LE numero du tour en cours (Partant de 1) </summary>
public int CurrentTurn { get; private set; } = 1;
/// <summary>la liste indiquant l'ordre des joueurs, _playerTurnsOrder[0] donne l'index du 1er joueur, _playerTurnsOrder[1] du second..... </summary>
private List<int> _playerTurnsOrder = new List<int>();
/// <summary>
/// Constructeur d'une nouvelle partie avec un nombre de joueurs données en parametres
/// </summary>
/// <param name="nbPlayer"></param>
/// <param name="staticData">un objet permettant de récupérer les données statiques du jeu</param>
public Match(IStaticDataGetter staticData)
{
@@ -55,14 +48,11 @@ public class Match
{
if (_players.Count < _maxPlayerCount)
{
if (_players.Any(p => p.PlayerName == playerName))
if (_players.ContainsKey(playerName))
{
throw new MatchConfigException("Un joueur existe déjà avec ce nom");
}
_players.Add(new PlayerZone()
{
PlayerName = playerName
});
_players.Add(playerName, new PlayerZone());
}
else
{
@@ -70,25 +60,6 @@ public class Match
}
}
/// <summary>
/// Demander au match d'executer une action si elle est autorisée
/// </summary>
/// <param name="action">l'action a réaliser</param>
public void ExecuteAction(IAction action)
{
ArgumentNullException.ThrowIfNull(action);
//quelques vérification génériques pour savoir si l'action peut être jouée
if (IsDone)
{
throw new MatchFinishedException("Impossible d'effectuer une action sur un match terminé");
}
//autoriser l'action a s'executer en lui donner les getters dont elle a besoin
action.Execute(this);
}
/// <summary> Initialiser la partie, il faut avoir ajouté les joueurs au préalable </summary>
/// <exception cref="MatchConfigException"></exception>
public void Init()
@@ -99,14 +70,13 @@ public class Match
ArgumentOutOfRangeException.ThrowIfGreaterThan(nbPlayer, _maxPlayerCount);
List<int> freeObjectiveIndexs = Enumerable.Range(0, _objectives.Count).ToList();
foreach (PlayerZone zone in _players)
foreach (PlayerZone zone in _players.Values)
{
zone.AddObjectives(GetRandomObjectives(nbPlayer switch
{
2 => 4,
3 => 3,
4 => 2,
_ => throw new MatchConfigException("Mauvais nombre de joueurs lors Workers")
}, freeObjectiveIndexs));
zone.AddRessources(Enums.ResourceType.Piece, 3);
}
@@ -136,8 +106,6 @@ public class Match
index = 0;
}
_currentPlayerIndex = 0;
}
/// <summary> Permet de récuperer une player zone(une copie) </summary>
@@ -145,10 +113,7 @@ public class Match
/// <returns></returns>
public PlayerZone GetPlayerZone(string playerName)
{
var value = _players.Where(p => p.PlayerName == playerName).FirstOrDefault();
if (null == value)
if (!_players.TryGetValue(playerName, out PlayerZone? value))
throw new ArgumentException("playerID is out of bound");
return value.Clone() as PlayerZone ?? throw new ArgumentException("Cast exception in GetPlayerZone"); ;
@@ -166,18 +131,4 @@ public class Match
}
return result;
}
/// <summary> Changer le joueur en cours pour passer au suivant </summary>
public void NextPlayer()
{
_currentPlayerIndex++;
if (_currentPlayerIndex >= _players.Count)
{
_currentPlayerIndex = 0;
CurrentTurn++;
}
if (CurrentTurn >= 4)
{
IsDone = true;
}
}
}

View File

@@ -7,8 +7,7 @@ public class PlayerZone : ICloneable
/// <summary> Les ressources que possede le joueur </summary>
public IDictionary<ResourceType, int> Ressources { get; init; } = new Dictionary<ResourceType, int>();
/// <summary> l'id du joueur a cette zone </summary>
public required string PlayerName { get; init; }
/// <summary> La liste des objectifs que le joueur possede/// </summary>
public IReadOnlyCollection<Objective> Objectives { get => _objectives.AsReadOnly(); init => _objectives = new List<Objective>(value); }
@@ -33,10 +32,6 @@ public class PlayerZone : ICloneable
}
}
/// <summary>
/// Assigner des objectifs au joueur
/// </summary>
/// <param name="objectives"></param>
public void AddObjectives(ICollection<Objective> objectives)
{
_objectives.AddRange(objectives);
@@ -50,8 +45,7 @@ public class PlayerZone : ICloneable
{
Ressources = new Dictionary<ResourceType, int>(Ressources),
Objectives = new List<Objective>(Objectives),
ScoreMarker = ScoreMarker,
PlayerName = PlayerName
ScoreMarker = ScoreMarker
};
return result;

View File

@@ -1,21 +0,0 @@
namespace LittleTown.Core.Actions;
/// <summary>
/// Un action de test qui permet de faire le déroulé d'une partie, cette action ne fait rien qu'utiliser un ouvrier du joueur et passer au suivant
/// </summary>
public class EmptyAction : IAction
{
/// <inheritdoc/>
public void Execute(Match match)
{
ArgumentNullException.ThrowIfNull(match);
match.NextPlayer();
}
/// <inheritdoc/>
public bool CanExecute(Match match)
{
return true;
}
}

View File

@@ -1,19 +0,0 @@
namespace LittleTown.Core.Actions;
/// <summary>
/// Action qui consiste a poser un pion sur le une case du plateau
/// </summary>
public class FieldAction : IAction
{
/// <inheritdoc/>>
public void Execute(Match match)
{
throw new NotImplementedException();
}
/// <inheritdoc/>>
public bool CanExecute(Match match)
{
return true;
}
}

View File

@@ -1,20 +0,0 @@
namespace LittleTown.Core.Actions;
/// <summary>
/// Interface qui représente ce que doivent implémenter les actions
/// </summary>
public interface IAction
{
/// <summary>
/// Methode demandant a l'action d'appliquer ses changement au match
/// </summary>
/// <param name="match">le match a modifier avec cette action</param>
public void Execute(Match match);
/// <summary>
/// Verifier si cette action peut être effectuée, si elle est légale
/// </summary>
/// <param name="match"></param>
/// <returns></returns>
public bool CanExecute(Match match);
}

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateDocumentationFile>true</GenerateDocumentationFile>