18 Commits

Author SHA1 Message Date
Renovate Bot
2a31e02556 Update actions/setup-dotnet action to v5
All checks were successful
check main state / build (10.0.x) (push) Successful in 1m38s
Main Build Process / Build & Test (pull_request) Successful in 1m28s
2026-02-05 21:01:41 +00:00
73ba6d36a2 Update dependency Microsoft.AspNetCore.OpenApi to v10 (#23)
All checks were successful
check main state / build (10.0.x) (push) Successful in 1m44s
Main Build Process / Build & Test (push) Successful in 1m34s
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [Microsoft.AspNetCore.OpenApi](https://asp.net/) ([source](https://github.com/dotnet/dotnet)) | `8.0.23` → `10.0.2` | ![age](https://developer.mend.io/api/mc/badges/age/nuget/Microsoft.AspNetCore.OpenApi/10.0.2?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/nuget/Microsoft.AspNetCore.OpenApi/8.0.23/10.0.2?slim=true) |

---

### Release Notes

<details>
<summary>dotnet/dotnet (Microsoft.AspNetCore.OpenApi)</summary>

### [`v9.0.7`](https://github.com/dotnet/dotnet/releases/tag/v9.0.7): .NET 9.0.7

You can build .NET 9.0 from the repository by cloning the release tag `v9.0.7` and following the build instructions in the [main README.md](https://github.com/dotnet/dotnet/blob/v9.0.7/README.md#building).

Alternatively, you can build from the sources attached to this release directly.
More information on this process can be found in the [dotnet/dotnet repository](https://github.com/dotnet/dotnet/blob/v9.0.7/README.md#building-from-released-sources).

Attached are PGP signatures for the GitHub generated tarball and zipball. You can find the public key at <https://dot.net/release-key-2023>

### [`v9.0.6`](https://github.com/dotnet/dotnet/releases/tag/v9.0.6): .NET 9.0.6

You can build .NET 9.0 from the repository by cloning the release tag `v9.0.6` and following the build instructions in the [main README.md](https://github.com/dotnet/dotnet/blob/v9.0.6/README.md#building).

Alternatively, you can build from the sources attached to this release directly.
More information on this process can be found in the [dotnet/dotnet repository](https://github.com/dotnet/dotnet/blob/v9.0.6/README.md#building-from-released-sources).

Attached are PGP signatures for the GitHub generated tarball and zipball. You can find the public key at <https://dot.net/release-key-2023>

### [`v9.0.5`](https://github.com/dotnet/dotnet/releases/tag/v9.0.5): .NET 9.0.5

You can build .NET 9.0 from the repository by cloning the release tag `v9.0.5` and following the build instructions in the [main README.md](https://github.com/dotnet/dotnet/blob/v9.0.5/README.md#building).

Alternatively, you can build from the sources attached to this release directly.
More information on this process can be found in the [dotnet/dotnet repository](https://github.com/dotnet/dotnet/blob/v9.0.5/README.md#building-from-released-sources).

Attached are PGP signatures for the GitHub generated tarball and zipball. You can find the public key at <https://dot.net/release-key-2023>

### [`v9.0.4`](https://github.com/dotnet/dotnet/releases/tag/v9.0.4): .NET 9.0.4

You can build .NET 9.0 from the repository by cloning the release tag `v9.0.4` and following the build instructions in the [main README.md](https://github.com/dotnet/dotnet/blob/v9.0.4/README.md#building).

Alternatively, you can build from the sources attached to this release directly.
More information on this process can be found in the [dotnet/dotnet repository](https://github.com/dotnet/dotnet/blob/v9.0.4/README.md#building-from-released-sources).

Attached are PGP signatures for the GitHub generated tarball and zipball. You can find the public key at <https://dot.net/release-key-2023>

### [`v9.0.3`](https://github.com/dotnet/dotnet/releases/tag/v9.0.3): .NET 9.0.3

You can build .NET 9.0 from the repository by cloning the release tag `v9.0.3` and following the build instructions in the [main README.md](https://github.com/dotnet/dotnet/blob/v9.0.3/README.md#building).

Alternatively, you can build from the sources attached to this release directly.
More information on this process can be found in the [dotnet/dotnet repository](https://github.com/dotnet/dotnet/blob/v9.0.3/README.md#building-from-released-sources).

Attached are PGP signatures for the GitHub generated tarball and zipball. You can find the public key at <https://dot.net/release-key-2023>

### [`v9.0.2`](https://github.com/dotnet/dotnet/releases/tag/v9.0.2): .NET 9.0.2

You can build .NET 9.0 from the repository by cloning the release tag `v9.0.2` and following the build instructions in the [main README.md](https://github.com/dotnet/dotnet/blob/v9.0.2/README.md#building).

Alternatively, you can build from the sources attached to this release directly.
More information on this process can be found in the [dotnet/dotnet repository](https://github.com/dotnet/dotnet/blob/v9.0.2/README.md#building-from-released-sources).

Attached are PGP signatures for the GitHub generated tarball and zipball. You can find the public key at <https://dot.net/release-key-2023>

### [`v9.0.1`](https://github.com/dotnet/dotnet/releases/tag/v9.0.1): .NET 9.0.1

You can build .NET 9.0 from the repository by cloning the release tag `v9.0.1` and following the build instructions in the [main README.md](https://github.com/dotnet/dotnet/blob/v9.0.1/README.md#building).

Alternatively, you can build from the sources attached to this release directly.
More information on this process can be found in the [dotnet/dotnet repository](https://github.com/dotnet/dotnet/blob/v9.0.1/README.md#building-from-released-sources).

Attached are PGP signatures for the GitHub generated tarball and zipball. You can find the public key at <https://dot.net/release-key-2023>

### [`v9.0.0`](https://github.com/dotnet/dotnet/releases/tag/v9.0.0): .NET 9.0.0

You can build .NET 9.0 from the repository by cloning the release tag `v9.0.0` and following the build instructions in the [main README.md](https://github.com/dotnet/dotnet/blob/v9.0.0/README.md#building).

Alternatively, you can build from the sources attached to this release directly.
More information on this process can be found in the [dotnet/dotnet repository](https://github.com/dotnet/dotnet/blob/v9.0.0/README.md#building-from-released-sources).

Attached are PGP signatures for the GitHub generated tarball and zipball. You can find the public key at <https://dot.net/release-key-2023>

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4zLjUiLCJ1cGRhdGVkSW5WZXIiOiI0My4zLjUiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=-->

Co-authored-by: Renovate Bot <renovate-bot@gitea.borealian.com>
Reviewed-on: #23
Co-authored-by: mcmuzzle <vezuvan@hotmail.com>
Co-committed-by: mcmuzzle <vezuvan@hotmail.com>
2026-02-05 20:59:39 +00:00
c656206513 [FEAT] mise en place des action pour passer
All checks were successful
Main Build Process / Build & Test (pull_request) Successful in 1m20s
check main state / build (8.0.x) (push) Successful in 1m29s
Main Build Process / Build & Test (push) Successful in 1m21s
2026-02-05 20:13:45 +00:00
Renovate Bot
55750bb5e5 Update actions/checkout action to v6
All checks were successful
check main state / build (8.0.x) (push) Successful in 1m29s
Main Build Process / Build & Test (push) Successful in 1m21s
2026-02-05 17:55:29 +00:00
Renovate Bot
9f9032d9af Update danielpalme/ReportGenerator-GitHub-Action action to v5.5.1
Some checks failed
Main Build Process / Build & Test (pull_request) Successful in 1m24s
Main Build Process / Build & Test (push) Has been cancelled
check main state / build (8.0.x) (push) Has been cancelled
2026-02-05 16:52:28 +00:00
Renovate Bot
effa82a069 Update dependency AutoMapper to v16
All checks were successful
Main Build Process / Build & Test (pull_request) Successful in 1m19s
check main state / build (8.0.x) (push) Successful in 1m49s
Main Build Process / Build & Test (push) Successful in 1m21s
2026-02-05 15:11:55 +00:00
Renovate Bot
25a4d10229 Update vstest monorepo to v17.14.1
All checks were successful
check main state / build (8.0.x) (push) Successful in 1m44s
Main Build Process / Build & Test (push) Successful in 1m33s
2026-02-05 14:50:38 +00:00
Renovate Bot
ebc50f693d Update dependency coverlet.collector to v6.0.4
Some checks failed
Main Build Process / Build & Test (pull_request) Successful in 1m25s
Main Build Process / Build & Test (push) Has been cancelled
check main state / build (8.0.x) (push) Successful in 1m31s
2026-02-05 14:38:08 +00:00
Renovate Bot
396d8070d5 Update dependency Microsoft.AspNetCore.OpenApi to 8.0.23
Some checks failed
Main Build Process / Build & Test (push) Has been cancelled
check main state / build (8.0.x) (push) Successful in 1m33s
Main Build Process / Build & Test (pull_request) Successful in 1m19s
2026-02-05 14:34:32 +00:00
Renovate Bot
6342cc4296 Update xunit-dotnet monorepo
Some checks failed
Main Build Process / Build & Test (push) Has been cancelled
check main state / build (8.0.x) (push) Successful in 1m48s
Main Build Process / Build & Test (pull_request) Successful in 1m45s
2026-02-05 14:32:41 +00:00
Renovate Bot
bf67c69899 Update dependency Swashbuckle.AspNetCore to v6.9.0
Some checks failed
Main Build Process / Build & Test (pull_request) Successful in 1m24s
check main state / build (8.0.x) (push) Successful in 1m45s
Main Build Process / Build & Test (push) Has been cancelled
2026-02-05 11:25:51 +00:00
97e5f6876b Ajout de la configuration pour renovate
All checks were successful
Main Build Process / Build & Test (pull_request) Successful in 1m10s
check main state / build (8.0.x) (push) Successful in 58s
Main Build Process / Build & Test (push) Successful in 2m57s
2024-11-02 16:58:26 +01:00
0503e95d64 plus simple
All checks were successful
Main Build Process / Build & Test (pull_request) Successful in 1m42s
check main state / build (8.0.x) (push) Successful in 55s
Main Build Process / Build & Test (push) Successful in 1m23s
2024-09-03 20:59:49 +02:00
4a5fc49c31 1er essais
All checks were successful
check main state / build (8.0.x) (push) Successful in 1m42s
Main Build Process / Build & Test (pull_request) Successful in 2m12s
2024-08-30 16:08:51 +02:00
b5a6b1c653 ajout d'un peu de couverture de code
All checks were successful
Main Build Process / Build & Test (pull_request) Successful in 1m56s
check main state / build (8.0.x) (push) Successful in 1m17s
Main Build Process / Build & Test (push) Successful in 2m15s
2024-08-30 00:02:05 +02:00
3cb1973fd1 ajout projet backend vide
All checks were successful
Main Build Process / Build & Test (pull_request) Successful in 1m39s
check main state / build (8.0.x) (push) Successful in 2m10s
Main Build Process / Build & Test (push) Successful in 1m28s
2024-08-29 22:20:45 +02:00
b77185fdc8 retour check main
All checks were successful
check main state / build (8.0.x) (push) Successful in 1m44s
Main Build Process / Build & Test (pull_request) Successful in 1m28s
Main Build Process / Build & Test (push) Successful in 2m5s
2024-08-29 19:58:17 +02:00
1d4f373c8f Ajout de commentaire automatique dans les PR
All checks were successful
Main Build Process / Build & Test (push) Successful in 1m37s
2024-08-29 19:54:35 +02:00
34 changed files with 833 additions and 57 deletions

View File

@@ -5,6 +5,7 @@ root = true
[*.cs]
dotnet_diagnostic.IDE1006.severity = warning
dotnet_diagnostic.IDE0005.severity = error
dotnet_diagnostic.CA5394.severity = none
# Exclude generated code
[src/**/Migrations/*.cs]

View File

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

View File

@@ -0,0 +1,82 @@
name: "Main Build Process"
# Runs on main branch commits,
# every commit in a pull request, any published release.
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
release:
types: [published]
env:
REGISTRY: gitea.borealian.ovh
IMAGE_NAME: ${{ github.repository }}
jobs:
build:
name: "Build & Test"
# Permissions this GitHub Action needs for other things in GitHub
permissions: write-all
runs-on: ubuntu-latest
steps:
- name: Check out the code
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: |
10.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
with:
reports: "**/*.cobertura.xml" # REQUIRED # The coverage reports that should be parsed (separated by semicolon). Globbing is supported.
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 Combined Coverage XML
uses: actions/upload-artifact@v3
with:
name: coverage
path: ${{ github.workspace }}/Cobertura.xml
retention-days: 5
- name: Publish Code Coverage Report
uses: irongut/CodeCoverageSummary@v1.3.0
with:
filename: "Cobertura.xml"
badge: true
fail_below_min: false # just informative for now
format: markdown
hide_branch_rate: false
hide_complexity: false
indicators: true
output: both
thresholds: "10 30"
- name: Comment on Gitea PR
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
GITEA_URL: https://gitea.borealian.ovh
REPO_OWNER: mcmuzzle
REPO_NAME: LittleTown
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
COMMENT_CONTENT=$(cat code-coverage-results.md)
curl -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
-d "{\"body\": \"${COMMENT_CONTENT}\"}" \
${GITEA_URL}/api/v1/repos/${REPO_OWNER}/${REPO_NAME}/issues/${PR_NUMBER}/comments

4
.gitignore vendored
View File

@@ -14,4 +14,6 @@
bin
obj
report
tools/
TestResults

View File

@@ -0,0 +1,6 @@
Pour générer la couverture en local il faut installer l'outil :
- dotnet tool install -g dotnet-reportgenerator-globaltool
- dotnet tool install dotnet-reportgenerator-globaltool --tool-path tools
Pour le lancer
- reportgenerator "-reports:src/**/TestResults/**/coverage.cobertura.xml" "-targetdir:./report" "-reporttypes:Html"

16
renovate.json Normal file
View File

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

View File

@@ -0,0 +1,13 @@
#supprimer les dossiers de tests précédents
get-childitem -Include TestResults -Recurse -force | Remove-Item -Force -Recurse
#lancer les tests
dotnet test ./src/LittleTown.sln --configuration Release --verbosity normal --logger trx --collect:"XPlat Code Coverage" --logger:"trx;LogFileName=test_results.xml"
#générer le rapport html
reportgenerator "-reports:src/**/TestResults/**/coverage.cobertura.xml" "-targetdir:./report" "-reporttypes:Html"
#ouvrir le fichier html
report/index.html

View File

@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.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" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,6 @@
@LittleTown.Api_HostAddress = http://localhost:5166
GET {{LittleTown.Api_HostAddress}}/helloWorld/
Accept: application/json
###

View File

@@ -0,0 +1,26 @@
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.MapGet("/helloWorld", () =>
{
return "Hello World";
})
.WithName("HelloWorld")
.WithOpenApi();
app.Run();

View File

@@ -0,0 +1,41 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:12798",
"sslPort": 44325
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5166",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7114;http://localhost:5166",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

View File

@@ -0,0 +1,18 @@
using System.Text.Json;
using LittleTown.StaticDataAcces;
namespace LittleTown.Core.Tests;
public class ExceptionTesting
{
[Fact]
public void ExceptionForStaticData()
{
StaticDataGetter getter = new StaticDataGetter("null", "null", "null");
Assert.Throws<JsonException>(() => getter.GetBoard(1));
Assert.Throws<JsonException>(() => getter.GetObjectives());
Assert.Throws<JsonException>(() => getter.GetBuildings());
}
}

View File

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

View File

@@ -1,3 +1,5 @@
using LittleTown.Core.Enums;
using LittleTown.Core.Exceptions;
using LittleTown.StaticDataAcces;
namespace LittleTown.Core.Tests;
@@ -8,20 +10,65 @@ public class MatchTesting
public void EnforcePlayerCountInMatchCreation()
{
StaticDataGetter getter = new();
Assert.Throws<ArgumentOutOfRangeException>(() => { new Match(1, getter); });
var match = new Match(getter);
match.AddPlayer("Player1");
Assert.Throws<ArgumentOutOfRangeException>(() => { match.Init(); });
Match match2Player = new Match(2, getter);
Match match2 = new Match(getter);
match2.AddPlayer("Player1");
match2.AddPlayer("Player2");
Assert.Throws<MatchConfigException>(() => match2.AddPlayer("Player2"));
match2.Init();
Match match3Player = new Match(3, getter);
Match match3 = new Match(getter);
match3.AddPlayer("Player1");
match3.AddPlayer("Player2");
match3.AddPlayer("Player3");
match3.Init();
Match match4Player = new Match(4, getter);
Match match4 = new Match(getter);
match4.AddPlayer("Player1");
match4.AddPlayer("Player2");
match4.AddPlayer("Player3");
match4.AddPlayer("Player4");
match4.Init();
Assert.Throws<ArgumentOutOfRangeException>(() => { new Match(5, getter); });
Match match5 = new Match(getter);
match5.AddPlayer("Player1");
match5.AddPlayer("Player2");
match5.AddPlayer("Player3");
match5.AddPlayer("Player4");
Assert.Throws<MatchConfigException>(() => { match5.AddPlayer("Player5"); });
}
[Fact]
public void CheckBoardBoundaries()
public void TwoPlayerInitMatchTest()
{
StaticDataGetter getter = new();
Match match = new Match(getter);
match.AddPlayer("Player1");
match.AddPlayer("Player2");
match.Init();
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

@@ -0,0 +1,34 @@
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

@@ -0,0 +1,183 @@
using LittleTown.Core.Actions;
using LittleTown.Core.Exceptions;
using LittleTown.Core.Ports;
namespace LittleTown.Core;
/// <summary>
/// Represente un match de LittleTown
/// </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;
private int _maxWorkerPerPlayer;
private int _maxBuidingPerPlayer;
private readonly Board _board;
private ICollection<Building> _buildings;
private ICollection<Objective> _objectives;
private Random _random = new Random();
private List<PlayerZone> _players = new();
private int _currentPlayerIndex;
/// <summary>
/// Constructeur d'une nouvelle partie avec un nombre de joueurs données en parametres
/// </summary>
/// <param name="staticData">un objet permettant de récupérer les données statiques du jeu</param>
public Match(IStaticDataGetter staticData)
{
ArgumentNullException.ThrowIfNull(staticData);
_board = staticData.GetBoard(1);
_buildings = staticData.GetBuildings();
_objectives = staticData.GetObjectives();
}
/// <summary> Ajouter un nouveau joueur a la partie </summary>
/// <param name="playerName">le nom du joueur</param>
public void AddPlayer(string playerName)
{
if (_players.Count < _maxPlayerCount)
{
if (_players.Any(p => p.PlayerName == playerName))
{
throw new MatchConfigException("Un joueur existe déjà avec ce nom");
}
_players.Add(new PlayerZone()
{
PlayerName = playerName
});
}
else
{
throw new MatchConfigException("Impossible d'ajouter de nouveau joueur, la partie est pleine");
}
}
/// <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()
{
int nbPlayer = _players.Count;
ArgumentOutOfRangeException.ThrowIfLessThan(nbPlayer, _minPlayerCount);
ArgumentOutOfRangeException.ThrowIfGreaterThan(nbPlayer, _maxPlayerCount);
List<int> freeObjectiveIndexs = Enumerable.Range(0, _objectives.Count).ToList();
foreach (PlayerZone zone in _players)
{
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);
}
_maxWorkerPerPlayer = nbPlayer switch
{
2 => 5,
3 => 4,
4 => 3,
_ => throw new MatchConfigException("Mauvais nombre de joueurs lors Workers")
};
_maxBuidingPerPlayer = nbPlayer switch
{
2 => 7,
3 => 6,
4 => 6,
_ => throw new MatchConfigException("Mauvais nombre de joueurs lors building")
};
// preparer l'ordre des joueurs
int index = _random.Next(nbPlayer);
for (int i = 0; i < nbPlayer; ++i)
{
_playerTurnsOrder.Add(index++);
if (index >= nbPlayer)
index = 0;
}
_currentPlayerIndex = 0;
}
/// <summary> Permet de récuperer une player zone(une copie) </summary>
/// <param name="playerName">le nom ou ID du joueur</param>
/// <returns></returns>
public PlayerZone GetPlayerZone(string playerName)
{
var value = _players.Where(p => p.PlayerName == playerName).FirstOrDefault();
if (null == value)
throw new ArgumentException("playerID is out of bound");
return value.Clone() as PlayerZone ?? throw new ArgumentException("Cast exception in GetPlayerZone"); ;
}
private List<Objective> GetRandomObjectives(int number, List<int> freeIndex)
{
List<Objective> result = new List<Objective>();
for (int i = 0; i < number; i++)
{
int randomIndex = _random.Next(freeIndex.Count);
int cardIndex = freeIndex[randomIndex];
freeIndex.RemoveAt(randomIndex);
result.Add(_objectives.ElementAt(randomIndex));
}
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

@@ -0,0 +1,18 @@
namespace LittleTown.Core;
/// <summary>
/// Représente une carte objectif dans le jeu, les objectif sont des conditions qui une fois remplie accordent des points au joueur
/// </summary>
public class Objective
{
/// <summary> la description, une clé pour la traduction </summary>
public required string Description { get; init; }
/// <summary> la condition de l'objectif sous forme de formule </summary>
public string Formula { get; init; } = string.Empty;
/// <summary> le nombre de points que procure cet objectif </summary>
public int Points { get; init; }
/// <summary> indique si l'objectif a deja été atteint ou non, un objectif ne peut etre atteint qu'une fois </summary>
public bool Filled { get; init; }
}

View File

@@ -0,0 +1,59 @@
using LittleTown.Core.Enums;
namespace LittleTown.Core;
/// <summary> Représente les données propre à un joueur </summary>
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); }
private List<Objective> _objectives = new List<Objective>();
/// <summary> Le marqueur de score pendant le match </summary>
public int ScoreMarker { get; init; }
/// <summary> Permet d'ajouter d'une type de ressources au stock du joueur </summary>
/// <param name="res">le type de ressources</param>
/// <param name="qte">la quantité non nulle non négative</param>
public void AddRessources(ResourceType res, int qte)
{
ArgumentOutOfRangeException.ThrowIfLessThan(qte, 1);
if (Ressources.ContainsKey(res))
{
Ressources[res] += qte;
}
else
{
Ressources.Add(res, qte);
}
}
/// <summary>
/// Assigner des objectifs au joueur
/// </summary>
/// <param name="objectives"></param>
public void AddObjectives(ICollection<Objective> objectives)
{
_objectives.AddRange(objectives);
}
/// <summary> Cloner ce playerZone </summary>
/// <returns>Une copie de l'objet</returns>
public object Clone()
{
PlayerZone result = new PlayerZone()
{
Ressources = new Dictionary<ResourceType, int>(Ressources),
Objectives = new List<Objective>(Objectives),
ScoreMarker = ScoreMarker,
PlayerName = PlayerName
};
return result;
}
}

View File

@@ -0,0 +1,21 @@
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>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateDocumentationFile>true</GenerateDocumentationFile>

View File

@@ -1,30 +0,0 @@
using LittleTown.Core.Ports;
namespace LittleTown.Core;
/// <summary>
/// Represente un match de LittleTown
/// </summary>
public class Match
{
private const int _minPlayerCount = 2;
private const int _maxPlayerCount = 4;
private readonly Board _board;
private ICollection<Building> _buildings;
/// <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(int nbPlayer, IStaticDataGetter staticData)
{
ArgumentNullException.ThrowIfNull(staticData);
ArgumentOutOfRangeException.ThrowIfLessThan(nbPlayer, _minPlayerCount);
ArgumentOutOfRangeException.ThrowIfGreaterThan(nbPlayer, _maxPlayerCount);
_board = staticData.GetBoard(1);
_buildings = staticData.GetBuildings();
}
}

View File

@@ -13,4 +13,9 @@ public interface IStaticDataGetter
/// <summary> Recupérer la liste des batiments et leurs données statiques </summary>
/// <returns></returns>
public ICollection<Building> GetBuildings();
/// <summary> Récupérer la liste des objectifs du jeu </summary>
/// <returns></returns>
public ICollection<Objective> GetObjectives();
}

View File

@@ -0,0 +1,21 @@
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

@@ -0,0 +1,19 @@
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

@@ -0,0 +1,20 @@
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

@@ -0,0 +1,92 @@
[
{
"Description": "desc",
"Formula": "formula",
"Points": 2
},
{
"Description": "desc",
"Formula": "formula",
"Points": 2
},
{
"Description": "desc",
"Formula": "formula",
"Points": 2
},
{
"Description": "desc",
"Formula": "formula",
"Points": 2
},
{
"Description": "desc",
"Formula": "formula",
"Points": 2
},
{
"Description": "desc",
"Formula": "formula",
"Points": 2
},
{
"Description": "desc",
"Formula": "formula",
"Points": 2
},
{
"Description": "desc",
"Formula": "formula",
"Points": 2
},
{
"Description": "desc",
"Formula": "formula",
"Points": 2
},
{
"Description": "desc",
"Formula": "formula",
"Points": 2
},
{
"Description": "desc",
"Formula": "formula",
"Points": 2
},
{
"Description": "desc",
"Formula": "formula",
"Points": 3
},
{
"Description": "desc",
"Formula": "formula",
"Points": 3
},
{
"Description": "desc",
"Formula": "formula",
"Points": 3
},
{
"Description": "desc",
"Formula": "formula",
"Points": 3
},
{
"Description": "desc",
"Formula": "formula",
"Points": 3
},
{
"Description": "desc",
"Formula": "formula",
"Points": 3
},
{
"Description": "desc",
"Formula": "formula",
"Points": 3
}
]

View File

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

View File

@@ -9,24 +9,59 @@ namespace LittleTown.StaticDataAcces;
/// </summary>
public class StaticDataGetter : IStaticDataGetter
{
string _boardData = "";
string _buildingData = "";
string _objectivesData = "";
/// <summary>
/// Constructeur avec les chemin des fichiers de données
/// </summary>
/// <param name="boardData">structure json definissant le plateau</param>
/// <param name="buildingData">structure json definissant les building</param>
/// <param name="objectivesData">structure json definissant les objectifs</param>
public StaticDataGetter(string boardData, string buildingData, string objectivesData)
{
_boardData = boardData;
_objectivesData = objectivesData;
_buildingData = buildingData;
}
/// <summary> Constructeur avec les chemins par défaut, à utiliser pour les tests seulement </summary>
public StaticDataGetter()
{
string boardPath = Path.Combine(Environment.CurrentDirectory, "../../../../LittleTown.StaticDataAccess/Data/Board1.json");
string buildingPath = Path.Combine(Environment.CurrentDirectory, "../../../../LittleTown.StaticDataAccess/Data/Buildings.json");
string objectivesPath = Path.Combine(Environment.CurrentDirectory, "../../../../LittleTown.StaticDataAccess/Data/Objectives.json");
ReadFiles(boardPath, buildingPath, objectivesPath);
}
private void ReadFiles(string boardPath, string buildingPath, string objectivesPath)
{
_boardData = File.ReadAllText(boardPath);
_buildingData = File.ReadAllText(buildingPath);
_objectivesData = File.ReadAllText(objectivesPath);
}
/// <inheritdoc/>
public Board GetBoard(int version)
{
string path = Path.Combine(Environment.CurrentDirectory, "../../../../LittleTown.StaticDataAccess/Data/Board1.json");
string data = File.ReadAllText(path);
Board board = JsonSerializer.Deserialize<Board>(data) ?? throw new JsonException("Cannot deserialize Board");
Board board = JsonSerializer.Deserialize<Board>(_boardData) ?? throw new JsonException("Cannot deserialize Board");
return board;
}
/// <inheritdoc/>
public ICollection<Building> GetBuildings()
{
string path = Path.Combine(Environment.CurrentDirectory, "../../../../LittleTown.StaticDataAccess/Data/Buildings.json");
string data = System.IO.File.ReadAllText(path);
List<Building> buildings = JsonSerializer.Deserialize<List<Building>>(data) ?? throw new JsonException("Cannot deserialize Buildings");
List<Building> buildings = JsonSerializer.Deserialize<List<Building>>(_buildingData) ?? throw new JsonException("Cannot deserialize Buildings");
return buildings;
}
/// <inheritdoc/>
public ICollection<Objective> GetObjectives()
{
List<Objective> objectives = JsonSerializer.Deserialize<List<Objective>>(_objectivesData) ?? throw new JsonException("Cannot deserialize Objectives");
return objectives;
}
}

View File

@@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LittleTown.Core.Tests", "Li
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LittleTown.StaticDataAccess", "LittleTown.StaticDataAccess\LittleTown.StaticDataAccess.csproj", "{FA0DE9D0-F788-4734-BDA3-F89F71D757BA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LittleTown.Api", "LittleTown.Api\LittleTown.Api.csproj", "{87327E52-A393-44C1-8247-EE51753F975F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -30,5 +32,9 @@ Global
{FA0DE9D0-F788-4734-BDA3-F89F71D757BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FA0DE9D0-F788-4734-BDA3-F89F71D757BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FA0DE9D0-F788-4734-BDA3-F89F71D757BA}.Release|Any CPU.Build.0 = Release|Any CPU
{87327E52-A393-44C1-8247-EE51753F975F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{87327E52-A393-44C1-8247-EE51753F975F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{87327E52-A393-44C1-8247-EE51753F975F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{87327E52-A393-44C1-8247-EE51753F975F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal