Compare commits

..

No commits in common. 'main' and 'fix_die_and_faces_structure' have entirely different histories.

@ -9,9 +9,6 @@ trigger:
steps:
- name: build
image: mcr.microsoft.com/dotnet/sdk:6.0
volumes:
- name: docs
path: /docs
commands:
- cd Sources/
- dotnet restore DiceApp.sln
@ -44,25 +41,4 @@ steps:
# accessible en ligne de commande par $${PLUGIN_SONAR_TOKEN}
sonar_token:
from_secret: SECRET_SONAR_LOGIN
depends_on: [tests]
# La documentation Doxygen doit être dans le répertoire
# Documentation/doxygen
# avec le ficher
# Documentation/doxygen/Doxyfile contenant
# OUTPUT_DIRECTORY = /docs/doxygen
- name: generate-and-deploy-docs
image: hub.codefirst.iut.uca.fr/thomas.bellembois/codefirst-docdeployer
volumes:
- name: docs
path: /docs
commands:
- /entrypoint.sh
when:
branch:
- master
depends_on: [ build ]
volumes:
- name: docs
temp: {}
depends_on: [tests]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

File diff suppressed because it is too large Load Diff

@ -1,8 +0,0 @@
<html><body>
<p>
<hr size="1"/><address style="text-align: right;"><small>Generated on $datetime with &nbsp;
<img src="CodeFirst.png" alt="Code#0" align="middle" border="0" height="40px"/>
by Doxygen version $doxygenversion</small></address>
</p>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

@ -24,38 +24,30 @@ The console prototype loads a stub with a few small games that you can test, and
### DiceApp DB context with stub
Still in *Program.cs*, we also now have a nacent data layer, using Entity Framework.
We also now have a budding persistence solution, using Entity Framework.
Open the *DiceAppConsole.sln* solution and navigate to the *App* project. The *Program.cs* file has a `Main()` method that can be launched.
Open the any of our *solutions* and navigate to the *Data* project. The *Program.cs* file has a `Main()` method that can be launched.
The NuGet packages are managed in files that are versioned, so you shouldn't need to manage the dependencies yourself. *"The Line"* is taken care of too.
However, you do need to create the migrations and DB (and you probably should delete them everytime you want to reload).
However, you do need to create the migrations and DB.
First, in Visual Studio's terminal ("Developer PowerShell"), go to *DiceApp/Sources/Data*, and make sure Entity Framework is installed and / or updated.
```
cd Data
dotnet tool install --global dotnet-ef
dotnet tool update --global dotnet-ef
```
Now the migrations and DB. Since we have a `DiceAppDbContext` *and* and `DiceAppDbContextWithStub`, you will need to specify which one to use.
Now the migrations and DB. Since we have a `DbContext` *and* and `DbContextWithStub`, you will need to specify which one to use. Make sure you are in *DiceApp/Sources/Data*.
```
cd Data
dotnet ef migrations add dice_app_db --context DiceAppDbContextWithStub
dotnet ef database update --context DiceAppDbContextWithStub --startup-project ../App
dotnet ef database update --context DiceAppDbContextWithStub
```
Replace `DiceAppDbContextWithStub` with `DiceAppDbContext` if you want to launch an app with an empty DB.
You can now run the *App* program, and check out your local DB.
You can now run the *Data* program, and check out your local DB.
You may not want to read tables in the debug window -- in which case, just download [DB Brower for SQLite](https://sqlitebrowser.org/dl/) and open the *.db* file in it.
Ta-da.
#### Troubleshooting (VS vs .NET EF)
**If Visual Studio's embedded terminal refuses to recognize `dotnet ef`, try to fully close and reopen Visual Studio**
## To contribute (workflow)
We are using the feature branch workflow ([details here](https://www.atlassian.com/git/tutorials/comparing-workflows/feature-branch-workflow), or see the summary below)
@ -100,9 +92,4 @@ On [the repository's main page](https://codefirst.iut.uca.fr/git/alexis.drai/dic
It should then allow you to `merge into: ...:main` and `pull from: ...:new-feature`
Follow the platform's instructions, until you've made a "work in progress" (WIP) pull request. You can now assign reviewers among your colleagues. They will get familiar with your new code -- and will either accept the branch as it is, or help you arrange it.
## Known issues and limitations
### copies of games
As of now, this app does not allow making copies of a game. We're not trying to make a roguelike, it's just not considered to be a priority feature.
Follow the platform's instructions, until you've made a "work in progress" (WIP) pull request. You can now assign reviewers among your colleagues. They will get familiar with your new code -- and will either accept the branch as it is, or help you arrange it.

@ -1,28 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<StartWorkingDirectory>$(MSBuildProjectDirectory)</StartWorkingDirectory>
</PropertyGroup>
<ItemGroup>
<Content Include="NLog.config">
<BuildAction>Content</BuildAction>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.9">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="NLog" Version="5.0.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Data\Data.csproj" />
</ItemGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Data\Data.csproj" />
</ItemGroup>
</Project>

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
throwConfigExceptions="true">
<targets async="true">
<target name="logfile" xsi:type="File" fileName="log.txt" />
<target name="logdebug" xsi:type="Debug" />
</targets>
<rules>
<logger name="*" minlevel="Info" writeTo="logdebug"/>
<logger name="*" minlevel="Warn" writeTo="logfile"/>
</rules>
</nlog>

@ -1,457 +1,300 @@
using Data;
using Data.EF;
using Data.EF.Players;
using Model.Dice;
using Model.Dice.Faces;
using Model.Games;
using Model.Players;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace App
{
internal static class Program
{
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
static async Task Main(string[] args)
{
// MODEL stuff
ILoader loader = new Stub();
MasterOfCeremonies masterOfCeremonies;
try
{
masterOfCeremonies = await loader.LoadApp();
}
catch (Exception ex)
{
logger.Warn(ex);
masterOfCeremonies = new(new PlayerManager(), new DiceGroupManager(), new GameManager());
}
try
{
// DB stuff when the app opens
using (DiceAppDbContext db = new())
{
// Later, we'll use the DiceAppDbContext to get a GameDbRunner
// get all the players from the DB
PlayerDbManager playerDbManager = new(db);
IEnumerable<PlayerEntity> entities = await playerDbManager.GetAll();
foreach (PlayerEntity entity in entities)
{
try
{
// persist them as models !
await masterOfCeremonies.GlobalPlayerManager.Add(entity.ToModel());
}
catch (Exception ex) { Debug.WriteLine($"{ex.Message}\n... Never mind"); }
}
}
}
catch (Exception ex) { Console.WriteLine($"{ex.Message}\n... Couldn't use the database"); }
string menuChoice = "nothing";
while (menuChoice != "q")
{
Console.WriteLine(
"l... load a game\n" +
"n... start new game\n" +
"d... delete a game\n" +
"i... see all dice\n" +
"c... create a group of dice\n" +
"p... see all players\n" +
"y... create players\n" +
"q... QUIT\n" +
">"
);
menuChoice = Console.ReadLine();
switch (menuChoice)
{
case "q":
break;
case "l":
string loadName = await ChooseGame(masterOfCeremonies);
if (masterOfCeremonies.GameManager.GetOneByName(loadName) != null)
{
await Play(masterOfCeremonies, loadName);
}
break;
case "n":
if (!(await masterOfCeremonies.DiceGroupManager.GetAll()).Any())
{
Console.WriteLine("make at least one dice group first, then try again");
break;
}
Console.WriteLine("add dice to the game");
IEnumerable<Die> newGameDice = await PrepareDice(masterOfCeremonies);
string newGameName;
Console.WriteLine("give this new game a name\n>");
newGameName = Console.ReadLine();
Console.WriteLine("add players to the game");
PlayerManager playerManager = await PreparePlayers(masterOfCeremonies);
await masterOfCeremonies.StartNewGame(newGameName, playerManager, newGameDice);
await Play(masterOfCeremonies, newGameName);
break;
case "d":
string deleteName = await ChooseGame(masterOfCeremonies);
masterOfCeremonies.GameManager.Remove(await masterOfCeremonies.GameManager.GetOneByName(deleteName));
break;
case "c":
string newGroupName;
Console.WriteLine("give this new dice group a name");
newGroupName = Console.ReadLine();
List<Die> newGroupDice = new();
string menuChoiceNewDice = "";
while (!(menuChoiceNewDice.Equals("ok") && newGroupDice.Any()))
{
Die die = null;
Console.WriteLine("create a die you want to add (at least one), or enter 'ok' if you're finished");
Console.WriteLine("what type of die ?\n" +
"n... number\n" +
"c... color\n" +
"i... image");
menuChoiceNewDice = Console.ReadLine();
switch (menuChoiceNewDice)
{
case "n":
die = MakeNumberDie();
break;
case "c":
die = MakeColorDie();
break;
case "i":
die = MakeImageDie();
break;
}
// almost no checks, this is temporary
if (die is not null)
{
newGroupDice.Add(die);
}
}
await masterOfCeremonies.DiceGroupManager.Add(new DiceGroup(newGroupName, newGroupDice));
break;
case "p":
await ShowPlayers(masterOfCeremonies);
break;
case "i":
await ShowDice(masterOfCeremonies);
break;
case "y":
await PreparePlayers(masterOfCeremonies);
break;
default:
Console.WriteLine("u wot m8?");
break;
}
}
try
{
// DB stuff when the app closes
using (DiceAppDbContext db = new())
{
// get all the players from the app's memory
IEnumerable<Player> models = await masterOfCeremonies.GlobalPlayerManager.GetAll();
// create a PlayerDbManager (and inject it with the DB)
PlayerDbManager playerDbManager = new(db);
foreach (Player model in models)
{
try // to persist them
{ // as entities !
PlayerEntity entity = model.ToEntity();
await playerDbManager.Add(entity);
}
// what if there's already a player with that name? Exception (see PlayerEntity's annotations)
catch (ArgumentException ex) { Debug.WriteLine($"{ex.Message}\n... Never mind"); }
}
}
// flushing and closing NLog before quitting completely
NLog.LogManager.Shutdown();
}
catch (Exception ex) { Console.WriteLine($"{ex.Message}\n... Couldn't use the database"); }
}
private static async Task Play(MasterOfCeremonies masterOfCeremonies, string name)
{
string menuChoicePlay = "";
while (menuChoicePlay != "q")
{
Game game = await masterOfCeremonies.GameManager.GetOneByName(name);
Console.WriteLine($"{PlayerToString(await game.GetWhoPlaysNow())}'s turn\n" +
"q... quit\n" +
"h... show history\n" +
"s... save\n" +
"any other... throw");
menuChoicePlay = Console.ReadLine();
switch (menuChoicePlay)
{
case "q":
break;
case "h":
foreach (Turn turn in game.GetHistory()) { Console.WriteLine(TurnToString(turn)); }
break;
case "s":
await masterOfCeremonies.GameManager.Add(game);
break;
default:
await MasterOfCeremonies.PlayGame(game);
Console.WriteLine(TurnToString(game.GetHistory().Last()));
break;
}
}
}
private static async Task<string> ChooseGame(MasterOfCeremonies masterOfCeremonies)
{
string name;
Console.WriteLine("which of these games?\n(choose by name)\n>");
foreach (Game game in await masterOfCeremonies.GameManager.GetAll())
{
Console.WriteLine(GameToString(game));
}
name = Console.ReadLine();
return name;
}
private static async Task ShowPlayers(MasterOfCeremonies masterOfCeremonies)
{
Console.WriteLine("Look at all them players!");
foreach (Player player in await masterOfCeremonies.GlobalPlayerManager.GetAll())
{
Console.WriteLine(PlayerToString(player));
}
}
private static async Task ShowDice(MasterOfCeremonies masterOfCeremonies)
{
foreach ((string name, ReadOnlyCollection<Die> dice) in await masterOfCeremonies.DiceGroupManager.GetAll())
{
Console.WriteLine($"{name} -- {dice}"); // maybe code a quick and dirty DieToString()
}
}
private static NumberDie MakeNumberDie()
{
NumberDie die;
List<NumberFace> faces = new();
string menuChoiceNewFaces = "";
while (menuChoiceNewFaces != "ok")
{
Console.WriteLine("create a face with a number, or enter 'ok' if you're finished");
menuChoiceNewFaces = Console.ReadLine();
PreventEmptyDieCreation(ref menuChoiceNewFaces, faces.Count);
if (!menuChoiceNewFaces.Equals("ok") && int.TryParse(menuChoiceNewFaces, out int num))
{
faces.Add(new(num));
}
}
NumberFace[] facesArr = faces.ToArray();
die = new NumberDie(facesArr[0], facesArr[1..]);
return die;
}
private static ColorDie MakeColorDie()
{
ColorDie die;
List<ColorFace> faces = new();
string menuChoiceNewFaces = "";
while (!menuChoiceNewFaces.Equals("ok"))
{
Console.WriteLine("create a face with an color name, or enter 'ok' if you're finished");
menuChoiceNewFaces = Console.ReadLine();
PreventEmptyDieCreation(ref menuChoiceNewFaces, faces.Count);
if (menuChoiceNewFaces != "ok") faces.Add(new(Color.FromName(menuChoiceNewFaces)));
}
ColorFace[] facesArr = faces.ToArray();
die = new ColorDie(facesArr[0], facesArr[1..]);
return die;
}
private static ImageDie MakeImageDie()
{
ImageDie die;
List<ImageFace> faces = new();
string menuChoiceNewFaces = "";
while (!menuChoiceNewFaces.Equals("ok"))
{
Console.WriteLine("create a face with an image uri, or enter 'ok' if you're finished");
menuChoiceNewFaces = Console.ReadLine();
PreventEmptyDieCreation(ref menuChoiceNewFaces, faces.Count);
if (menuChoiceNewFaces != "ok")
{
try
{
faces.Add(new(new Uri(menuChoiceNewFaces)));
}
catch (ArgumentNullException ex)
{
Console.WriteLine(ex.Message);
logger.Warn(ex);
}
catch (UriFormatException ex)
{
Console.WriteLine("that URI was not valid");
Console.WriteLine(ex.Message);
logger.Warn(ex);
}
}
}
ImageFace[] facesArr = faces.ToArray();
die = new ImageDie(facesArr[0], facesArr[1..]);
return die;
}
private static void PreventEmptyDieCreation(ref string menuChoice, int count)
{
if (menuChoice.Equals("ok") && count == 0)
{
Console.WriteLine("create at least one valid face");
menuChoice = ""; // persists outside the scope of this function
}
}
private async static Task<IEnumerable<Die>> PrepareDice(MasterOfCeremonies masterOfCeremonies)
{
List<Die> result = new();
Console.WriteLine("all known dice or groups of dice:");
await ShowDice(masterOfCeremonies);
string menuChoiceDice = "";
while (!(menuChoiceDice.Equals("ok") && result.Any()))
{
Console.WriteLine("write the name of a dice group you want to add (at least one), or 'ok' if you're finished");
menuChoiceDice = Console.ReadLine();
if (!menuChoiceDice.Equals("ok"))
{
IEnumerable<Die> chosenDice = (await masterOfCeremonies.DiceGroupManager.GetOneByName(menuChoiceDice)).Dice;
foreach (Die die in chosenDice)
{
result.Add(die);
}
}
}
return result.AsEnumerable();
}
private async static Task<PlayerManager> PreparePlayers(MasterOfCeremonies masterOfCeremonies)
{
PlayerManager result = new();
Console.WriteLine("all known players:");
await ShowPlayers(masterOfCeremonies);
string menuChoicePlayers = "";
while (!(menuChoicePlayers.Equals("ok") && (await result.GetAll()).Any()))
{
Console.WriteLine("write the name of a player you want to add (at least one), or 'ok' if you're finished");
menuChoicePlayers = Console.ReadLine();
if (!menuChoicePlayers.Equals("ok"))
{
Player player = new(menuChoicePlayers);
if (!(await masterOfCeremonies.GlobalPlayerManager.GetAll()).Contains(player))
{
// if the player didn't exist, now it does...
await masterOfCeremonies.GlobalPlayerManager.Add(player);
}
// almost no checks, this is temporary
try
{
await result.Add(player);
}
catch (ArgumentException ex) { Console.WriteLine($"{ex.Message}\n... Never mind"); }
}
}
return result;
}
private static string TurnToString(Turn turn)
{
string[] datetime = turn.When.ToString("s", System.Globalization.CultureInfo.InvariantCulture).Split("T");
string date = datetime[0];
string time = datetime[1];
StringBuilder sb = new();
sb.AppendFormat("{0} {1} -- {2} rolled:",
date,
time,
PlayerToString(turn.Player));
foreach (KeyValuePair<Die, Face> kvp in turn.DiceNFaces)
{
sb.Append(" " + kvp.Value.StringValue);
}
return sb.ToString();
}
private async static Task<string> GameToString(Game game)
{
StringBuilder sb = new();
sb.Append($"Game: {game.Name}");
sb.Append("\nPlayers:");
foreach (Player player in game.PlayerManager.GetAll()?.Result)
{
sb.Append($" {PlayerToString(player)}");
}
sb.Append($"\nNext: {PlayerToString(await game.GetWhoPlaysNow())}");
sb.Append("\nLog:\n");
foreach (Turn turn in game.GetHistory())
{
sb.Append($"\t{TurnToString(turn)}\n");
}
return sb.ToString();
}
private static string PlayerToString(Player player)
{
return player.Name;
}
}
using Model.Dice;
using Model.Dice.Faces;
using Model.Games;
using Model.Players;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using Data;
namespace App
{
internal static class Program
{
static void Main(string[] args)
{
ILoader loader = new Stub();
GameRunner gameRunner;
try
{
gameRunner = loader.LoadApp();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
gameRunner = new(new PlayerManager(), new DieManager(), null);
}
string menuChoice = "nothing";
while (menuChoice != "q")
{
Console.WriteLine(
"l... load a game\n" +
"n... start new game\n" +
"d... delete a game\n" +
"c... create a group of dice\n" +
"q... QUIT\n" +
">"
);
menuChoice = Console.ReadLine();
switch (menuChoice)
{
case "q":
break;
case "l":
string loadName = ChooseGame(gameRunner);
if (gameRunner.GetOneByName(loadName) != null)
{
Play(gameRunner, loadName);
}
break;
case "n":
if (!gameRunner.GlobalDieManager.GetAll().Any())
{
Console.WriteLine("make at least one dice group first, then try again");
break;
}
IEnumerable<Die> newGameDice = PrepareDice(gameRunner);
string newGameName;
Console.WriteLine("give this new game a name\n>");
newGameName = Console.ReadLine();
PlayerManager playerManager = PreparePlayers(gameRunner);
gameRunner.StartNewGame(newGameName, playerManager, newGameDice);
Play(gameRunner, newGameName);
break;
case "d":
string deleteName = ChooseGame(gameRunner);
gameRunner.Remove(gameRunner.GetOneByName(deleteName));
break;
case "c":
string newGroupName;
Console.WriteLine("give this new dice group a name");
newGroupName = Console.ReadLine();
List<Die> newGroupDice = new();
string menuChoiceNewDice = "";
while (!(menuChoiceNewDice.Equals("ok") && newGroupDice.Any()))
{
Die die = null;
Console.WriteLine("create a die you want to add (at least one), or enter 'ok' if you're finished");
Console.WriteLine("what type of die ?\n" +
"n... number\n" +
"c... color\n" +
"i... image");
menuChoiceNewDice = Console.ReadLine();
switch (menuChoiceNewDice)
{
case "n":
die = MakeNumberDie();
break;
case "c":
die = MakeColorDie();
break;
case "i":
die = MakeImageDie();
break;
}
// almost no checks, this is temporary
if (die is not null)
{
newGroupDice.Add(die);
}
}
gameRunner.GlobalDieManager.Add(new KeyValuePair<string, IEnumerable<Die>>(newGroupName, newGroupDice));
break;
default:
Console.WriteLine("u wot m8?");
break;
}
}
}
private static void Play(GameRunner gameRunner, string name)
{
string menuChoicePlay = "";
while (menuChoicePlay != "q")
{
Game game = gameRunner.GetOneByName(name);
Console.WriteLine($"{game.GetWhoPlaysNow()}'s turn\n" +
"q... quit\n" +
"h... show history\n" +
"s... save\n" +
"any other... throw");
menuChoicePlay = Console.ReadLine();
switch (menuChoicePlay)
{
case "q":
break;
case "h":
foreach (Turn turn in game.GetHistory())
{
Console.WriteLine(turn);
}
break;
case "s":
gameRunner.Add(game);
break;
default:
GameRunner.PlayGame(game);
Console.WriteLine(game.GetHistory().Last());
break;
}
}
}
private static string ChooseGame(GameRunner gameRunner)
{
string name;
Console.WriteLine("which of these games?\n(choose by name)\n>");
foreach (Game game in gameRunner.GetAll())
{
Console.WriteLine(game);
}
name = Console.ReadLine();
return name;
}
private static NumberDie MakeNumberDie()
{
NumberDie die;
List<NumberFace> faces = new();
string menuChoiceNewFaces = "";
while (menuChoiceNewFaces != "ok")
{
Console.WriteLine("create a face with a number, or enter 'ok' if you're finished");
menuChoiceNewFaces = Console.ReadLine();
if (!menuChoiceNewFaces.Equals("ok") && int.TryParse(menuChoiceNewFaces, out int num))
{
faces.Add(new(num));
}
}
die = new NumberDie(faces.ToArray());
return die;
}
private static ColorDie MakeColorDie()
{
ColorDie die;
List<ColorFace> faces = new();
string menuChoiceNewFaces = "";
while (!menuChoiceNewFaces.Equals("ok"))
{
Console.WriteLine("create a face with an color name, or enter 'ok' if you're finished");
menuChoiceNewFaces = Console.ReadLine();
if (menuChoiceNewFaces != "ok") faces.Add(new(Color.FromName(menuChoiceNewFaces)));
}
die = new ColorDie(faces.ToArray());
return die;
}
private static ImageDie MakeImageDie()
{
ImageDie die;
List<ImageFace> faces = new();
string menuChoiceNewFaces = "";
while (!menuChoiceNewFaces.Equals("ok"))
{
Console.WriteLine("create a face with an image uri, or enter 'ok' if you're finished");
menuChoiceNewFaces = Console.ReadLine();
if (menuChoiceNewFaces != "ok")
{
try
{
faces.Add(new(new Uri(menuChoiceNewFaces)));
}
catch (ArgumentNullException ex)
{
Console.WriteLine(ex.Message);
}
catch (UriFormatException ex)
{
Console.WriteLine("that URI was not valid");
Console.WriteLine(ex.Message);
}
}
}
die = new ImageDie(faces.ToArray());
return die;
}
private static IEnumerable<Die> PrepareDice(GameRunner gameRunner)
{
List<Die> result = new();
Console.WriteLine("add dice to the game");
Console.WriteLine("all known dice or groups of dice:");
foreach ((string name, IEnumerable<Die> dice) in gameRunner.GlobalDieManager.GetAll())
{
Console.WriteLine($"{name} -- {dice}");
}
string menuChoiceDice = "";
while (!(menuChoiceDice.Equals("ok") && result.Any()))
{
Console.WriteLine("write the name of a dice group you want to add (at least one), or 'ok' if you're finished");
menuChoiceDice = Console.ReadLine();
// no checks, this is temporary
if (!menuChoiceDice.Equals("ok"))
{
IEnumerable<Die> chosenDice = gameRunner.GlobalDieManager.GetOneByName(menuChoiceDice).Value;
foreach (Die die in chosenDice)
{
result.Add(die);
}
}
}
return result.AsEnumerable();
}
private static PlayerManager PreparePlayers(GameRunner gameRunner)
{
PlayerManager result = new();
Console.WriteLine("add players to the game");
Console.WriteLine("all known players:");
foreach (Player player in gameRunner.GlobalPlayerManager.GetAll())
{
Console.WriteLine(player);
}
string menuChoicePlayers = "";
while (!(menuChoicePlayers.Equals("ok") && result.GetAll().Any()))
{
Console.WriteLine("write the name of a player you want to add (at least one), or 'ok' if you're finished");
menuChoicePlayers = Console.ReadLine();
if (!menuChoicePlayers.Equals("ok"))
{
Player player = new(menuChoicePlayers);
if (!gameRunner.GlobalPlayerManager.GetAll().Contains(player))
{
// if the player didn't exist, now it does... this is temporary
gameRunner.GlobalPlayerManager.Add(player);
}
// almost no checks, this is temporary
result.Add(player);
}
}
return result;
}
}
}

@ -1,8 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<StartWorkingDirectory>$(MSBuildProjectDirectory)</StartWorkingDirectory>
</PropertyGroup>
@ -13,12 +15,10 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="NLog" Version="5.0.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Model\Model.csproj" />
<ProjectReference Include="..\Utils\Utils\Utils.csproj" />
</ItemGroup>
</Project>

@ -1,9 +0,0 @@
using Data.EF.Dice.Faces;
namespace Data.EF.Dice
{
public class ColorDieEntity : DieEntity
{
public new ICollection<ColorFaceEntity> Faces { get; set; } = new List<ColorFaceEntity>();
}
}

@ -1,35 +0,0 @@
using Data.EF.Dice.Faces;
using Model.Dice;
using Model.Dice.Faces;
namespace Data.EF.Dice
{
public static class ColorDieExtensions
{
public static ColorDie ToModel(this ColorDieEntity dieEntity)
{
/*
* creating an array of faces model
*/
ColorFace[] faces = dieEntity.Faces.ToModels().ToArray();
/*
* creating the die
*/
ColorDie die = new(faces[0], faces[1..]);
return die;
}
public static IEnumerable<ColorDie> ToModels(this IEnumerable<ColorDieEntity> entities) => entities.Select(entity => entity.ToModel());
public static ColorDieEntity ToEntity(this ColorDie model)
{
var entity = new ColorDieEntity();
foreach (var face in model.Faces) { entity.Faces.Add(((ColorFace)face).ToEntity()); }
return entity;
}
public static IEnumerable<ColorDieEntity> ToEntities(this IEnumerable<ColorDie> models) => models.Select(model => model.ToEntity());
}
}

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Data.EF.Dice
{
public class DiceGroupDbManager
{
}
}

@ -1,32 +0,0 @@
using Data.EF.Dice.Faces;
using Data.EF.Games;
using Data.EF.Joins;
using System.Diagnostics.CodeAnalysis;
namespace Data.EF.Dice
{
/// <summary>
/// not designed to be instantiated, but not abstract in order to allow extensions
/// </summary>
///
public class DieEntity : IEqualityComparer<DieEntity>
{
public Guid ID { get; set; }
public ICollection<FaceEntity> Faces { get; set; } = new List<FaceEntity>(); // one to many
public ICollection<TurnEntity> Turns { get; set; } = new List<TurnEntity>(); // many to many
public List<DieTurn> DieTurns { get; set; } = new();
public bool Equals(DieEntity x, DieEntity y)
{
return x is not null
&& y is not null
&& x.ID.Equals(y.ID)
&& x.Faces.Equals(y.Faces);
}
public int GetHashCode([DisallowNull] DieEntity obj)
{
return HashCode.Combine(ID, Faces);
}
}
}

@ -1,23 +0,0 @@
using System.Drawing;
namespace Data.EF.Dice.Faces
{
public class ColorFaceEntity : FaceEntity
{
public byte A { get; set; }
public byte R { get; set; }
public byte G { get; set; }
public byte B { get; set; }
public Guid ColorDieEntityID { get; set; }
public ColorDieEntity ColorDieEntity { get; set; }
public void SetValue(Color c)
{
A = c.A;
R = c.R;
G = c.G;
B = c.B;
}
}
}

@ -1,21 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Model.Dice.Faces;
using System.Drawing;
namespace Data.EF.Dice.Faces
{
public static class ColorFaceExtensions
{
public static ColorFace ToModel(this ColorFaceEntity clrFaceEntity) => new(Color.FromArgb(clrFaceEntity.A, clrFaceEntity.R, clrFaceEntity.G, clrFaceEntity.B));
public static IEnumerable<ColorFace> ToModels(this IEnumerable<ColorFaceEntity> entities) => entities.Select(entity => entity.ToModel());
public static ColorFaceEntity ToEntity(this ColorFace model) => new() { A = model.Value.A, R = model.Value.R, G = model.Value.G, B = model.Value.B };
public static IEnumerable<ColorFaceEntity> ToEntities(this IEnumerable<ColorFace> models) => models.Select(model => model.ToEntity());
}
}

@ -1,28 +0,0 @@
using Data.EF.Games;
using Data.EF.Joins;
using System.Diagnostics.CodeAnalysis;
namespace Data.EF.Dice.Faces
{
/// <summary>
/// not designed to be instantiated, but not abstract in order to allow extensions
/// </summary>
public class FaceEntity : IEqualityComparer<FaceEntity>
{
public Guid ID { get; set; }
public ICollection<TurnEntity> Turns { get; set; } // many to many
public List<FaceTurn> FaceTurns { get; set; }
public bool Equals(FaceEntity x, FaceEntity y)
{
return x is not null
&& y is not null
&& x.ID.Equals(y.ID);
}
public int GetHashCode([DisallowNull] FaceEntity obj)
{
return ID.GetHashCode();
}
}
}

@ -1,9 +0,0 @@
namespace Data.EF.Dice.Faces
{
public class ImageFaceEntity : FaceEntity
{
public string Value { get; set; }
public Guid ImageDieEntityID { get; set; }
public ImageDieEntity ImageDieEntity { get; set; }
}
}

@ -1,22 +0,0 @@
using Data.EF.Players;
using Model.Dice.Faces;
using Model.Players;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Data.EF.Dice.Faces
{
public static class ImageFaceExtensions
{
public static ImageFace ToModel(this ImageFaceEntity entity) => new(new Uri(entity.Value));
public static IEnumerable<ImageFace> ToModels(this IEnumerable<ImageFaceEntity> entities) => entities.Select(entity => entity.ToModel());
public static ImageFaceEntity ToEntity(this ImageFace model) => new() { Value = model.StringValue };
public static IEnumerable<ImageFaceEntity> ToEntities(this IEnumerable<ImageFace> models) => models.Select(model => model.ToEntity());
}
}

@ -1,9 +0,0 @@
namespace Data.EF.Dice.Faces
{
public class NumberFaceEntity : FaceEntity
{
public int Value { get; set; }
public Guid NumberDieEntityID { get; set; }
public NumberDieEntity NumberDieEntity { get; set; }
}
}

@ -1,20 +0,0 @@
using Model.Dice.Faces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Data.EF.Dice.Faces
{
public static class NumberFaceExtensions
{
public static NumberFace ToModel(this NumberFaceEntity entity) => new(entity.Value);
public static IEnumerable<NumberFace> ToModels(this IEnumerable<NumberFaceEntity> entities) => entities.Select(entity => entity.ToModel());
public static NumberFaceEntity ToEntity(this NumberFace model) => new() { Value = model.Value };
public static IEnumerable<NumberFaceEntity> ToEntities(this IEnumerable<NumberFace> models) => models.Select(model => model.ToEntity());
}
}

@ -1,9 +0,0 @@
using Data.EF.Dice.Faces;
namespace Data.EF.Dice
{
public class ImageDieEntity : DieEntity
{
public new ICollection<ImageFaceEntity> Faces { get; set; } = new List<ImageFaceEntity>();
}
}

@ -1,35 +0,0 @@
using Data.EF.Dice.Faces;
using Model.Dice;
using Model.Dice.Faces;
namespace Data.EF.Dice
{
public static class ImageDieExtensions
{
public static ImageDie ToModel(this ImageDieEntity dieEntity)
{
/*
* creating an array of faces model
*/
ImageFace[] faces = dieEntity.Faces.ToModels().ToArray();
/*
* creating the die
*/
ImageDie die = new(faces[0], faces[1..]);
return die;
}
public static IEnumerable<ImageDie> ToModels(this IEnumerable<ImageDieEntity> entities) => entities.Select(entity => entity.ToModel());
public static ImageDieEntity ToEntity(this ImageDie model)
{
var entity = new ImageDieEntity();
foreach (var face in model.Faces) { entity.Faces.Add(((ImageFace)face).ToEntity()); }
return entity;
}
public static IEnumerable<ImageDieEntity> ToEntities(this IEnumerable<ImageDie> models) => models.Select(model => model.ToEntity());
}
}

@ -1,9 +0,0 @@
using Data.EF.Dice.Faces;
namespace Data.EF.Dice
{
public class NumberDieEntity : DieEntity
{
public new ICollection<NumberFaceEntity> Faces { get; set; } = new List<NumberFaceEntity>();
}
}

@ -1,35 +0,0 @@
using Data.EF.Dice.Faces;
using Model.Dice;
using Model.Dice.Faces;
namespace Data.EF.Dice
{
public static class NumberDieExtensions
{
public static NumberDie ToModel(this NumberDieEntity dieEntity)
{
/*
* creating an array of faces model
*/
NumberFace[] faces = dieEntity.Faces.ToModels().ToArray();
/*
* creating the die
*/
NumberDie die = new(faces[0], faces[1..]);
return die;
}
public static IEnumerable<NumberDie> ToModels(this IEnumerable<NumberDieEntity> entities) => entities.Select(entity => ToModel(entity));
public static NumberDieEntity ToEntity(this NumberDie model)
{
var entity = new NumberDieEntity();
foreach (var face in model.Faces) { entity.Faces.Add(((NumberFace)face).ToEntity()); }
return entity;
}
public static IEnumerable<NumberDieEntity> ToEntities(this IEnumerable<NumberDie> models) => models.Select(model => model.ToEntity());
}
}

@ -1,82 +1,19 @@
using Data.EF.Dice;
using Data.EF.Dice.Faces;
using Data.EF.Games;
using Data.EF.Joins;
using Data.EF.Players;
using Data.EF.Players;
using Microsoft.EntityFrameworkCore;
using Model.Games;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Data.EF
{
public class DiceAppDbContext : DbContext, ILoader
public class DiceAppDbContext : DbContext
{
// will be async!
public virtual Task<MasterOfCeremonies> LoadApp() { throw new NotImplementedException(); }
public DbSet<PlayerEntity> PlayerEntity { get; set; }
public DbSet<TurnEntity> TurnEntity { get; set; }
public DbSet<NumberDieEntity> NumberDieEntity { get; set; }
public DbSet<NumberFaceEntity> NumberFaceEntity { get; set; }
public DbSet<ImageDieEntity> ImageDieEntity { get; set; }
public DbSet<ImageFaceEntity> ImageFaceEntity { get; set; }
public DbSet<ColorDieEntity> ColorDieEntity { get; set; }
public DbSet<ColorFaceEntity> ColorFaceEntity { get; set; }
public DiceAppDbContext() { }
public DiceAppDbContext(DbContextOptions<DiceAppDbContext> options)
: base(options) { }
public DbSet<PlayerEntity>? Players { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured) optionsBuilder.UseSqlite("Data Source=EFDice.DiceApp.db").EnableSensitiveDataLogging();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// thanks to https://learn.microsoft.com/en-us/ef/core/modeling/relationships?tabs=fluent-api%2Cfluent-api-simple-key%2Csimple-key#join-entity-type-configuration
// many to many TurnEntity <-> FaceEntity
modelBuilder.Entity<FaceEntity>()
.HasMany(face => face.Turns)
.WithMany(turn => turn.Faces)
.UsingEntity<FaceTurn>(
join => join
// FaceTurn --> TurnEntity
.HasOne(faceturn => faceturn.TurnEntity)
.WithMany(turn => turn.FaceTurns)
.HasForeignKey(faceturn => faceturn.TurnEntityID),
join => join
// FaceTurn --> FaceEntity
.HasOne(faceturn => faceturn.FaceEntity)
.WithMany(face => face.FaceTurns)
.HasForeignKey(faceturn => faceturn.FaceEntityID),
// FaceTurn.PK = (ID1, ID2)
join => join.HasKey(faceturn => new { faceturn.FaceEntityID, faceturn.TurnEntityID })
);
// many to many TurnEntity <-> DieEntity
modelBuilder.Entity<DieEntity>()
.HasMany(die => die.Turns)
.WithMany(turn => turn.Dice)
.UsingEntity<DieTurn>(
join => join
// DieTurn --> TurnEntity
.HasOne(dieturn => dieturn.TurnEntity)
.WithMany(turn => turn.DieTurns)
.HasForeignKey(dieturn => dieturn.TurnEntityID),
join => join
// DieTurn --> DieEntity
.HasOne(dieturn => dieturn.DieEntity)
.WithMany(die => die.DieTurns)
.HasForeignKey(dieturn => dieturn.DieEntityID),
// DieTurn.PK = (ID1, ID2)
join => join.HasKey(dieturn => new { dieturn.DieEntityID, dieturn.TurnEntityID })
=> optionsBuilder.UseSqlite("Data Source=EFDice.DiceApp.db");
);
}
}
}

@ -1,112 +1,25 @@
using Data.EF.Dice;
using Data.EF.Dice.Faces;
using Data.EF.Games;
using Data.EF.Joins;
using Data.EF.Players;
using Data.EF.Players;
using Microsoft.EntityFrameworkCore;
using Model.Games;
using System.Drawing;
using System.Linq.Expressions;
using System.Security.Cryptography.X509Certificates;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Data.EF
{
public class DiceAppDbContextWithStub : DiceAppDbContext
{
// will be async
public override Task<MasterOfCeremonies> LoadApp() { throw new NotImplementedException(); }
public DiceAppDbContextWithStub() { }
public DiceAppDbContextWithStub(DbContextOptions<DiceAppDbContext> options)
: base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
Guid playerID_1 = Guid.NewGuid();
Guid playerID_2 = new("6e856818-92f1-4d7d-b35c-f9c6687ef8e1");
Guid playerID_3 = Guid.NewGuid();
Guid playerID_4 = Guid.NewGuid();
PlayerEntity player_1 = new() { ID = playerID_1, Name = "Alice" };
PlayerEntity player_2 = new() { ID = playerID_2, Name = "Bob" };
PlayerEntity player_3 = new() { ID = playerID_3, Name = "Clyde" };
PlayerEntity player_4 = new() { ID = playerID_4, Name = "Dahlia" };
Guid turnID_1 = Guid.NewGuid();
Guid turnID_2 = Guid.NewGuid();
DateTime datetime_1 = new(2017, 1, 6, 17, 30, 0, DateTimeKind.Utc);
TurnEntity turn_1 = new() { ID = turnID_1, When = datetime_1, PlayerEntityID = playerID_1 };
TurnEntity turn_2 = new() { ID = turnID_2, When = DateTime.UtcNow, PlayerEntityID = playerID_2 };
Guid dieID_1 = Guid.NewGuid();
Guid dieID_2 = Guid.NewGuid();
Guid dieID_3 = Guid.NewGuid();
NumberDieEntity die_1 = new() { ID = dieID_1 };
ImageDieEntity die_2 = new() { ID = dieID_2 };
ColorDieEntity die_3 = new() { ID = dieID_3 };
Guid faceID_1 = Guid.NewGuid();
Guid faceID_2 = Guid.NewGuid();
Guid faceID_3 = Guid.NewGuid();
Guid faceID_4 = Guid.NewGuid();
Guid faceID_5 = Guid.NewGuid();
Guid faceID_6 = Guid.NewGuid();
NumberFaceEntity face_1 = new() { ID = faceID_1, Value = 1, NumberDieEntityID = dieID_1 };
NumberFaceEntity face_2 = new() { ID = faceID_2, Value = 2, NumberDieEntityID = dieID_1 };
ImageFaceEntity face_3 = new() { ID = faceID_3, Value = "https://1", ImageDieEntityID = dieID_2 };
ImageFaceEntity face_4 = new() { ID = faceID_4, Value = "https://2", ImageDieEntityID = dieID_2 };
ColorFaceEntity face_5 = new() { ID = faceID_5, ColorDieEntityID = dieID_3 };
face_5.SetValue(Color.FromArgb(255, 255, 0, 0));
ColorFaceEntity face_6 = new() { ID = faceID_6, ColorDieEntityID = dieID_3 };
face_6.SetValue(Color.FromName("green"));
modelBuilder.Entity<PlayerEntity>().HasData(player_1, player_2, player_3, player_4);
modelBuilder.Entity<TurnEntity>().HasData(turn_1, turn_2);
modelBuilder.Entity<NumberDieEntity>().HasData(die_1);
modelBuilder.Entity<NumberFaceEntity>().HasData(face_1, face_2);
modelBuilder.Entity<ImageDieEntity>().HasData(die_2);
modelBuilder.Entity<ImageFaceEntity>().HasData(face_3, face_4);
modelBuilder.Entity<ColorDieEntity>().HasData(die_3);
modelBuilder.Entity<ColorFaceEntity>().HasData(face_5, face_6);
// die 1 die 2 die 3
// turn 1 : num->2, img->https://2, clr->red
// turn 2 : num->1, clr->green
modelBuilder
.Entity<TurnEntity>()
.HasMany(turn => turn.Faces)
.WithMany(face => face.Turns)
.UsingEntity<FaceTurn>(join => join.HasData(
new { TurnEntityID = turnID_1, FaceEntityID = faceID_2 },
new { TurnEntityID = turnID_1, FaceEntityID = faceID_4 },
new { TurnEntityID = turnID_1, FaceEntityID = faceID_5 },
new { TurnEntityID = turnID_2, FaceEntityID = faceID_1 },
new { TurnEntityID = turnID_2, FaceEntityID = faceID_6 }));
modelBuilder
.Entity<TurnEntity>()
.HasMany(turn => turn.Dice)
.WithMany(die => die.Turns)
.UsingEntity<DieTurn>(join => join.HasData(
new { TurnEntityID = turnID_1, DieEntityID = dieID_1 },
new { TurnEntityID = turnID_1, DieEntityID = dieID_2 },
new { TurnEntityID = turnID_1, DieEntityID = dieID_3 },
new { TurnEntityID = turnID_2, DieEntityID = dieID_1 },
new { TurnEntityID = turnID_2, DieEntityID = dieID_3 }));
modelBuilder.Entity<PlayerEntity>().HasData(
new PlayerEntity { ID = Guid.Parse("e3b42372-0186-484c-9b1c-01618fbfac44"), Name = "Alice" },
new PlayerEntity { ID = Guid.Parse("73265e15-3c43-45f8-8f5d-d02feaaf7620"), Name = "Bob" },
new PlayerEntity { ID = Guid.Parse("5198ba9d-44d6-4660-85f9-1843828c6f0d"), Name = "Clyde" },
new PlayerEntity { ID = Guid.Parse("386cec27-fd9d-4475-8093-93c8b569bf2e"), Name = "Dahlia" }
);
}
}
}

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Data.EF.Games
{
public class GameDbManager
{
}
}

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Data.EF.Games
{
public class GameEntity
{
}
}

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Data.EF.Games
{
public static class GameExtensions
{
}
}

@ -1,88 +0,0 @@
using Data.EF.Dice;
using Data.EF.Dice.Faces;
using Data.EF.Joins;
using Data.EF.Players;
using Model.Players;
namespace Data.EF.Games
{
public sealed class TurnEntity : IEquatable<TurnEntity>
{
public Guid ID { get; set; }
public DateTime When { get; set; }
public PlayerEntity PlayerEntity { get; set; }
public Guid PlayerEntityID { get; set; }
public ICollection<DieEntity> Dice { get; set; } = new List<DieEntity>(); // many to many
public List<DieTurn> DieTurns { get; set; } = new();
public ICollection<FaceEntity> Faces { get; set; } = new List<FaceEntity>(); // many to many
public List<FaceTurn> FaceTurns { get; set; } = new();
public override bool Equals(object obj)
{
if (obj is not TurnEntity)
{
return false;
}
return Equals(obj as TurnEntity);
}
public bool Equals(TurnEntity other)
{
if (other is null
||
!(PlayerEntity.Equals(other.PlayerEntity)
&& When.Equals(other.When)
&& ID.Equals(other.ID)
&& Dice.Count == other.Dice.Count
&& Faces.Count == other.Faces.Count))
{
return false;
}
for (int i = 0; i < Faces.Count; i++)
{
if (Dice.ElementAt(i).Faces.Count
!= other.Dice.ElementAt(i).Faces.Count)
{
return false;
}
if (!other.Faces.ElementAt(i).ID
.Equals(Faces.ElementAt(i).ID))
{
return false;
}
for (int j = 0; j < Dice.ElementAt(i).Faces.Count; j++)
{
if (!other.Dice.ElementAt(i).Faces.ElementAt(j).ID
.Equals(Dice.ElementAt(i).Faces.ElementAt(j).ID))
{
return false;
}
}
}
return true;
}
public override int GetHashCode()
{
int result = HashCode.Combine(
ID,
When,
PlayerEntity);
foreach (DieEntity die in Dice)
{
result += die.GetHashCode();
}
foreach (FaceEntity face in Faces)
{
result += face.GetHashCode();
}
return result;
}
}
}

@ -1,68 +0,0 @@
using Data.EF.Dice;
using Data.EF.Dice.Faces;
using Data.EF.Players;
using Model.Dice;
using Model.Dice.Faces;
using Model.Games;
namespace Data.EF.Games
{
public static class TurnExtensions
{
private static (List<Die>, List<Face>) ToModelsByTypes(ICollection<DieEntity> diceEntities, ICollection<FaceEntity> faceEntities)
{
List<Die> dice = new();
List<Face> faces = new();
foreach (DieEntity dieEntity in diceEntities)
{
if (dieEntity.GetType() == typeof(NumberDieEntity)) { dice.Add((dieEntity as NumberDieEntity).ToModel()); }
if (dieEntity.GetType() == typeof(ColorDieEntity)) { dice.Add((dieEntity as ColorDieEntity).ToModel()); }
if (dieEntity.GetType() == typeof(ImageDieEntity)) { dice.Add((dieEntity as ImageDieEntity).ToModel()); }
}
foreach (FaceEntity faceEntity in faceEntities)
{
if (faceEntity.GetType() == typeof(NumberFaceEntity)) { faces.Add((faceEntity as NumberFaceEntity).ToModel()); }
if (faceEntity.GetType() == typeof(ColorFaceEntity)) { faces.Add((faceEntity as ColorFaceEntity).ToModel()); }
if (faceEntity.GetType() == typeof(ImageFaceEntity)) { faces.Add((faceEntity as ImageFaceEntity).ToModel()); }
}
return (dice, faces);
}
public static Turn ToModel(this TurnEntity entity)
{
Dictionary<Die, Face> DiceNFaces = new();
List<Die> keysList;
List<Face> valuesList;
(keysList, valuesList) = ToModelsByTypes(entity.Dice, entity.Faces);
DiceNFaces = Utils.Enumerables.FeedListsToDict(DiceNFaces, keysList, valuesList);
return Turn.CreateWithSpecifiedTime(when: entity.When, player: entity.PlayerEntity.ToModel(), diceNFaces: DiceNFaces);
}
public static IEnumerable<Turn> ToModels(this IEnumerable<TurnEntity> entities) => entities.Select(entity => entity.ToModel());
public static TurnEntity ToEntity(this Turn model)
{
List<DieEntity> DiceEntities = new();
List<FaceEntity> FaceEntities = new();
foreach (KeyValuePair<Die, Face> kvp in model.DiceNFaces)
{
if (kvp.Key.GetType() == typeof(NumberDie)) { DiceEntities.Add((kvp.Key as NumberDie).ToEntity()); FaceEntities.Add((kvp.Value as NumberFace).ToEntity()); }
if (kvp.Key.GetType() == typeof(ImageDie)) { DiceEntities.Add((kvp.Key as ImageDie).ToEntity()); FaceEntities.Add((kvp.Value as ImageFace).ToEntity()); }
if (kvp.Key.GetType() == typeof(ColorDie)) { DiceEntities.Add((kvp.Key as ColorDie).ToEntity()); FaceEntities.Add((kvp.Value as ColorFace).ToEntity()); }
}
return new TurnEntity() { When = model.When, PlayerEntity = model.Player.ToEntity(), Dice = DiceEntities, Faces = FaceEntities };
}
public static IEnumerable<TurnEntity> ToEntities(this IEnumerable<Turn> models) => models.Select(model => model.ToEntity());
}
}

@ -1,15 +0,0 @@
using Data.EF.Dice;
using Data.EF.Dice.Faces;
using Data.EF.Games;
namespace Data.EF.Joins
{
public class DieTurn
{
public Guid DieEntityID { get; set; }
public DieEntity DieEntity { get; set; }
public Guid TurnEntityID { get; set; }
public TurnEntity TurnEntity { get; set; }
}
}

@ -1,19 +0,0 @@
using Data.EF.Dice.Faces;
using Data.EF.Games;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Data.EF.Joins
{
public class FaceTurn
{
public Guid FaceEntityID { get; set; }
public FaceEntity FaceEntity { get; set; }
public Guid TurnEntityID { get; set; }
public TurnEntity TurnEntity { get; set; }
}
}

@ -1,186 +1,57 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Model;
using System.Collections.ObjectModel;
namespace Data.EF.Players
{
public sealed class PlayerDbManager : IManager<PlayerEntity>
{
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private readonly DiceAppDbContext db;
public PlayerDbManager(DiceAppDbContext db)
{
if (db is null)
{
ArgumentNullException ex = new(nameof(db), "param should not be null");
logger.Error(ex, "attempted to construct PlayerDbManager with a null context");
throw ex;
}
this.db = db;
}
/// <summary>
/// side effect: entity's name is trimmed.
/// </summary>
/// <param name="entity"></param>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentException"></exception>
private static void CleanPlayerEntity(PlayerEntity entity)
{
if (entity is null)
{
ArgumentNullException ex = new(nameof(entity), "param should not be null");
logger.Warn(ex);
throw ex;
}
if (string.IsNullOrWhiteSpace(entity.Name))
{
ArgumentException ex = new("Name property should not be null or whitespace", nameof(entity));
logger.Warn(ex);
throw ex;
}
entity.Name = entity.Name.Trim();
}
/// <summary>
/// adds a non-null PlayerEntity with a valid name to this mgr's context
/// </summary>
/// <param name="toAdd">the entity to add</param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentException"></exception>
public Task<PlayerEntity> Add(PlayerEntity toAdd)
{
CleanPlayerEntity(toAdd);
if (db.PlayerEntity.Where(entity => entity.Name == toAdd.Name).Any())
{
ArgumentException ex = new("this username is already taken", nameof(toAdd));
logger.Warn(ex);
throw ex;
}
return InternalAdd(toAdd);
}
private async Task<PlayerEntity> InternalAdd(PlayerEntity toAdd)
{
EntityEntry ee = await db.PlayerEntity.AddAsync(toAdd);
await db.SaveChangesAsync();
logger.Info("Added {0}", ee.Entity.ToString());
return (PlayerEntity)ee.Entity;
}
public async Task<ReadOnlyCollection<PlayerEntity>> GetAll()
{
List<PlayerEntity> players = new();
await Task.Run(() => players.AddRange(db.PlayerEntity));
return new ReadOnlyCollection<PlayerEntity>(players);
}
/// <summary>
/// This will throw an exception if no player with such name exists.
/// If you want to know whether any player with that name exists, call IsPresentByName()
/// </summary>
/// <param name="name"></param>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="InvalidOperationException"></exception>
/// <returns></returns>
public Task<PlayerEntity> GetOneByName(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentException("Name property should not be null or whitespace", nameof(name));
}
name = name.Trim();
return InternalGetOneByName(name);
}
private async Task<PlayerEntity> InternalGetOneByName(string name)
{
return await db.PlayerEntity.Where(p => p.Name == name).FirstAsync();
}
public async Task<bool> IsPresentByName(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
return false;
}
name = name.Trim();
return await db.PlayerEntity.Where(p => p.Name == name).FirstOrDefaultAsync() is not null;
}
/// <summary>
/// removes a non-null PlayerEntity with a valid name from this mgr's context
/// </summary>
/// <param name="toRemove">the entity to remove</param>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentException"></exception>
public void Remove(PlayerEntity toRemove)
{
CleanPlayerEntity(toRemove);
bool isPresent = IsPresentByID(toRemove.ID).Result;
if (isPresent)
{
db.PlayerEntity.Remove(toRemove);
logger.Info("Removed {0}", toRemove.ToString());
db.SaveChanges();
}
}
/// <summary>
/// updates a non-null PlayerEntity with a valid name in this mgr's context. This cannot update an ID
/// </summary>
/// <param name="before">the entity to update</param>
/// <param name="after">the entity to replace 'before'</param>
/// <returns>the updated entity</returns>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentException"></exception>
public Task<PlayerEntity> Update(PlayerEntity before, PlayerEntity after)
{
PlayerEntity[] args = { before, after };
foreach (PlayerEntity entity in args)
{
CleanPlayerEntity(entity);
}
if (before.ID != after.ID)
{
ArgumentException ex = new("ID cannot be updated", nameof(after));
logger.Warn(ex);
throw ex;
}
return InternalUpdate(before, after);
}
private async Task<PlayerEntity> InternalUpdate(PlayerEntity before, PlayerEntity after)
{
Remove(before);
return await Add(after);
}
/// <summary>
/// This will throw an exception if no player with such ID exists.
/// If you want to know whether any player with that ID exists, call IsPresentByID()
/// </summary>
/// <param name="ID">the ID to look for</param>
/// <returns>PlayerEntity with that ID</returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task<PlayerEntity> GetOneByID(Guid ID)
{
return await db.PlayerEntity.FirstAsync(p => p.ID == ID);
}
public async Task<bool> IsPresentByID(Guid ID)
{
return await db.PlayerEntity.FirstOrDefaultAsync(p => p.ID == ID) is not null;
}
}
}
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Data.EF.Players
{
public sealed class PlayerDBManager : IManager<PlayerEntity>, IDisposable
{
private readonly DiceAppDbContext db = new DiceAppDbContextWithStub();
public void Dispose()
{
db.Dispose();
}
public PlayerEntity Add(PlayerEntity toAdd)
{
if (db.Players!.Where(entity => entity.Name == toAdd.Name).Any())
{
throw new ArgumentException("this username is already taken", nameof(toAdd));
}
EntityEntry ee = db.Players!.Add(toAdd);
db.SaveChanges();
return (PlayerEntity)ee.Entity;
}
public IEnumerable<PlayerEntity> GetAll()
{
return db.Players!.AsEnumerable();
}
public PlayerEntity GetOneByName(string name)
{
throw new NotImplementedException();
}
public void Remove(PlayerEntity toRemove)
{
throw new NotImplementedException();
}
public PlayerEntity Update(PlayerEntity before, PlayerEntity after)
{
throw new NotImplementedException();
}
public PlayerEntity GetOneByID(Guid ID)
{
throw new NotImplementedException();
}
}
}

@ -1,186 +0,0 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Model;
using System.Collections.ObjectModel;
namespace Data.EF.Players
{
public sealed class PlayerDbManager : IManager<PlayerEntity>
{
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private readonly DiceAppDbContext db;
public PlayerDbManager(DiceAppDbContext db)
{
if (db is null)
{
ArgumentNullException ex = new(nameof(db), "param should not be null");
logger.Error(ex, "attempted to construct PlayerDbManager with a null context");
throw ex;
}
this.db = db;
}
/// <summary>
/// side effect: entity's name is trimmed.
/// </summary>
/// <param name="entity"></param>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentException"></exception>
private static void CleanPlayerEntity(PlayerEntity entity)
{
if (entity is null)
{
ArgumentNullException ex = new(nameof(entity), "param should not be null");
logger.Warn(ex);
throw ex;
}
if (string.IsNullOrWhiteSpace(entity.Name))
{
ArgumentException ex = new("Name property should not be null or whitespace", nameof(entity));
logger.Warn(ex);
throw ex;
}
entity.Name = entity.Name.Trim();
}
/// <summary>
/// adds a non-null PlayerEntity with a valid name to this mgr's context
/// </summary>
/// <param name="toAdd">the entity to add</param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentException"></exception>
public Task<PlayerEntity> Add(PlayerEntity toAdd)
{
CleanPlayerEntity(toAdd);
if (db.PlayerEntity.Where(entity => entity.Name == toAdd.Name).Any())
{
ArgumentException ex = new("this username is already taken", nameof(toAdd));
logger.Warn(ex);
throw ex;
}
return InternalAdd(toAdd);
}
private async Task<PlayerEntity> InternalAdd(PlayerEntity toAdd)
{
EntityEntry ee = await db.PlayerEntity.AddAsync(toAdd);
await db.SaveChangesAsync();
logger.Info("Added {0}", ee.Entity.ToString());
return (PlayerEntity)ee.Entity;
}
public async Task<ReadOnlyCollection<PlayerEntity>> GetAll()
{
List<PlayerEntity> players = new();
await Task.Run(() => players.AddRange(db.PlayerEntity));
return new ReadOnlyCollection<PlayerEntity>(players);
}
/// <summary>
/// This will throw an exception if no player with such name exists.
/// If you want to know whether any player with that name exists, call IsPresentByName()
/// </summary>
/// <param name="name"></param>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="InvalidOperationException"></exception>
/// <returns></returns>
public Task<PlayerEntity> GetOneByName(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentException("Name property should not be null or whitespace", nameof(name));
}
name = name.Trim();
return InternalGetOneByName(name);
}
private async Task<PlayerEntity> InternalGetOneByName(string name)
{
return await db.PlayerEntity.Where(p => p.Name == name).FirstAsync();
}
public async Task<bool> IsPresentByName(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
return false;
}
name = name.Trim();
return await db.PlayerEntity.Where(p => p.Name == name).FirstOrDefaultAsync() is not null;
}
/// <summary>
/// removes a non-null PlayerEntity with a valid name from this mgr's context
/// </summary>
/// <param name="toRemove">the entity to remove</param>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentException"></exception>
public void Remove(PlayerEntity toRemove)
{
CleanPlayerEntity(toRemove);
bool isPresent = IsPresentByID(toRemove.ID).Result;
if (isPresent)
{
db.PlayerEntity.Remove(toRemove);
logger.Info("Removed {0}", toRemove.ToString());
db.SaveChanges();
}
}
/// <summary>
/// updates a non-null PlayerEntity with a valid name in this mgr's context. This cannot update an ID
/// </summary>
/// <param name="before">the entity to update</param>
/// <param name="after">the entity to replace 'before'</param>
/// <returns>the updated entity</returns>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentException"></exception>
public Task<PlayerEntity> Update(PlayerEntity before, PlayerEntity after)
{
PlayerEntity[] args = { before, after };
foreach (PlayerEntity entity in args)
{
CleanPlayerEntity(entity);
}
if (before.ID != after.ID)
{
ArgumentException ex = new("ID cannot be updated", nameof(after));
logger.Warn(ex);
throw ex;
}
return InternalUpdate(before, after);
}
private async Task<PlayerEntity> InternalUpdate(PlayerEntity before, PlayerEntity after)
{
Remove(before);
return await Add(after);
}
/// <summary>
/// This will throw an exception if no player with such ID exists.
/// If you want to know whether any player with that ID exists, call IsPresentByID()
/// </summary>
/// <param name="ID">the ID to look for</param>
/// <returns>PlayerEntity with that ID</returns>
/// <exception cref="InvalidOperationException"></exception>
public async Task<PlayerEntity> GetOneByID(Guid ID)
{
return await db.PlayerEntity.FirstAsync(p => p.ID == ID);
}
public async Task<bool> IsPresentByID(Guid ID)
{
return await db.PlayerEntity.FirstOrDefaultAsync(p => p.ID == ID) is not null;
}
}
}

@ -1,5 +1,10 @@
using Data.EF.Games;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Model.Players;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Data.EF.Players
{
@ -8,11 +13,9 @@ namespace Data.EF.Players
{
public Guid ID { get; set; }
public string Name { get; set; }
public string? Name { get; set; }
public ICollection<TurnEntity> Turns { get; set; } = new List<TurnEntity>();
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
if (obj is not PlayerEntity)
{
@ -21,9 +24,9 @@ namespace Data.EF.Players
return Equals(obj as PlayerEntity);
}
public bool Equals(PlayerEntity other)
public bool Equals(PlayerEntity? other)
{
return other is not null && this.ID.Equals(other.ID) && this.Name.Equals(other.Name);
return other is not null && this.ID == other!.ID && this.Name == other.Name;
}
public override int GetHashCode()
@ -31,7 +34,7 @@ namespace Data.EF.Players
return HashCode.Combine(ID, Name);
}
public override string ToString()
public override string? ToString()
{
return $"{ID.ToString().ToUpper()} -- {Name}";
}

@ -4,12 +4,24 @@ namespace Data.EF.Players
{
public static class PlayerExtensions
{
public static Player ToModel(this PlayerEntity entity) => new(name: entity.Name);
public static Player ToModel(this PlayerEntity entity)
{
return new Player(name: entity.Name);
}
public static IEnumerable<Player> ToModels(this IEnumerable<PlayerEntity> entities) => entities.Select(entity => entity.ToModel());
public static IEnumerable<Player> ToModels(this IEnumerable<PlayerEntity> entities)
{
return entities.Select(entity => entity.ToModel());
}
public static PlayerEntity ToEntity(this Player model) => new() { Name = model.Name };
public static PlayerEntity ToEntity(this Player model)
{
return new PlayerEntity() { Name = model.Name };
}
public static IEnumerable<PlayerEntity> ToEntities(this IEnumerable<Player> models) => models.Select(model => model.ToEntity());
public static IEnumerable<PlayerEntity> ToEntities(this IEnumerable<Player> models)
{
return models.Select(model => model.ToEntity());
}
}
}

@ -1,9 +1,14 @@
using Model.Games;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Model.Games;
namespace Data
{
public interface ILoader
{
public Task<MasterOfCeremonies> LoadApp();
public GameRunner LoadApp();
}
}

@ -0,0 +1,24 @@

using Data.EF;
using Data.EF.Players;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Model.Players;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.Intrinsics.Arm;
namespace Data
{
internal static class Program
{
static void Main(string[] args)
{
using PlayerDBManager playerDBManager = new();
try { playerDBManager.Add(new Player("Ernesto").ToEntity()); }
catch (ArgumentException ex) { Debug.WriteLine($"{ex.Message}\n... Never mind"); }
foreach (PlayerEntity entity in playerDBManager.GetAll()) { Debug.WriteLine(entity); }
}
}
}

@ -1,22 +1,24 @@
using Model.Dice;
using Model;
using Model.Dice;
using Model.Dice.Faces;
using Model.Games;
using Model.Players;
using System.Collections.Generic;
using System.Drawing;
namespace Data
{
public class Stub : ILoader
{
public async Task<MasterOfCeremonies> LoadApp()
public GameRunner LoadApp()
{
MasterOfCeremonies mc = new(new PlayerManager(), new DiceGroupManager(), new GameManager());
GameRunner gr = new(new PlayerManager(), new DieManager());
Player player1 = new("Alice(Old Stub)"), player2 = new("Bob(Old Stub)"), player3 = new("Clyde(Old Stub)");
Player player1 = new("Alice"), player2 = new("Bob"), player3 = new("Clyde");
await mc.GlobalPlayerManager.Add(player1);
await mc.GlobalPlayerManager.Add(player2);
await mc.GlobalPlayerManager.Add(player3);
gr.GlobalPlayerManager.Add(player1);
gr.GlobalPlayerManager.Add(player2);
gr.GlobalPlayerManager.Add(player3);
List<Die> monopolyDice = new();
@ -27,8 +29,8 @@ namespace Data
NumberFace[] d6Faces = new NumberFace[] { new(1), new(2), new(3), new(4), new(5), new(6) };
monopolyDice.Add(new NumberDie(new NumberFace(1), new NumberFace(1), new NumberFace(1), new NumberFace(1)));
monopolyDice.Add(new NumberDie(d6Faces[0], d6Faces[1..]));
monopolyDice.Add(new NumberDie(d6Faces[0], d6Faces[1..]));
monopolyDice.Add(new NumberDie(d6Faces));
monopolyDice.Add(new NumberDie(d6Faces));
ColorFace[] colorFaces = new ColorFace[]
{
@ -40,7 +42,7 @@ namespace Data
new(Color.FromName("white"))
};
monopolyDice.Add(new ColorDie(colorFaces[0], colorFaces[1..]));
monopolyDice.Add(new ColorDie(colorFaces));
string rootPath = "https://unsplash.com/photos/";
@ -52,7 +54,7 @@ namespace Data
new(new Uri(rootPath + "A_Ncbi-RH6s")),
};
monopolyDice.Add(new ImageDie(imageFaces[0], imageFaces[1..]));
monopolyDice.Add(new ImageDie(imageFaces));
NumberFace[] d20Faces = new NumberFace[] {
new(1), new(2), new(3), new(4), new(5),
@ -61,38 +63,38 @@ namespace Data
new(16), new(17), new(18), new(19), new(20)
};
dndDice.Add(new NumberDie(d20Faces[0], d20Faces[1..]));
dndDice.Add(new NumberDie(d20Faces));
await mc.DiceGroupManager.Add(new DiceGroup(dndName, dndDice));
await mc.DiceGroupManager.Add(new DiceGroup(monopolyName, monopolyDice));
gr.GlobalDieManager.Add(new KeyValuePair<string, IEnumerable<Die>>(dndName, dndDice.AsEnumerable()));
gr.GlobalDieManager.Add(new KeyValuePair<string, IEnumerable<Die>>(monopolyName, monopolyDice.AsEnumerable()));
string game1 = "Forgotten Realms", game2 = "4e", game3 = "The Coopers";
await mc.GameManager.Add(new(game1, new PlayerManager(), dndDice.AsEnumerable()));
await mc.GameManager.Add(new(game2, new PlayerManager(), dndDice.AsEnumerable()));
await mc.GameManager.Add(new(game3, new PlayerManager(), monopolyDice.AsEnumerable()));
gr.Add(new(game1, new PlayerManager(), dndDice.AsEnumerable()));
gr.Add(new(game2, new PlayerManager(), dndDice.AsEnumerable()));
gr.Add(new(game3, new PlayerManager(), monopolyDice.AsEnumerable()));
await (await mc.GameManager.GetOneByName(game1)).PlayerManager.Add(player1);
await (await mc.GameManager.GetOneByName(game1)).PlayerManager.Add(player2);
gr.GetOneByName(game1).PlayerManager.Add(player1);
gr.GetOneByName(game1).PlayerManager.Add(player2);
await (await mc.GameManager.GetOneByName(game2)).PlayerManager.Add(player1);
await (await mc.GameManager.GetOneByName(game2)).PlayerManager.Add(player2);
await (await mc.GameManager.GetOneByName(game2)).PlayerManager.Add(player3);
gr.GetOneByName(game2).PlayerManager.Add(player1);
gr.GetOneByName(game2).PlayerManager.Add(player2);
gr.GetOneByName(game2).PlayerManager.Add(player3);
await (await mc.GameManager.GetOneByName(game3)).PlayerManager.Add(player1);
await (await mc.GameManager.GetOneByName(game3)).PlayerManager.Add(player3);
gr.GetOneByName(game3).PlayerManager.Add(player1);
gr.GetOneByName(game3).PlayerManager.Add(player3);
foreach (Game game in mc.GameManager.GetAll()?.Result)
foreach (Game game in gr.GetAll())
{
for (int i = 0; i < 10; i++)
{
Player currentPlayer = await game.GetWhoPlaysNow();
Player currentPlayer = game.GetWhoPlaysNow();
game.PerformTurn(currentPlayer);
await game.PrepareNextPlayer(currentPlayer);
game.PrepareNextPlayer(currentPlayer);
}
}
return mc;
return gr;
}
}
}

@ -9,9 +9,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Tests\Tests.csproj
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{953D2D67-BCE7-412C-B7BB-7C63B5592359}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Data", "Data\Data.csproj", "{E9683741-E603-4ED3-8088-4099D67FCA6D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Utils", "Utils\Utils\Utils.csproj", "{9300910D-9D32-4C79-8868-67D0ED56E2F3}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Data", "Data\Data.csproj", "{E9683741-E603-4ED3-8088-4099D67FCA6D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -31,10 +29,6 @@ Global
{E9683741-E603-4ED3-8088-4099D67FCA6D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E9683741-E603-4ED3-8088-4099D67FCA6D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E9683741-E603-4ED3-8088-4099D67FCA6D}.Release|Any CPU.Build.0 = Release|Any CPU
{9300910D-9D32-4C79-8868-67D0ED56E2F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9300910D-9D32-4C79-8868-67D0ED56E2F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9300910D-9D32-4C79-8868-67D0ED56E2F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9300910D-9D32-4C79-8868-67D0ED56E2F3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

@ -14,9 +14,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Tests\Tests.csproj
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{953D2D67-BCE7-412C-B7BB-7C63B5592359}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Data", "Data\Data.csproj", "{E9683741-E603-4ED3-8088-4099D67FCA6D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Utils", "Utils\Utils\Utils.csproj", "{9300910D-9D32-4C79-8868-67D0ED56E2F3}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Data", "Data\Data.csproj", "{E9683741-E603-4ED3-8088-4099D67FCA6D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -40,10 +38,6 @@ Global
{E9683741-E603-4ED3-8088-4099D67FCA6D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E9683741-E603-4ED3-8088-4099D67FCA6D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E9683741-E603-4ED3-8088-4099D67FCA6D}.Release|Any CPU.Build.0 = Release|Any CPU
{9300910D-9D32-4C79-8868-67D0ED56E2F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9300910D-9D32-4C79-8868-67D0ED56E2F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9300910D-9D32-4C79-8868-67D0ED56E2F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9300910D-9D32-4C79-8868-67D0ED56E2F3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

@ -5,9 +5,9 @@ namespace Model.Dice
{
public class ColorDie : HomogeneousDie<Color>
{
public ColorDie(ColorFace first, params ColorFace[] faces)
: base(first, faces)
public ColorDie(params ColorFace[] faces) : base(faces)
{
}
}
}

@ -1,45 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
namespace Model.Dice
{
public sealed class DiceGroup : IEquatable<DiceGroup>
{
public string Name { get; private set; }
public ReadOnlyCollection<Die> Dice => new(dice);
private readonly List<Die> dice = new();
public DiceGroup(string name, IEnumerable<Die> dice)
{
Name = name;
this.dice.AddRange(dice);
}
public bool Equals(DiceGroup other)
{
return Name == other.Name && Dice.SequenceEqual(other.Dice);
}
public override bool Equals(object obj)
{
if (obj is null) return false; // is null
if (ReferenceEquals(obj, this)) return true; // is me
if (!obj.GetType().Equals(GetType())) return false; // is different type
return Equals(obj as DiceGroup); // is not me, is not null, is same type : send up
}
public override int GetHashCode()
{
return HashCode.Combine(Name, dice);
}
public void Deconstruct(out string name, out ReadOnlyCollection<Die> dice)
{
dice = Dice;
name = Name;
}
}
}

@ -1,86 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
namespace Model.Dice
{
public class DiceGroupManager : IManager<DiceGroup>
{
private readonly List<DiceGroup> diceGroups = new();
public Task<DiceGroup> Add(DiceGroup toAdd)
{
if (string.IsNullOrWhiteSpace(toAdd.Name))
{
throw new ArgumentNullException(nameof(toAdd), "param should not be null or empty");
}
if (diceGroups.Contains(toAdd))
{
throw new ArgumentException("this dice group already exists", nameof(toAdd));
}
diceGroups.Add(new(toAdd.Name.Trim(), toAdd.Dice));
return Task.FromResult(toAdd);
}
public Task<ReadOnlyCollection<DiceGroup>> GetAll()
{
return Task.FromResult(new ReadOnlyCollection<DiceGroup>(diceGroups));
}
public Task<DiceGroup> GetOneByID(Guid ID)
{
throw new NotImplementedException();
}
public Task<DiceGroup> GetOneByName(string name)
{
// les groupes de dés nommés :
// ils sont case-sensistive, mais "mon jeu" == "mon jeu " == " mon jeu"
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentNullException(nameof(name), "param should not be null or empty");
}
return Task.FromResult(diceGroups.First(diceGroup => diceGroup.Name.Equals(name.Trim())));
}
public void Remove(DiceGroup toRemove)
{
if (toRemove.Name is null)
{
throw new ArgumentNullException(nameof(toRemove), "param should not be null");
}
else
{
diceGroups.Remove(toRemove);
}
}
/// <summary>
/// updates a (string, ReadOnlyCollection-of-Die) couple. only the name can be updated
/// </summary>
/// <param name="before">original couple</param>
/// <param name="after">new couple</param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="ArgumentNullException"></exception>
public Task<DiceGroup> Update(DiceGroup before, DiceGroup after)
{
// pas autorisé de changer les dés, juste le nom
if (!before.Dice.SequenceEqual(after.Dice))
{
throw new ArgumentException("the group of dice cannot be updated, only the name", nameof(before));
}
if (string.IsNullOrWhiteSpace(before.Name) || string.IsNullOrWhiteSpace(after.Name))
{
throw new ArgumentNullException(nameof(before), "dice group name should not be null or empty");
}
Remove(before);
Add(after);
return Task.FromResult(after);
}
}
}

@ -1,27 +1,26 @@
using Model.Dice.Faces;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
namespace Model.Dice
{
public abstract class Die
{
public ReadOnlyCollection<Face> Faces => new(faces);
public IEnumerable<Face> Faces => faces;
protected static readonly Random rnd = new();
private readonly List<Face> faces = new();
protected Die(Face first, params Face[] faces)
protected Die(params Face[] faces)
{
this.faces.AddRange(faces.Append(first));
this.faces.AddRange(faces);
}
public virtual Face GetRandomFace()
{
int faceIndex = rnd.Next(0, Faces.Count);
int faceIndex = rnd.Next(0, Faces.Count());
return Faces.ElementAt(faceIndex);
}
}

@ -0,0 +1,85 @@
using Model.Dice.Faces;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Model.Dice
{
public class DieManager : IManager<KeyValuePair<string, IEnumerable<Die>>>
{
private readonly Dictionary<string, IEnumerable<Die>> diceGroups = new();
public KeyValuePair<string, IEnumerable<Die>> Add(KeyValuePair<string, IEnumerable<Die>> toAdd)
{
// on trim la clé d'abord
if (string.IsNullOrWhiteSpace(toAdd.Key))
{
throw new ArgumentNullException(nameof(toAdd), "param should not be null or empty");
}
if (diceGroups.Contains(toAdd))
{
throw new ArgumentException("this username is already taken", nameof(toAdd));
}
diceGroups.Add(toAdd.Key.Trim(), toAdd.Value);
return toAdd;
}
public IEnumerable<KeyValuePair<string, IEnumerable<Die>>> GetAll()
{
return diceGroups.AsEnumerable();
}
public KeyValuePair<string, IEnumerable<Die>> GetOneByID(Guid ID)
{
throw new NotImplementedException();
}
public KeyValuePair<string, IEnumerable<Die>> GetOneByName(string name)
{
// les groupes de dés nommés :
// ils sont case-sensistive, mais "mon jeu" == "mon jeu " == " mon jeu"
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentNullException(nameof(name), "param should not be null or empty");
}
else
{
return new KeyValuePair<string, IEnumerable<Die>>(name, diceGroups[name]);
}
}
public void Remove(KeyValuePair<string, IEnumerable<Die>> toRemove)
{
if (toRemove.Key is null)
{
throw new ArgumentNullException(nameof(toRemove), "param should not be null");
}
else
{
diceGroups.Remove(toRemove.Key);
}
}
public KeyValuePair<string, IEnumerable<Die>> Update(KeyValuePair<string, IEnumerable<Die>> before, KeyValuePair<string, IEnumerable<Die>> after)
{
// pas autorisé de changer les dés, juste le nom
if (!before.Value.Equals(after.Value))
{
if (string.IsNullOrWhiteSpace(before.Key) || string.IsNullOrWhiteSpace(after.Key))
{
throw new ArgumentNullException(nameof(before), "dice group name should not be null or empty");
}
diceGroups.Remove(before.Key);
diceGroups.Add(after.Key, after.Value);
return after;
}
return before;
}
}
}

@ -3,8 +3,12 @@
public abstract class Face
{
public string StringValue { get; protected set; }
}
public override string ToString()
{
return StringValue;
}
}
public abstract class Face<T> : Face
{
public T Value { get; protected set; }
@ -14,5 +18,11 @@
Value = value;
StringValue = value.ToString();
}
protected Face(T value, string stringValue)
{
Value = value;
StringValue = stringValue;
}
}
}

@ -4,8 +4,7 @@ namespace Model.Dice
{
public abstract class HomogeneousDie<T> : Die
{
protected HomogeneousDie(Face<T> first, params Face<T>[] faces)
: base(first, faces)
protected HomogeneousDie(params Face<T>[] faces) : base(faces)
{
}

@ -5,8 +5,7 @@ namespace Model.Dice
{
public class ImageDie : HomogeneousDie<Uri>
{
public ImageDie(ImageFace first, params ImageFace[] faces)
: base(first, faces)
public ImageDie(params ImageFace[] faces) : base(faces)
{
}
}

@ -1,11 +1,15 @@
using Model.Dice.Faces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Model.Dice
{
public class NumberDie : HomogeneousDie<int>
{
public NumberDie(NumberFace first, params NumberFace[] faces)
: base(first, faces)
public NumberDie(params NumberFace[] faces) : base(faces)
{
}
}

@ -3,9 +3,10 @@ using Model.Dice.Faces;
using Model.Players;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Numerics;
using System.Text;
namespace Model.Games
{
@ -20,7 +21,7 @@ namespace Model.Games
{
return name;
}
set // MasterOfCeremonies will need to take care of forbidding
set // GameRunner will need to take care of forbidding
// (or allowing) having two Games with the same name etc.
{
if (string.IsNullOrWhiteSpace(value))
@ -35,18 +36,18 @@ namespace Model.Games
/// <summary>
/// references the position in list of the current player, for a given game.
/// </summary>
private int nextIndex = 0;
private int nextIndex;
/// <summary>
/// the turns that have been done so far
/// </summary>
private readonly List<Turn> turns = new();
private readonly List<Turn> turns;
/// </summary>
/// get a READ ONLY enumerable of all turns belonging to this game
/// </summary>
/// <returns>a readonly enumerable of all this game's turns</returns>
public ReadOnlyCollection<Turn> GetHistory() => new(turns);
public IEnumerable<Turn> GetHistory() => turns.AsEnumerable();
/// <summary>
/// the game's player manager, doing CRUD on players and switching whose turn it is
@ -56,8 +57,8 @@ namespace Model.Games
/// <summary>
/// the group of dice used for this game
/// </summary>
public ReadOnlyCollection<Die> Dice => new(dice);
private readonly List<Die> dice = new();
public IEnumerable<Die> Dice => dice;
private readonly IEnumerable<Die> dice;
/// <summary>
/// constructs a Game with its own history of Turns.
@ -71,19 +72,19 @@ namespace Model.Games
{
Name = name;
PlayerManager = playerManager;
this.dice.AddRange(dice);
this.turns.AddRange(turns);
this.turns = turns is null ? new List<Turn>() : turns.ToList();
this.dice = dice;
this.nextIndex = 0;
}
/// <summary>
/// constructs a Game with no history of turns.
///
/// </summary>
/// <param name="name">the name of the game 😎</param>
/// <param name="playerManager">the game's player manager, doing CRUD on players and switching whose turn it is</param>
/// <param name="favGroup">the group of dice used for this game</param>
public Game(string name, IManager<Player> playerManager, IEnumerable<Die> dice)
: this(name, playerManager, dice, new List<Turn>())
: this(name, playerManager, dice, null)
{ }
/// <summary>
@ -113,13 +114,13 @@ namespace Model.Games
/// </summary>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public async Task<Player> GetWhoPlaysNow()
public Player GetWhoPlaysNow()
{
if (!(await PlayerManager.GetAll()).Any())
if (!PlayerManager.GetAll().Any())
{
throw new MemberAccessException("you are exploring an empty collection\nthis should not have happened");
}
return (await PlayerManager.GetAll()).ElementAt(nextIndex);
return PlayerManager.GetAll().ElementAt(nextIndex);
}
/// <summary>
@ -129,9 +130,9 @@ namespace Model.Games
/// <exception cref="MemberAccessException"></exception>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentException"></exception>
public async Task PrepareNextPlayer(Player current)
public void PrepareNextPlayer(Player current)
{
IEnumerable<Player> players = await PlayerManager.GetAll();
IEnumerable<Player> players = PlayerManager.GetAll();
if (!players.Any())
{
throw new MemberAccessException("you are exploring an empty collection\nthis should not have happened");
@ -144,8 +145,16 @@ namespace Model.Games
{
throw new ArgumentException("param could not be found in this collection\n did you forget to add it?", nameof(current));
}
nextIndex = (nextIndex + 1) % players.Count();
if (players.Last() == current)
{
// if we've reached the last player, we need the index to loop back around
nextIndex = 0;
}
else
{
// else we can just move up by one from the current index
nextIndex++;
}
}
/// <summary>
@ -161,5 +170,31 @@ namespace Model.Games
}
return faces;
}
/// <summary>
/// represents a Game in string format
/// </summary>
/// <returns>a Game in string format</returns>
public override string ToString()
{
StringBuilder sb = new();
sb.Append($"Game: {Name}");
sb.Append("\nPlayers:");
foreach (Player player in PlayerManager.GetAll())
{
sb.Append($" {player.ToString()}");
}
sb.Append($"\nNext: {GetWhoPlaysNow()}");
sb.Append("\nLog:\n");
foreach (Turn turn in this.turns)
{
sb.Append($"\t{turn.ToString()}\n");
}
return sb.ToString();
}
}
}

@ -1,106 +1,117 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
namespace Model.Games
{
public class GameManager : IManager<Game>
{
/// <summary>
/// the games managed by this instance
/// </summary>
private readonly List<Game> games = new();
/// <summary>
/// gets an unmodifiable collection of the games
/// </summary>
/// <returns>unmodifiable collection of the games</returns>
public Task<ReadOnlyCollection<Game>> GetAll() => Task.FromResult(new ReadOnlyCollection<Game>(games));
/// <summary>
/// finds the game with that name and returns it
/// <br/>
/// that copy does not belong to this manager's games, so it should not be modified
/// </summary>
/// <param name="name">a games's name</param>
/// <returns>game with said name, <em>or null</em> if no such game was found</returns>
public Task<Game> GetOneByName(string name)
{
if (!string.IsNullOrWhiteSpace(name))
{
return Task.FromResult(games.FirstOrDefault(g => g.Name == name)); // may return null
}
throw new ArgumentException("param should not be null or blank", nameof(name));
}
/// <summary>
/// not implemented in the model
/// </summary>
/// <param name="ID"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public Task<Game> GetOneByID(Guid ID)
{
throw new NotImplementedException();
}
/// <summary>
/// saves a given game -- does not allow copies yet: if a game with the same name exists, it is overwritten
/// </summary>
/// <param name="toAdd">a game to save</param>
public Task<Game> Add(Game toAdd)
{
if (toAdd is null)
{
throw new ArgumentNullException(nameof(toAdd), "param should not be null");
}
games.Remove(games.FirstOrDefault(g => g.Name == toAdd.Name));
// will often be an update: if game with that name exists, it is removed, else, nothing happens above
games.Add(toAdd);
return Task.FromResult(toAdd);
}
/// <summary>
/// removes a game. does nothing if the game doesn't exist
/// </summary>
/// <param name="toRemove">game to remove</param>
/// <exception cref="ArgumentNullException"></exception>
public void Remove(Game toRemove)
{
if (toRemove is null)
{
throw new ArgumentNullException(nameof(toRemove), "param should not be null");
}
games.Remove(toRemove);
}
/// <summary>
/// updates a game
/// </summary>
/// <param name="before">original game</param>
/// <param name="after">new game</param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public Task<Game> Update(Game before, Game after)
{
Game[] args = { before, after };
foreach (Game game in args)
{
if (game is null)
{
throw new ArgumentNullException(nameof(after), "param should not be null");
// could also be because of before, but one param had to be chosen as an example
// and putting "player" there was raising a major code smell
}
}
Remove(before);
return (Add(after));
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Model.Dice;
using Model.Dice.Faces;
using Model.Players;
namespace Model.Games
{
public class GameRunner : IManager<Game>
{
public IManager<Player> GlobalPlayerManager { get; private set; }
public IManager<KeyValuePair<string, IEnumerable<Die>>> GlobalDieManager { get; private set; }
private readonly List<Game> games;
public GameRunner(IManager<Player> globalPlayerManager, IManager<KeyValuePair<string, IEnumerable<Die>>> globalDieManager, List<Game> games)
{
GlobalPlayerManager = globalPlayerManager;
GlobalDieManager = globalDieManager;
this.games = games ?? new();
}
public GameRunner(IManager<Player> globalPlayerManager, IManager<KeyValuePair<string, IEnumerable<Die>>> globalDieManager)
: this(globalPlayerManager, globalDieManager, null){ }
public IEnumerable<Game> GetAll() => games.AsEnumerable();
/// <summary>
/// finds the game with that name and returns it
/// <br/>
/// that copy does not belong to this gamerunner's games, so it should not be modified
/// </summary>
/// <param name="name">a games's name</param>
/// <returns>game with said name, <em>or null</em> if no such game was found</returns>
public Game GetOneByName(string name)
{
if (!string.IsNullOrWhiteSpace(name))
{
Game result = games.FirstOrDefault(g => g.Name == name);
return result; // may return null
}
throw new ArgumentException("param should not be null or blank", nameof(name));
}
/// <summary>
/// saves a given game -- does not allow copies yet: if a game with the same name exists, it is overwritten
/// </summary>
/// <param name="toAdd">a game to save</param>
public Game Add(Game toAdd)
{
if (toAdd is null)
{
throw new ArgumentNullException(nameof(toAdd), "param should not be null");
}
games.Remove(games.FirstOrDefault(g => g.Name == toAdd.Name));
// will often be an update: if game with that name exists, it is removed, else, nothing happens above
games.Add(toAdd);
return toAdd;
}
/// <summary>
/// creates a new game
/// </summary>
public Game StartNewGame(string name, IManager<Player> playerManager, IEnumerable<Die> dice)
{
Game game = new(name, playerManager, dice);
return Add(game);
}
public void Remove(Game toRemove)
{
if (toRemove is null)
{
throw new ArgumentNullException(nameof(toRemove), "param should not be null");
}
games.Remove(toRemove);
}
public Game Update(Game before, Game after)
{
Game[] args = { before, after };
foreach (Game game in args)
{
if (game is null)
{
throw new ArgumentNullException(nameof(after), "param should not be null");
// could also be because of before, but one param had to be chosen as an example
// and putting "player" there was raising a major code smell
}
}
Remove(before);
return Add(after);
}
/// <summary>
/// plays one turn of the game
/// </summary>
/// <param name="game">the game from which a turn will be played</param>
public static void PlayGame(Game game)
{
Player current = game.GetWhoPlaysNow();
game.PerformTurn(current);
game.PrepareNextPlayer(current);
}
public Game GetOneByID(Guid ID)
{
throw new NotImplementedException();
}
}
}

@ -1,46 +0,0 @@
using Model.Dice;
using Model.Players;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Model.Games
{
public class MasterOfCeremonies
{
public IManager<Player> GlobalPlayerManager { get; private set; }
public IManager<DiceGroup> DiceGroupManager { get; private set; }
public IManager<Game> GameManager { get; private set; }
public MasterOfCeremonies(IManager<Player> globalPlayerManager, IManager<DiceGroup> globalDiceGroupManager, IManager<Game> gameManager)
{
GlobalPlayerManager = globalPlayerManager;
DiceGroupManager = globalDiceGroupManager;
GameManager = gameManager;
}
/// <summary>
/// creates a new game
/// </summary>
/// <param name="name"></param>
/// <param name="playerManager"></param>
/// <param name="dice"></param>
/// <returns></returns>
public async Task<Game> StartNewGame(string name, IManager<Player> playerManager, IEnumerable<Die> dice)
{
Game game = new(name, playerManager, dice);
return await GameManager.Add(game);
}
/// <summary>
/// plays one turn of the game
/// </summary>
/// <param name="game">the game from which a turn will be played</param>
public static async Task PlayGame(Game game)
{
Player current = await game.GetWhoPlaysNow();
game.PerformTurn(current);
await game.PrepareNextPlayer(current);
}
}
}

@ -1,16 +1,19 @@
using Model.Dice;
using Model.Dice.Faces;
using Model.Players;
using System;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using Model.Dice;
using Model.Dice.Faces;
using Model.Players;
namespace Model.Games
{
/// <summary>
/// a Turn consists of a Player, a DateTime, and a IEnumerable of AbstractDieFace
/// Like a turn in some game.
/// <br/>
/// Two turns are equal if they are litterally the same instance in RAM
/// (default behaviors Equals() and GetHashCode())
/// </summary>
public sealed class Turn : IEquatable<Turn>
{
@ -28,7 +31,7 @@ namespace Model.Games
/// <summary>
/// the collection of Face that were rolled
/// </summary>
public ReadOnlyDictionary<Die, Face> DiceNFaces => new(diceNFaces);
public IEnumerable<KeyValuePair<Die, Face>> DiceNFaces => diceNFaces.AsEnumerable();
private readonly Dictionary<Die, Face> diceNFaces;
/// <summary>
@ -37,7 +40,24 @@ namespace Model.Games
/// <param name="when">date and time of the turn</param>
/// <param name="player">player who played the turn</param>
/// <param name="faces">faces that were rolled</param>
private Turn(DateTime when, Player player, IEnumerable<KeyValuePair<Die, Face>> diceNFaces)
private Turn(DateTime when, Player player, Dictionary<Die, Face> diceNFaces)
{
When = when;
Player = player;
this.diceNFaces = diceNFaces;
}
/// <summary>
/// creates a Turn with a specified time, passed as a parameter.
/// <br/>
/// whatever the DateTimeKind of <paramref name="when"/> might be,
/// it will become UTC during construction
/// </summary>
/// <param name="when">date and time of the turn</param>
/// <param name="player">player who played the turn</param>
/// <param name="faces">faces that were rolled</param>
/// <returns>a new Turn object</returns>
public static Turn CreateWithSpecifiedTime(DateTime when, Player player, Dictionary<Die, Face> diceNFaces)
{
if (player is null)
{
@ -47,7 +67,7 @@ namespace Model.Games
{
throw new ArgumentNullException(nameof(diceNFaces), "param should not be null");
}
if (!diceNFaces.Any())
if (diceNFaces.Count == 0)
{
throw new ArgumentException("param should not be null", nameof(diceNFaces));
}
@ -56,73 +76,50 @@ namespace Model.Games
when = when.ToUniversalTime();
}
When = when;
Player = player;
this.diceNFaces = diceNFaces.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
return new Turn(when, player, diceNFaces);
}
/// <summary>
/// creates a Turn with a specified time, passed as a parameter.
/// <br/>
/// whatever the DateTimeKind of <paramref name="when"/> might be,
/// it will become UTC during construction
/// creates a Turn with a default time, which is "now" in UTC.
/// </summary>
/// <param name="when">date and time of the turn</param>
/// <param name="player">player who played the turn</param>
/// <param name="faces">faces that were rolled</param>
/// <returns>a new Turn object</returns>
public static Turn CreateWithSpecifiedTime(DateTime when, Player player, IEnumerable<KeyValuePair<Die, Face>> diceNFaces)
public static Turn CreateWithDefaultTime(Player player, Dictionary<Die, Face> diceNFaces)
{
return new Turn(when, player, diceNFaces);
return CreateWithSpecifiedTime(DateTime.UtcNow, player, diceNFaces);
}
/// <summary>
/// creates a Turn with a default time, which is "now" in UTC.
/// represents a turn in string format
/// </summary>
/// <param name="player">player who played the turn</param>
/// <param name="faces">faces that were rolled</param>
/// <returns>a new Turn object</returns>
public static Turn CreateWithDefaultTime(Player player, IEnumerable<KeyValuePair<Die, Face>> diceNFaces)
/// <returns>a turn in string format</returns>
public override string ToString()
{
return CreateWithSpecifiedTime(DateTime.UtcNow, player, diceNFaces);
string[] datetime = When.ToString("s", System.Globalization.CultureInfo.InvariantCulture).Split("T");
string date = datetime[0];
string time = datetime[1];
StringBuilder sb = new();
sb.AppendFormat("{0} {1} -- {2} rolled:",
date,
time,
Player.ToString());
foreach (Face face in this.diceNFaces.Values)
{
sb.Append(" " + face.ToString());
}
return sb.ToString();
}
public bool Equals(Turn other)
{
if (other is null
||
!(Player.Equals(other.Player)
&& When.Equals(other.When)
&& DiceNFaces.Count == other.DiceNFaces.Count))
{
return false;
}
return Player.Equals(other.Player)
&& When.Equals(other.When)
&& DiceNFaces.SequenceEqual(other.DiceNFaces);
// 🤮
for (int i = 0; i < DiceNFaces.Count; i++)
{
if (DiceNFaces.ElementAt(i).Key.Faces.Count
!= other.DiceNFaces.ElementAt(i).Key.Faces.Count)
{
return false;
}
if (!other.DiceNFaces.ElementAt(i).Value.StringValue
.Equals(DiceNFaces.ElementAt(i).Value.StringValue))
{
return false;
}
for (int j = 0; j < DiceNFaces.ElementAt(i).Key.Faces.Count; j++)
{
if (!other.DiceNFaces.ElementAt(i).Key.Faces.ElementAt(j).StringValue
.Equals(DiceNFaces.ElementAt(i).Key.Faces.ElementAt(j).StringValue))
{
return false;
}
}
}
return true;
}
public override bool Equals(object obj)
@ -136,7 +133,7 @@ namespace Model.Games
public override int GetHashCode()
{
return When.GetHashCode();
return HashCode.Combine(Player, When, DiceNFaces);
}
}
}

@ -1,21 +1,14 @@
using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace Model
{
public interface IManager<T>
{
public Task<T> Add(T toAdd);
public Task<T> GetOneByName(string name);
public Task<T> GetOneByID(Guid ID);
public Task<ReadOnlyCollection<T>> GetAll();
public Task<T> Update(T before, T after);
public T Add(T toAdd);
public T GetOneByName(string name);
public T GetOneByID(Guid ID);
public IEnumerable<T> GetAll();
public T Update(T before, T after);
public void Remove(T toRemove);
}
}

@ -4,8 +4,4 @@
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NLog" Version="5.0.4" />
</ItemGroup>
</Project>

@ -30,6 +30,11 @@ namespace Model.Players
: this(player?.Name) // passes the player's name if player exists, else null
{ }
public override string ToString()
{
return Name;
}
public bool Equals(Player other)
{
return other is not null && Name.ToUpper() == other.Name.ToUpper(); // equality is case insensitive

@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
namespace Model.Players
{
@ -11,14 +9,18 @@ namespace Model.Players
/// <summary>
/// a collection of the players that this manager is in charge of
/// </summary>
private readonly List<Player> players = new();
private readonly List<Player> players;
public PlayerManager()
{
players = new();
}
/// <summary>
/// add a new player
/// </summary>
/// <param name="toAdd">player to be added</param>
/// <returns>added player</returns>
public Task<Player> Add(Player toAdd)
public Player Add(Player toAdd)
{
if (toAdd is null)
{
@ -29,27 +31,25 @@ namespace Model.Players
throw new ArgumentException("this username is already taken", nameof(toAdd));
}
players.Add(toAdd);
return Task.FromResult(toAdd);
return toAdd;
}
/// <summary>
/// finds the player with that name and returns it
/// finds the player with that name and returns A COPY OF IT
/// <br/>
/// that copy does not belong to this manager's players, so it should not be modified
/// </summary>
/// <param name="name">a player's unique name</param>
/// <returns>player with said name, <em>or null</em> if no such player was found</returns>
public Task<Player> GetOneByName(string name)
public Player GetOneByName(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentException("param should not be null or blank", nameof(name));
}
Player result = players.FirstOrDefault(p => p.Name.ToUpper().Equals(name.ToUpper().Trim()));
if (result == null)
if (!string.IsNullOrWhiteSpace(name))
{
return Task.FromResult<Player>(null);
Player wanted = new(name);
Player result = players.FirstOrDefault(p => p.Equals(wanted));
return result is null ? null : new Player(result); // THIS IS A COPY (using a copy constructor)
}
return Task.FromResult(result);
throw new ArgumentException("param should not be null or blank", nameof(name));
}
/// </summary>
@ -57,7 +57,7 @@ namespace Model.Players
/// so that the only way to modify the collection of players is to use this class's methods
/// </summary>
/// <returns>a readonly enumerable of all this manager's players</returns>
public Task<ReadOnlyCollection<Player>> GetAll() => Task.FromResult(new ReadOnlyCollection<Player>(players));
public IEnumerable<Player> GetAll() => players.AsEnumerable();
/// <summary>
/// update a player from <paramref name="before"/> to <paramref name="after"/>
@ -65,7 +65,7 @@ namespace Model.Players
/// <param name="before">player to be updated</param>
/// <param name="after">player in the state that it needs to be in after the update</param>
/// <returns>updated player</returns>
public Task<Player> Update(Player before, Player after)
public Player Update(Player before, Player after)
{
Player[] args = { before, after };
@ -96,7 +96,7 @@ namespace Model.Players
players.Remove(toRemove);
}
public Task<Player> GetOneByID(Guid ID)
public Player GetOneByID(Guid ID)
{
throw new NotImplementedException();
}

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tests.Data_UTs.Dice
{
public class ColorDieEntityTest
{
}
}

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tests.Data_UTs.Dice
{
public class ColorDieExtensionsTest
{
}
}

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tests.Data_UTs.Dice
{
public class DiceGroupDbManagerTest
{
}
}

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tests.Data_UTs.Dice.Faces
{
public class ColorFaceEntityTest
{
}
}

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tests.Data_UTs.Dice.Faces
{
public class ColorFaceExtensionsTest
{
}
}

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tests.Data_UTs.Dice.Faces
{
public class ImageFaceEntityTest
{
}
}

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tests.Data_UTs.Dice.Faces
{
public class ImageFaceExtensionsTest
{
}
}

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tests.Data_UTs.Dice.Faces
{
public class NumberFaceEntityTest
{
}
}

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tests.Data_UTs.Dice.Faces
{
public class NumberFaceExtensionsTest
{
}
}

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tests.Data_UTs.Dice
{
public class ImageDieEntityTest
{
}
}

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tests.Data_UTs.Dice
{
public class ImageDieExtensionsTest
{
}
}

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tests.Data_UTs.Dice
{
public class NumberDieEntityTest
{
}
}

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tests.Data_UTs.Dice
{
public class NumberDieExtensionsTest
{
}
}

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tests.Data_UTs
{
public class DiceAppDbContextTest
{
}
}

@ -1,49 +0,0 @@
using Data.EF;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
namespace Tests.Data_UTs
{
public class DiceAppDbContextWithStubTest
{
private readonly SqliteConnection connection = new("DataSource=:memory:");
private readonly DbContextOptions<DiceAppDbContext> options;
public DiceAppDbContextWithStubTest()
{
connection.Open();
options = new DbContextOptionsBuilder<DiceAppDbContext>()
.UseSqlite(connection)
.EnableSensitiveDataLogging()
.Options;
}
[Theory]
[InlineData("Alice")]
[InlineData("Bob")]
[InlineData("Clyde")]
[InlineData("Dahlia")]
public void TestDbStubContainsAll(string name)
{
// Arrange
using (DiceAppDbContextWithStub db = new(options))
{
db.Database.EnsureCreated();
// Assert
Assert.True(db.PlayerEntity.Where(p => p.Name.Equals(name)).Any());
}
}
}
}

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tests.Data_UTs.Games
{
public class GameDbManagerTest
{
}
}

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tests.Data_UTs.Games
{
public class GameEntityTest
{
}
}

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tests.Data_UTs.Games
{
public class GameExtensionsTest
{
}
}

@ -1,407 +0,0 @@
using Data.EF.Dice;
using Data.EF.Dice.Faces;
using Data.EF.Games;
using Data.EF.Joins;
using Data.EF.Players;
using System;
using System.Collections.Generic;
using System.Drawing;
using Xunit;
namespace Tests.Data_UTs.Games
{
public class TurnEntityTest
{
private readonly DieEntity numDie;
private readonly FaceEntity numFace1 = new NumberFaceEntity() { ID = Guid.NewGuid(), Value = 7 };
private readonly FaceEntity numFace2 = new NumberFaceEntity() { ID = Guid.NewGuid(), Value = 8 };
private readonly DieEntity clrDie;
private readonly FaceEntity clrFace1 = new ColorFaceEntity() { ID = Guid.NewGuid(), A = 255, R = 255, G = 255, B = 255 };
private readonly FaceEntity clrFace2 = new ColorFaceEntity() { ID = Guid.NewGuid() };
private readonly DieEntity imgDie;
private readonly FaceEntity imgFace1 = new ImageFaceEntity() { ID = Guid.NewGuid(), Value = "https://a" };
private readonly FaceEntity imgFace2 = new ImageFaceEntity() { ID = Guid.NewGuid(), Value = "https://b" };
private readonly PlayerEntity player1 = new() { ID = Guid.NewGuid(), Name = "Marvin" };
private readonly PlayerEntity player2 = new() { ID = Guid.NewGuid(), Name = "Barbara" };
private readonly DateTime datetime1 = new(2020, 6, 15, 12, 15, 3, DateTimeKind.Utc);
private readonly DateTime datetime2 = new(2016, 12, 13, 14, 15, 16, DateTimeKind.Utc);
private readonly DieTurn dieTurn1;
private readonly DieTurn dieTurn2;
private readonly DieTurn dieTurn3;
private readonly DieTurn dieTurn4;
private readonly DieTurn dieTurn5;
private readonly FaceTurn faceTurn1;
private readonly FaceTurn faceTurn2;
private readonly FaceTurn faceTurn3;
private readonly FaceTurn faceTurn4;
private readonly FaceTurn faceTurn5;
private readonly TurnEntity turn1;
private readonly TurnEntity turn2;
private readonly TurnEntity turn3;
public TurnEntityTest()
{
numDie = new NumberDieEntity() { ID = Guid.NewGuid(), Faces = new List<NumberFaceEntity>() { numFace1 as NumberFaceEntity, numFace2 as NumberFaceEntity } };
(numFace1 as NumberFaceEntity).NumberDieEntity = (NumberDieEntity)numDie;
(numFace2 as NumberFaceEntity).NumberDieEntity = (NumberDieEntity)numDie;
(clrFace2 as ColorFaceEntity).SetValue(Color.FromName("blue"));
clrDie = new ColorDieEntity() { ID = Guid.NewGuid(), Faces = new List<ColorFaceEntity>() { clrFace1 as ColorFaceEntity, clrFace2 as ColorFaceEntity } };
(clrFace1 as ColorFaceEntity).ColorDieEntity = (ColorDieEntity)clrDie;
(clrFace2 as ColorFaceEntity).ColorDieEntity = (ColorDieEntity)clrDie;
imgDie = new ImageDieEntity() { ID = Guid.NewGuid(), Faces = new List<ImageFaceEntity>() { imgFace1 as ImageFaceEntity, imgFace2 as ImageFaceEntity } };
(imgFace1 as ImageFaceEntity).ImageDieEntity = (ImageDieEntity)imgDie;
(imgFace2 as ImageFaceEntity).ImageDieEntity = (ImageDieEntity)imgDie;
turn1 = new()
{
ID = Guid.NewGuid(),
When = datetime1,
PlayerEntity = player1,
PlayerEntityID = player1.ID,
Dice = new List<DieEntity>
{
numDie,
clrDie,
imgDie
},
Faces = new List<FaceEntity>
{
numFace1,
clrFace2,
imgFace2
},
};
dieTurn1 = new() { DieEntityID = numDie.ID, DieEntity = numDie, TurnEntityID = turn1.ID, TurnEntity = turn1 };
dieTurn2 = new() { DieEntityID = clrDie.ID, DieEntity = clrDie, TurnEntityID = turn1.ID, TurnEntity = turn1 };
dieTurn3 = new() { DieEntityID = imgDie.ID, DieEntity = imgDie, TurnEntityID = turn1.ID, TurnEntity = turn1 };
turn1.DieTurns = new() { dieTurn1, dieTurn2, dieTurn3 };
numDie.DieTurns = new() { dieTurn1 };
clrDie.DieTurns = new() { dieTurn2 };
imgDie.DieTurns = new() { dieTurn3 };
faceTurn1 = new() { FaceEntityID = numFace1.ID, FaceEntity = numFace1, TurnEntityID = turn1.ID, TurnEntity = turn1 };
faceTurn2 = new() { FaceEntityID = clrFace2.ID, FaceEntity = clrFace2, TurnEntityID = turn1.ID, TurnEntity = turn1 };
faceTurn3 = new() { FaceEntityID = imgFace2.ID, FaceEntity = imgFace2, TurnEntityID = turn1.ID, TurnEntity = turn1 };
turn1.FaceTurns = new() { faceTurn1, faceTurn2, faceTurn3 };
numFace1.FaceTurns = new() { faceTurn1 };
clrFace2.FaceTurns = new() { faceTurn2 };
imgFace2.FaceTurns = new() { faceTurn3 };
Guid turn2ID = Guid.NewGuid();
turn2 = new()
{
ID = turn2ID,
When = datetime2,
PlayerEntity = player2,
PlayerEntityID = player2.ID,
Dice = new List<DieEntity>
{
numDie,
clrDie
},
Faces = new List<FaceEntity>
{
numFace2,
clrFace2
},
};
dieTurn4 = new() { DieEntityID = numDie.ID, DieEntity = numDie, TurnEntityID = turn2.ID, TurnEntity = turn2 };
dieTurn5 = new() { DieEntityID = clrDie.ID, DieEntity = clrDie, TurnEntityID = turn2.ID, TurnEntity = turn2 };
turn2.DieTurns = new() { dieTurn4, dieTurn5 };
numDie.DieTurns = new() { dieTurn4 };
clrDie.DieTurns = new() { dieTurn5 };
faceTurn4 = new() { FaceEntityID = numFace2.ID, FaceEntity = numFace2, TurnEntityID = turn2.ID, TurnEntity = turn2 };
faceTurn5 = new() { FaceEntityID = clrFace2.ID, FaceEntity = clrFace2, TurnEntityID = turn2.ID, TurnEntity = turn2 };
turn2.FaceTurns = new() { faceTurn4, faceTurn5 };
numFace2.FaceTurns = new() { faceTurn4 };
clrFace2.FaceTurns = new() { faceTurn5 };
turn3 = new()
{
ID = turn2ID,
When = datetime2,
PlayerEntity = player2,
PlayerEntityID = player2.ID,
Dice = new List<DieEntity>
{
numDie,
clrDie
},
Faces = new List<FaceEntity>
{
numFace2,
clrFace2
},
};
}
[Fact]
public void TestGetSetID()
{
// Arrange
TurnEntity turn = new();
Guid expected = Guid.NewGuid();
// Act
turn.ID = expected;
Guid actual = turn.ID;
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public void TestGetSetWhen()
{
// Arrange
TurnEntity turn = new();
DateTime expected = datetime1;
// Act
turn.When = expected;
DateTime actual = turn.When;
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public void TestGetSetPlayer()
{
// Arrange
TurnEntity turn = new();
PlayerEntity expected = player1;
// Act
turn.PlayerEntity = expected;
PlayerEntity actual = turn.PlayerEntity;
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public void TestGetSetPlayerID()
{
// Arrange
TurnEntity turn = new();
Guid expected = player1.ID;
// Act
turn.PlayerEntityID = expected;
Guid actual = turn.PlayerEntityID;
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public void TestGetSetDice()
{
// Arrange
TurnEntity turn = new();
ICollection<DieEntity> expected = new List<DieEntity>
{
numDie,
clrDie,
imgDie
};
// Act
turn.Dice = expected;
ICollection<DieEntity> actual = turn.Dice;
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public void TestGetSetDieTurns()
{
// Arrange
TurnEntity turn = new();
List<DieTurn> expected = new() { dieTurn1, dieTurn2, dieTurn3 };
// Act
turn.DieTurns = expected;
List<DieTurn> actual = turn.DieTurns;
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public void TestGetSetFaces()
{
// Arrange
TurnEntity turn = new();
ICollection<FaceEntity> expected = new List<FaceEntity>
{
numFace1,
clrFace1,
imgFace1
};
// Act
turn.Faces = expected;
ICollection<FaceEntity> actual = turn.Faces;
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public void TestGetSetFaceTurns()
{
// Arrange
TurnEntity turn = new();
List<FaceTurn> expected = new() { faceTurn1, faceTurn2 };
// Act
turn.FaceTurns = expected;
List<FaceTurn> actual = turn.FaceTurns;
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public void TestEqualsWhenNotTurnEntityThenFalse()
{
// Arrange
Point point;
TurnEntity entity;
// Act
point = new(1, 2);
entity = turn1;
// Assert
Assert.False(point.Equals(entity));
Assert.False(entity.Equals(point));
}
[Fact]
public void TestEqualsWhenNullThenFalse()
{
// Arrange
TurnEntity entity;
// Act
entity = turn2;
// Assert
Assert.False(entity.Equals(null));
}
[Fact]
public void TestGoesThruToSecondMethodIfObjIsTypeTurnEntity()
{
// Arrange
object t1;
TurnEntity t2;
// Act
t1 = turn1;
t2 = turn2;
// Assert
Assert.False(t1.Equals(t2));
Assert.False(t2.Equals(t1));
}
[Fact]
public void TestEqualsFalseIfNotSame()
{
// Arrange
TurnEntity t1;
TurnEntity t2;
// Act
t1 = turn1;
t2 = turn2;
// Assert
Assert.False(t1.Equals(t2));
Assert.False(t2.Equals(t1));
}
[Fact]
public void TestEqualsTrueIfSame()
{
// Arrange
TurnEntity t1;
TurnEntity t2;
// Act
t1 = turn2;
t2 = turn3; // turns 2 and 3 should be same as far as Equals is concerned
// Assert
Assert.True(t1.Equals(t2));
Assert.True(t2.Equals(t1));
}
[Fact]
public void TestSameHashFalseIfNotSame()
{
// Arrange
TurnEntity t1;
TurnEntity t2;
// Act
t1 = turn1;
t2 = turn2;
// Assert
Assert.False(t1.GetHashCode().Equals(t2.GetHashCode()));
Assert.False(t2.GetHashCode().Equals(t1.GetHashCode()));
}
[Fact]
public void TestSameHashTrueIfSame()
{
// Arrange
TurnEntity t1;
TurnEntity t2;
// Act
t1 = turn2;
t2 = turn3;
// Assert
Assert.True(t1.GetHashCode().Equals(t2.GetHashCode()));
Assert.True(t2.GetHashCode().Equals(t1.GetHashCode()));
}
}
}

@ -1,274 +0,0 @@
using Data.EF.Dice.Faces;
using Data.EF.Dice;
using Data.EF.Players;
using Model.Dice;
using Model.Players;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
using Data.EF.Games;
using System.Drawing;
using Model.Games;
using Newtonsoft.Json.Linq;
using Model.Dice.Faces;
using System.Diagnostics;
namespace Tests.Data_UTs.Games
{
public class TurnExtensionsTest
{
private readonly DateTime datetime1 = new(2013, 2, 1, 1, 19, 4, DateTimeKind.Utc);
private readonly DateTime datetime2 = new(2014, 8, 1, 23, 12, 4, DateTimeKind.Utc);
private readonly PlayerEntity playerEntity = new() { Name = "Paula" };
private readonly DieEntity numDieEntity;
private readonly FaceEntity numFace1Entity = new NumberFaceEntity() { Value = 7 };
private readonly FaceEntity numFace2Entity = new NumberFaceEntity() { Value = 8 };
private readonly DieEntity clrDieEntity;
private readonly FaceEntity clrFace1Entity = new ColorFaceEntity() { A = 255, R = 255, G = 255, B = 255 };
private readonly FaceEntity clrFace2Entity = new ColorFaceEntity() { A = 255, R = 0, G = 0, B = 128 };
private readonly DieEntity imgDieEntity;
private readonly FaceEntity imgFace1Entity = new ImageFaceEntity() { Value = "https://a" };
private readonly FaceEntity imgFace2Entity = new ImageFaceEntity() { Value = "https://b" };
public TurnExtensionsTest()
{
numDieEntity = new NumberDieEntity() { Faces = new List<NumberFaceEntity>() { numFace1Entity as NumberFaceEntity, numFace2Entity as NumberFaceEntity } };
(numFace1Entity as NumberFaceEntity).NumberDieEntity = (NumberDieEntity)numDieEntity;
(numFace2Entity as NumberFaceEntity).NumberDieEntity = (NumberDieEntity)numDieEntity;
clrDieEntity = new ColorDieEntity() { Faces = new List<ColorFaceEntity>() { clrFace1Entity as ColorFaceEntity, clrFace2Entity as ColorFaceEntity } };
(clrFace1Entity as ColorFaceEntity).ColorDieEntity = (ColorDieEntity)clrDieEntity;
(clrFace2Entity as ColorFaceEntity).ColorDieEntity = (ColorDieEntity)clrDieEntity;
imgDieEntity = new ImageDieEntity() { Faces = new List<ImageFaceEntity>() { imgFace1Entity as ImageFaceEntity, imgFace2Entity as ImageFaceEntity } };
(imgFace1Entity as ImageFaceEntity).ImageDieEntity = (ImageDieEntity)imgDieEntity;
(imgFace2Entity as ImageFaceEntity).ImageDieEntity = (ImageDieEntity)imgDieEntity;
}
[Fact]
public void TestToModel()
{
// Arrange
TurnEntity entity = new()
{
When = datetime1,
PlayerEntity = playerEntity,
Dice = new List<DieEntity>
{
numDieEntity,
clrDieEntity,
imgDieEntity
},
Faces = new List<FaceEntity>
{
numFace1Entity,
clrFace2Entity,
imgFace2Entity
}
};
Turn expected = Turn.CreateWithSpecifiedTime(
datetime1,
playerEntity.ToModel(),
new Dictionary<Die, Face>()
{
{(numDieEntity as NumberDieEntity).ToModel(), (numFace1Entity as NumberFaceEntity).ToModel() },
{(clrDieEntity as ColorDieEntity).ToModel(), (clrFace2Entity as ColorFaceEntity).ToModel() },
{(imgDieEntity as ImageDieEntity).ToModel(), (imgFace2Entity as ImageFaceEntity).ToModel() }
});
// Act
Turn actual = entity.ToModel();
// Assert
Assert.True(expected.Equals(actual));
}
[Fact]
public void TestToModels()
{
// Arrange
TurnEntity[] entities = new TurnEntity[]
{
new TurnEntity()
{
When = datetime1,
PlayerEntity = new PlayerEntity() {Name = "Aardvark"},
Dice = new List<DieEntity>
{
numDieEntity,
clrDieEntity
},
Faces = new List<FaceEntity>
{
numFace2Entity,
clrFace2Entity
}
},
new TurnEntity()
{
When = datetime2,
PlayerEntity = new PlayerEntity() {Name = "Chloe"},
Dice = new List<DieEntity>
{
clrDieEntity,
imgDieEntity
},
Faces = new List<FaceEntity>
{
clrFace1Entity,
imgFace1Entity
}
}
};
IEnumerable<Turn> expected = new Turn[]
{
Turn.CreateWithSpecifiedTime(
datetime1,
new("Aardvark"),
new Dictionary<Die, Face>()
{
{(numDieEntity as NumberDieEntity).ToModel(), (numFace2Entity as NumberFaceEntity).ToModel() },
{(clrDieEntity as ColorDieEntity).ToModel(), (clrFace2Entity as ColorFaceEntity).ToModel() },
}),
Turn.CreateWithSpecifiedTime(
datetime2,
new("Chloe"),
new Dictionary<Die, Face>()
{
{(clrDieEntity as ColorDieEntity).ToModel(), (clrFace1Entity as ColorFaceEntity).ToModel() },
{(imgDieEntity as ImageDieEntity).ToModel(), (imgFace1Entity as ImageFaceEntity).ToModel() }
})
}.AsEnumerable();
// Act
IEnumerable<Turn> actual = entities.ToModels();
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public void TestToEntity()
{
// Arrange
Turn model = Turn.CreateWithSpecifiedTime(
datetime1,
playerEntity.ToModel(),
new Dictionary<Die, Face>()
{
{(numDieEntity as NumberDieEntity).ToModel(), (numFace2Entity as NumberFaceEntity).ToModel() },
{(clrDieEntity as ColorDieEntity).ToModel(), (clrFace2Entity as ColorFaceEntity).ToModel() },
{(imgDieEntity as ImageDieEntity).ToModel(), (imgFace1Entity as ImageFaceEntity).ToModel() }
});
TurnEntity expected = new()
{
When = datetime1,
PlayerEntity = playerEntity,
Dice = new List<DieEntity>
{
numDieEntity,
clrDieEntity,
imgDieEntity
},
Faces = new List<FaceEntity>
{
numFace2Entity,
clrFace2Entity,
imgFace1Entity
}
};
// Act
TurnEntity actual = model.ToEntity();
// Assert
Assert.True(expected.Equals(actual));
}
[Fact]
public void TestToEntities()
{
// Arrange
Turn[] models = new Turn[]
{
Turn.CreateWithSpecifiedTime(
datetime2,
new("Mimi"),
new Dictionary<Die, Face>()
{
{(numDieEntity as NumberDieEntity).ToModel(), (numFace2Entity as NumberFaceEntity).ToModel() },
{(clrDieEntity as ColorDieEntity).ToModel(), (clrFace2Entity as ColorFaceEntity).ToModel() },
}),
Turn.CreateWithSpecifiedTime(
datetime1,
new("blaaargh"),
new Dictionary<Die, Face>()
{
{(clrDieEntity as ColorDieEntity).ToModel(), (clrFace1Entity as ColorFaceEntity).ToModel() },
{(imgDieEntity as ImageDieEntity).ToModel(), (imgFace1Entity as ImageFaceEntity).ToModel() }
})
};
IEnumerable<TurnEntity> expected = new TurnEntity[]
{
new TurnEntity()
{
When = datetime2,
PlayerEntity = new PlayerEntity() {Name = "Mimi"},
Dice = new List<DieEntity>
{
numDieEntity,
clrDieEntity
},
Faces = new List<FaceEntity>
{
numFace2Entity,
clrFace2Entity
}
},
new TurnEntity()
{
When = datetime1,
PlayerEntity = new PlayerEntity() {Name = "blaaargh"},
Dice = new List<DieEntity>
{
clrDieEntity,
imgDieEntity
},
Faces = new List<FaceEntity>
{
clrFace1Entity,
imgFace1Entity
}
}
}.AsEnumerable();
// Act
IEnumerable<TurnEntity> actual = models.ToEntities();
// Assert
Assert.Equal(expected, actual);
}
}
}

@ -1,688 +0,0 @@
using Data.EF;
using Data.EF.Players;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
namespace Tests.Data_UTs.Players
{
public class PlayerDbManagerTest
{
private readonly SqliteConnection connection = new("DataSource=:memory:");
private readonly DbContextOptions<DiceAppDbContext> options;
public PlayerDbManagerTest()
{
connection.Open();
options = new DbContextOptionsBuilder<DiceAppDbContext>()
.UseSqlite(connection)
.EnableSensitiveDataLogging()
.Options;
}
[Fact]
public async Task TestConstructorWhenGivenContextThenConstructs()
{
// Arrange
PlayerDbManager mgr;
// Act
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
// Assert
Assert.Equal(new Collection<PlayerEntity>(), await mgr.GetAll());
}
}
[Fact]
public void TestConstructorWhenGivenNullThrowsException()
{
// Arrange
PlayerDbManager mgr;
// Act
void action() => mgr = new PlayerDbManager(null);
// Assert
Assert.Throws<ArgumentNullException>(action);
}
[Fact]
public async Task TestAddWhenValidThenValid()
{
// Arrange
string expectedName = "Jeff";
int expectedCount = 2;
PlayerDbManager mgr;
// Act
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
await mgr.Add(new PlayerEntity() { Name = expectedName });
await mgr.Add(new PlayerEntity() { Name = "whatever" });
// mgr takes care of the SaveChange() calls internally
// we might use Units of Work later, to optimize our calls to DB
}
// Assert
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
Assert.Equal(expectedName, (await mgr.GetOneByName(expectedName)).Name);
Assert.Equal(expectedCount, (await mgr.GetAll()).Count);
}
}
[Fact]
public async Task TestAddWhenPreExistentThenException()
{
// Arrange
string name = "Flynt";
PlayerDbManager mgr;
// Act
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
await mgr.Add(new PlayerEntity() { Name = name });
async Task actionAsync() => await mgr.Add(new PlayerEntity() { Name = name });
// Assert
await Assert.ThrowsAsync<ArgumentException>(actionAsync);
}
}
[Fact]
public void TestAddWhenNullThenException()
{
// Arrange
PlayerDbManager mgr;
// Act
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
async Task actionAsync() => await mgr.Add(null);
// Assert
Assert.ThrowsAsync<ArgumentNullException>(actionAsync);
}
}
[Theory]
[InlineData(" ")]
[InlineData(null)]
[InlineData("")]
public void TestAddWhenInvalidNameThenException(string name)
{
// Arrange
PlayerDbManager mgr;
// Act
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
async Task actionAsync() => await mgr.Add(new PlayerEntity() { Name = name });
// Assert
Assert.ThrowsAsync<ArgumentException>(actionAsync);
}
}
[Theory]
[InlineData(" ")]
[InlineData(null)]
[InlineData("")]
public async Task TestGetOneByNameWhenInvalidThenException(string name)
{
// Arrange
PlayerDbManager mgr;
// Act
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
await mgr.Add(new() { Name = "Ernesto" });
await mgr.Add(new() { Name = "Basil" });
async Task actionAsync() => await mgr.GetOneByName(name);
// Assert
await Assert.ThrowsAsync<ArgumentException>(actionAsync);
}
}
[Theory]
[InlineData("Caroline")]
[InlineData("Caroline ")]
[InlineData(" Caroline")]
public async Task TestGetOneByNameWhenValidAndExistsThenGetsIt(string name)
{
// Arrange
PlayerDbManager mgr;
PlayerEntity actual;
PlayerEntity expected = new() { Name = name.Trim() };
// Act
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
await mgr.Add(expected);
await mgr.Add(new() { Name = "Philip" });
}
// Assert
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
actual = await mgr.GetOneByName(name);
Assert.Equal(expected, actual);
}
}
[Fact]
public async Task TestGetOneByNameWhenValidAndNotExistsThenException()
{
// Arrange
PlayerDbManager mgr;
// Act
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
//mgr.Add(expected);
await mgr.Add(new() { Name = "Brett" });
await mgr.Add(new() { Name = "Noah" });
async Task actionAsync() => await mgr.GetOneByName("*r^a*éàru é^à");
// Assert
await Assert.ThrowsAsync<InvalidOperationException>(actionAsync);
}
}
[Fact]
public async Task TestIsPresentByNameWhenValidAndExistsThenTrue()
{
// Arrange
PlayerDbManager mgr;
string name = "Gerald";
// Act
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
await mgr.Add(new() { Name = "Philip" });
await mgr.Add(new() { Name = name });
}
// Assert
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
Assert.True(await mgr.IsPresentByName(name));
}
}
[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData(null)]
[InlineData("nowaythatthisnameisalreadyinourdatabase")]
public async Task TestIsPresentByNameWhenInvalidOrNonExistentThenFalse(string name)
{
// Arrange
PlayerDbManager mgr;
// Act
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
await mgr.Add(new() { Name = "Herman" });
await mgr.Add(new() { Name = "Paulo" });
}
// Assert
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
Assert.False(await mgr.IsPresentByName(name));
}
}
[Fact]
public void TestRemoveWhenNullThenException()
{
// Arrange
PlayerDbManager mgr;
// Act
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
void action() => mgr.Remove(null);
// Assert
Assert.Throws<ArgumentNullException>(action);
}
}
[Fact]
public async Task TestRemoveWhenPreExistentThenRemoves()
{
// Arrange
PlayerDbManager mgr;
PlayerEntity toRemove = new() { ID = Guid.NewGuid(), Name = "Please!" };
// Act
using (DiceAppDbContextWithStub db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
await mgr.Add(toRemove); // calls SaveChangesAsync()
mgr.Remove(toRemove);
}
// Assert
using (DiceAppDbContextWithStub db = new(options))
{
db.Database.EnsureCreated();
Assert.DoesNotContain(toRemove, db.PlayerEntity);
}
}
[Fact]
public async Task TestRemoveWhenNonExistentThenStillNonExistent()
{
// Arrange
PlayerDbManager mgr;
PlayerEntity toRemove = new() { ID = Guid.NewGuid(), Name = "Filibert" };
// Act
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
await mgr.Add(new() { ID = Guid.NewGuid(), Name = "Bert" });
mgr.Remove(toRemove);
}
// Assert
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
Assert.DoesNotContain(toRemove, await mgr.GetAll());
}
}
[Theory]
[InlineData("filiBert")]
[InlineData("Bertrand")]
public async Task TestUpdateWhenValidThenUpdates(string name)
{
// Arrange
PlayerDbManager mgr;
Guid idBefore = Guid.NewGuid();
PlayerEntity before = new() { ID = idBefore, Name = "Filibert" };
PlayerEntity after = new() { ID = idBefore, Name = name };
// Act
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
await mgr.Add(before);
await mgr.Update(before, after);
}
// Assert
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
Assert.DoesNotContain(before, await mgr.GetAll());
Assert.Contains(after, await mgr.GetAll());
}
}
[Theory]
[InlineData("Valerie")]
[InlineData("Valerie ")]
[InlineData(" Valerie")]
public async Task TestUpdateWhenSameThenKeepsAndWorks(string name)
{
// Arrange
PlayerDbManager mgr;
string nameBefore = "Valerie";
Guid idBefore = Guid.NewGuid();
PlayerEntity before = new() { ID = idBefore, Name = nameBefore };
PlayerEntity after = new() { ID = idBefore, Name = name };
// Act
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
await mgr.Add(before);
await mgr.Update(before, after);
}
// Assert
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
Assert.Contains(before, await mgr.GetAll());
Assert.Contains(after, await mgr.GetAll());
}
}
[Fact]
public async Task TestUpdateWhenNewIDThenException()
{
// Arrange
PlayerDbManager mgr;
PlayerEntity before = new() { ID = Guid.NewGuid(), Name = "Nova" };
PlayerEntity after = new() { ID = Guid.NewGuid(), Name = "Jacquie" };
// Act
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
await mgr.Add(before);
async Task actionAsync() => await mgr.Update(before, after);
// Assert
await Assert.ThrowsAsync<ArgumentException>(actionAsync);
}
}
[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData(null)]
public async Task TestUpdateWhenInvalidThenException(string name)
{
// Arrange
PlayerDbManager mgr;
Guid id = Guid.NewGuid();
PlayerEntity before = new() { ID = id, Name = "Llanfair­pwll­gwyn­gyll­go­gery­chwyrn­drobwll­llan­tysilio­gogo­goch" };
PlayerEntity after = new() { ID = id, Name = name };
// Act
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
await mgr.Add(before);
async Task actionAsync() => await mgr.Update(before, after);
// Assert
await Assert.ThrowsAsync<ArgumentException>(actionAsync);
}
}
[Fact]
public async Task TestUpdateWhenNullThenException()
{
// Arrange
PlayerDbManager mgr;
PlayerEntity before = new() { ID = Guid.NewGuid(), Name = "Dwight" };
// Act
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
await mgr.Add(before);
async Task actionAsync() => await mgr.Update(before, null);
// Assert
await Assert.ThrowsAsync<ArgumentNullException>(actionAsync);
}
}
[Fact]
public async Task TestGetOneByIDWhenExistsThenGetsIt()
{
// Arrange
PlayerDbManager mgr;
Guid id = Guid.NewGuid();
PlayerEntity actual;
PlayerEntity expected = new() { ID = id, Name = "Hugh" };
// Act
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
await mgr.Add(expected);
}
// Assert
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
actual = await mgr.GetOneByID(id);
Assert.Equal(expected, actual);
}
}
[Fact]
public async Task TestGetOneByIDWhenNotExistsThenExceptionAsync()
{
// Arrange
PlayerDbManager mgr;
Guid id = Guid.NewGuid();
PlayerEntity expected = new() { ID = id, Name = "Kyle" };
Guid otherId = Guid.NewGuid();
// Act
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
await mgr.Add(expected);
async Task actionAsync() => await mgr.GetOneByID(otherId);
// Assert
await Assert.ThrowsAsync<InvalidOperationException>(actionAsync);
}
}
[Fact]
public async Task TestIsPresentbyIdWhenExistsThenTrue()
{
// Arrange
PlayerDbManager mgr;
Guid id = Guid.NewGuid();
// Act
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
await mgr.Add(new() { ID = id, Name = "Bobby" });
}
// Assert
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
Assert.True(await mgr.IsPresentByID(id));
}
}
[Fact]
public async Task TestIsPresentbyIdWhenNotExistsThenFalse()
{
// Arrange
PlayerDbManager mgr;
Guid id = Guid.NewGuid();
Guid otherId;
PlayerEntity presentEntity;
// Act
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
presentEntity = new() { ID = id, Name = "Victor" };
await mgr.Add(presentEntity);
otherId = Guid.NewGuid();
// not added
}
// Assert
using (DiceAppDbContext db = new(options))
{
db.Database.EnsureCreated();
mgr = new(db);
Assert.False(await mgr.IsPresentByID(otherId));
}
}
}
}

@ -1,6 +1,12 @@
using Data.EF.Players;
using Model.Players;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
using Data.EF.Players;
using Tests.Model_UTs;
namespace Tests.Data_UTs.Players
{
@ -26,7 +32,7 @@ namespace Tests.Data_UTs.Players
{
// Arrange
PlayerEntity player = new();
Guid expected = Guid.NewGuid();
Guid expected = new("c8f60957-dd36-4e47-a7ce-1281f4f8bea4");
// Act
player.ID = expected;
@ -106,16 +112,10 @@ namespace Tests.Data_UTs.Players
PlayerEntity p2;
PlayerEntity p3;
Guid id1 = Guid.NewGuid();
Guid id2 = Guid.NewGuid();
string name1 = "Panama";
string name2 = "Clyde";
// Act
p1 = new() { ID = id1, Name = name1 };
p2 = new() { ID = id1, Name = name2 };
p3 = new() { ID = id2, Name = name2 };
p1 = new() { ID = new Guid("ae04ef10-bd25-4f4e-b4c1-4860fe3daaa0"), Name = "Panama" };
p2 = new() { ID = new Guid("ae04ef10-bd25-4f4e-b4c1-4860fe3daaa0"), Name = "Clyde" };
p3 = new() { ID = new Guid("846d332f-56ca-44fc-8170-6cfd28dab88b"), Name = "Clyde" };
// Assert
Assert.False(p1.Equals(p2));
@ -132,12 +132,10 @@ namespace Tests.Data_UTs.Players
// Arrange
PlayerEntity p1;
PlayerEntity p2;
Guid id = Guid.NewGuid();
string name = "Marley";
// Act
p1 = new() { ID = id, Name = name };
p2 = new() { ID = id, Name = name };
p1 = new() { ID = new Guid("ae04ef10-bd25-4f4e-b4c1-4860fe3daaa0"), Name = "Marley" };
p2 = new() { ID = new Guid("ae04ef10-bd25-4f4e-b4c1-4860fe3daaa0"), Name = "Marley" };
// Assert
Assert.True(p1.Equals(p2));
@ -152,16 +150,10 @@ namespace Tests.Data_UTs.Players
PlayerEntity p2;
PlayerEntity p3;
Guid id1 = Guid.NewGuid();
Guid id2 = Guid.NewGuid();
string name1 = "Panama";
string name2 = "Clyde";
// Act
p1 = new() { ID = id1, Name = name1 };
p2 = new() { ID = id1, Name = name2 };
p3 = new() { ID = id2, Name = name2 };
p1 = new() { ID = new Guid("ae04ef10-bd25-4f4e-b4c1-4860fe3daaa0"), Name = "Panama" };
p2 = new() { ID = new Guid("ae04ef10-bd25-4f4e-b4c1-4860fe3daaa0"), Name = "Clyde" };
p3 = new() { ID = new Guid("846d332f-56ca-44fc-8170-6cfd28dab88b"), Name = "Clyde" };
// Assert
Assert.False(p1.GetHashCode().Equals(p2.GetHashCode()));
@ -178,12 +170,10 @@ namespace Tests.Data_UTs.Players
// Arrange
PlayerEntity p1;
PlayerEntity p2;
Guid id = Guid.NewGuid();
string name = "Marley";
// Act
p1 = new() { ID = id, Name = name };
p2 = new() { ID = id, Name = name };
p1 = new() { ID = new Guid("ae04ef10-bd25-4f4e-b4c1-4860fe3daaa0"), Name = "Marley" };
p2 = new() { ID = new Guid("ae04ef10-bd25-4f4e-b4c1-4860fe3daaa0"), Name = "Marley" };
// Assert
Assert.True(p1.GetHashCode().Equals(p2.GetHashCode()));

@ -1,7 +1,10 @@
using Data.EF.Players;
using Model.Players;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
namespace Tests.Data_UTs.Players

@ -1,51 +0,0 @@
using Model.Dice.Faces;
using Model.Dice;
using System.Collections.Generic;
using System.Drawing;
using Xunit;
namespace Tests.Model_UTs.Dice
{
public class ColorDieTest
{
public static IEnumerable<object[]> Data_Uri()
{
yield return new object[]
{
new ColorFace(Color.FromName("Chocolate")),
new ColorFace(Color.FromName("Aqua")),
new ColorFace(Color.FromName("Beige")),
new ColorFace(Color.FromName("Black")),
new ColorFace(Color.FromName("BurlyWood")),
};
}
[Theory]
[MemberData(nameof(Data_Uri))]
public void RndmFaceTest(ColorFace f1, ColorFace f2, ColorFace f3, ColorFace f4, ColorFace f5)
{
//Arrange
List<ColorFace> listFaces = new() {
f1,f2,f3,f4,f5
};
ColorDie die = new(
listFaces[1],
listFaces[2],
listFaces[3],
listFaces[4]
);
//Act
ColorFace actual = (ColorFace)die.GetRandomFace();
//Assert
Assert.Contains(listFaces, face => face == actual);
}
}
}

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tests.Model_UTs.Dice
{
public class DiceGroupManagerTest
{
}
}

@ -1,70 +0,0 @@
using Model.Dice.Faces;
using System.Collections.Generic;
using System.Drawing;
using Xunit;
namespace Tests.Model_UTs.Dice.Faces
{
public class ColorFaceTest
{
public static IEnumerable<object[]> Data_Colors()
{
yield return new object[]
{
Color.FromName("Chocolate"),
Color.FromArgb(144, 255, 78, 240),
};
yield return new object[]
{
Color.FromName("Chocolate"),
Color.FromArgb(144, 255, 78, 240),
};
}
[Theory]
[MemberData(nameof(Data_Colors))]
public void ColorFaceValueTest(Color clrA, Color clrB)
{
//Arrage
ColorFace face1 = new(clrA);
ColorFace face2 = new(clrB);
//Act
Color expected1 = clrA;
Color actual1 = face1.Value;
Color expected2 = clrB;
Color actual2 = face2.Value;
//Assert
Assert.Equal(expected1, actual1);
Assert.Equal(expected2, actual2);
}
[Theory]
[MemberData(nameof(Data_Colors))]
public void ColorFaceValueToStringTest(Color clrA, Color clrB)
{
//Arrage
ColorFace face1 = new(clrA);
ColorFace face2 = new(clrB);
//Act
string expected1 = clrA.ToString();
string actual1 = face1.StringValue;
string expected2 = clrB.ToString();
string actual2 = face2.StringValue;
//Assert
Assert.Equal(expected1, actual1);
Assert.Equal(expected2, actual2);
}
}
}

@ -1,70 +0,0 @@
using Model.Dice.Faces;
using System;
using System.Collections.Generic;
using Xunit;
namespace Tests.Model_UTs.Dice.Faces
{
public class ImageFaceTest
{
public static IEnumerable<object[]> Data_Colors()
{
yield return new object[]
{
new Uri("http://www.contoso.com/"),
new Uri("https://www.pedagojeux.fr/wp-content/uploads/2019/11/1280x720_LoL.jpg"),
};
yield return new object[]
{
new Uri("https://www.lacremedugaming.fr/wp-content/uploads/creme-gaming/2022/02/media-13411.jpg"),
new Uri("https://i1.moyens.net/io/images/2022/01/1642321015_Mises-a-jour-de-VALORANT-en-melee-a-venir-dans.jpg"),
};
}
[Theory]
[MemberData(nameof(Data_Colors))]
public void ImageFaceValueTest(Uri uriA, Uri uriB)
{
//Arrage
ImageFace face1 = new(uriA);
ImageFace face2 = new(uriB);
//Act
Uri expected1 = uriA;
Uri actual1 = face1.Value;
Uri expected2 = uriB;
Uri actual2 = face2.Value;
//Assert
Assert.Equal(expected1, actual1);
Assert.Equal(expected2, actual2);
}
[Theory]
[MemberData(nameof(Data_Colors))]
public void ImageFaceValueToStringTest(Uri uriA, Uri uriB)
{
//Arrage
ImageFace face1 = new(uriA);
ImageFace face2 = new(uriB);
//Act
string expected1 = uriA.ToString();
string actual1 = face1.StringValue;
string expected2 = uriB.ToString();
string actual2 = face2.StringValue;
//Assert
Assert.Equal(expected1, actual1);
Assert.Equal(expected2, actual2);
}
}
}

@ -1,51 +0,0 @@
using Model.Dice.Faces;
using Xunit;
namespace Tests.Model_UTs.Dice.Faces
{
public class NumberFaceTest
{
[Fact]
public void NumberFaceValueTest()
{
//Arrage
NumberFace face1 = new NumberFace(3);
NumberFace face2 = new NumberFace(5);
//Act
int expected1 = 3;
int actual1 = face1.Value;
int expected2 = 5;
int actual2 = face2.Value;
//Assert
Assert.Equal(expected1, actual1);
Assert.Equal(expected2, actual2);
}
[Fact]
public void NumberFaceValueToStringTest()
{
//Arrage
NumberFace face1 = new(3);
NumberFace face2 = new(5);
//Act
string expected1 = 3.ToString();
string actual1 = face1.StringValue;
string expected2 = 5.ToString();
string actual2 = face2.StringValue;
//Assert
Assert.Equal(expected1, actual1);
Assert.Equal(expected2, actual2);
}
}
}

@ -1,53 +0,0 @@
using Model.Dice.Faces;
using Model.Dice;
using System;
using System.Collections.Generic;
using Xunit;
namespace Tests.Model_UTs.Dice
{
public class ImageDieTest
{
public static IEnumerable<object[]> Data_Uri()
{
yield return new object[]
{
new ImageFace(new Uri("https://nothing1/")),
new ImageFace(new Uri("https://nothing2/")),
new ImageFace(new Uri("https://nothing3/")),
new ImageFace(new Uri("https://nothing4/")),
new ImageFace(new Uri("https://nothing5/")),
};
}
[Theory]
[MemberData(nameof(Data_Uri))]
public void RndmFaceTest(ImageFace f1, ImageFace f2, ImageFace f3, ImageFace f4, ImageFace f5)
{
//Arrange
List<ImageFace> listFaces = new() {
f1,f2,f3,f4,f5
};
ImageDie die = new(
listFaces[1],
listFaces[2],
listFaces[3],
listFaces[4]
);
//Act
ImageFace actual = (ImageFace)die.GetRandomFace();
//Assert
Assert.Contains(listFaces, face => face == actual);
}
}
}

@ -1,41 +0,0 @@
using Model.Dice;
using Model.Dice.Faces;
using System.Collections.Generic;
using Xunit;
namespace Tests.Model_UTs.Dice
{
public class NumberDieTest
{
[Fact]
public void RndmFaceTest()
{
//Arrange
List<NumberFace> listFaces = new() {
new NumberFace(1),
new NumberFace(2),
new NumberFace(3),
new NumberFace(4),
new NumberFace(5),
};
NumberDie die = new(
listFaces[1],
listFaces[2],
listFaces[3],
listFaces[4]
);
//Act
NumberFace actual = (NumberFace)die.GetRandomFace();
//Assert
Assert.Contains(listFaces, face => face == actual);
}
}
}

@ -1,282 +0,0 @@
using Data;
using Model;
using Model.Dice;
using Model.Games;
using Model.Players;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tests.Data_UTs.Games;
using Xunit;
namespace Tests.Model_UTs.Games
{
public class GameManagerTest
{
private readonly MasterOfCeremonies stubGameRunner = new Stub().LoadApp()?.Result;
[Fact]
public async Task TestConstructorReturnsEmptyEnumerableAsync()
{
// Arrange
GameManager gm = new();
IEnumerable<Game> expected;
IEnumerable<Game> actual;
// Act
expected = new Collection<Game>();
actual = await gm.GetAll();
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public async Task TestAddWhenGamesThenDoAddAndReturnGamesAsync()
{
// Arrange
GameManager gm = new();
Game game1 = (await stubGameRunner.GameManager.GetAll()).First();
Game game2 = (await stubGameRunner.GameManager.GetAll()).Last();
// Act
IEnumerable<Game> expected = new List<Game>() { game1, game2 }.AsEnumerable();
IEnumerable<Game> actual = new List<Game>()
{
await gm.Add(game1),
await gm.Add(game2)
};
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public async Task TestAddWhenNullThenThrowsException()
{
// Arrange
GameManager gm = new();
// Act
async Task actionAsync() => await gm.Add(null);// Add() returns the added element if succesful
// Assert
await Assert.ThrowsAsync<ArgumentNullException>(actionAsync);
Assert.DoesNotContain(null, await stubGameRunner.GameManager.GetAll());
}
[Fact]
public void TestGetOneByIdThrowsException()
{
// Arrange
GameManager gm = new();
// Act
void action() => gm.GetOneByID(Guid.NewGuid());
// Assert
Assert.Throws<NotImplementedException>(action);
}
[Theory]
[InlineData("")]
[InlineData(null)]
[InlineData(" ")]
public async Task TestGetOneByNameWhenInvalidThenThrowsExceptionAsync(string name)
{
// Arrange
GameManager gm = new();
// Act
async Task actionAsync() => await gm.GetOneByName(name);
// Assert
await Assert.ThrowsAsync<ArgumentException>(actionAsync);
}
[Fact]
public async Task TestGetOneByNameWhenValidButNotExistThenReturnNullAsync()
{
// Arrange
GameManager gm = new();
// Act
Game result = await gm.GetOneByName("thereisbasicallynowaythatthisgamenamealreadyexists");
// Assert
Assert.Null(result);
}
[Fact]
public async Task TestGetOneByNameWhenValidThenReturnGameAsync()
{
// Arrange
GameManager gm = new();
Game game = (await stubGameRunner.GameManager.GetAll()).First();
// Act
Game actual = await gm.Add(game);
Game expected = game;
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public async Task TestWhenRemoveExistsThenSucceeds()
{
// Arrange
GameManager gm = new();
Game game = new("blargh", new PlayerManager(), (await stubGameRunner.GameManager.GetAll()).First().Dice);
await gm.Add(game);
// Act
gm.Remove(game);
// Assert
Assert.DoesNotContain(game, await gm.GetAll());
}
[Fact]
public void TestRemoveWhenGivenNullThenThrowsException()
{
// Arrange
GameManager gm = new();
// Act
void action() => gm.Remove(null);
// Assert
Assert.Throws<ArgumentNullException>(action);
}
[Fact]
public async Task TestRemoveWhenGivenNonExistentThenFailsSilentlyAsync()
{
// Arrange
IManager<Game> gm = stubGameRunner.GameManager;
Game notGame = new("blargh", new PlayerManager(), (await stubGameRunner.GameManager.GetAll()).First().Dice);
IEnumerable<Game> expected = await stubGameRunner.GameManager.GetAll();
// Act
gm.Remove(notGame);
IEnumerable<Game> actual = await gm.GetAll();
// Assert
Assert.Equal(actual, expected);
}
[Fact]
public async Task TestUpdateWhenValidThenSucceeds()
{
// Arrange
GameManager gm = new();
string oldName = "blargh";
string newName = "blargh2.0";
Game game = new(oldName, new PlayerManager(), (await stubGameRunner.GameManager.GetAll()).First().Dice);
await game.PlayerManager.Add(new("Alice"));
await gm.Add(game);
Game oldGame = (await gm.GetAll()).First();
Game newGame = new(newName, oldGame.PlayerManager, oldGame.Dice);
// Act
int expectedSize = (await gm.GetAll()).Count;
await gm.Update(oldGame, newGame);
int actualSize = (await gm.GetAll()).Count;
// Assert
Assert.NotEqual(oldName, newName);
Assert.DoesNotContain(oldGame, await gm.GetAll());
Assert.Contains(newGame, await gm.GetAll());
Assert.Equal(expectedSize, actualSize);
}
[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData(null)]
public async Task TestUpdateWhenValidBeforeAndInvalidAfterThenDoesNotGoAsync(string badName)
{
// Arrange
IManager<Game> gm = stubGameRunner.GameManager;
int expectedSize = (await gm.GetAll()).Count;
Game oldGame = (await gm.GetAll()).First();
// Act
void action() => gm.Update(oldGame, new(badName, oldGame.PlayerManager, oldGame.Dice));
int actualSize = (await gm.GetAll()).Count;
// Assert
Assert.Throws<ArgumentException>(action); // thrown by constructor
Assert.Contains(oldGame, await gm.GetAll()); // still there
Assert.Equal(expectedSize, actualSize);
}
[Fact]
public async Task TestUpdateWhenValidBeforeAndNullAfterThenDoesNotGoAsync()
{
// Arrange
IManager<Game> gm = stubGameRunner.GameManager;
int expectedSize = (await gm.GetAll()).Count;
Game oldGame = (await gm.GetAll()).First();
// Act
async Task actionAsync() => await gm.Update(oldGame, null);
int actualSize = (await gm.GetAll()).Count;
// Assert
await Assert.ThrowsAsync<ArgumentNullException>(actionAsync); // thrown by constructor
Assert.Contains(oldGame, await gm.GetAll()); // still there
Assert.True(expectedSize == actualSize);
}
[Fact]
public async Task TestUpdateDoesNotGoWithValidAfterAndNullBefore()
{
// Arrange
IManager<Game> gm = stubGameRunner.GameManager;
int expectedSize = (await gm.GetAll()).Count;
Game oldGame = (await gm.GetAll()).First();
// Act
async Task actionAsync() => await gm.Update(null, new("newgamename", oldGame.PlayerManager, oldGame.Dice));
int actualSize = (await gm.GetAll()).Count;
// Assert
await Assert.ThrowsAsync<ArgumentNullException>(actionAsync); // thrown by constructor
Assert.Contains(oldGame, await gm.GetAll()); // still there
Assert.True(expectedSize == actualSize);
}
[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData(null)]
public async Task TestUpdateWhenInvalidBeforeAndValidAfterThenDoesNotGoAsync(string badName)
{
// Arrange
IManager<Game> gm = stubGameRunner.GameManager;
int expectedSize = (await gm.GetAll()).Count;
Game oldGame = (await gm.GetAll()).First();
// Act
void action() => gm.Update(new(badName, oldGame.PlayerManager, oldGame.Dice), new("valid", oldGame.PlayerManager, oldGame.Dice));
int actualSize = (await gm.GetAll()).Count;
// Assert
Assert.Throws<ArgumentException>(action); // thrown by constructor
Assert.Contains(oldGame, await gm.GetAll()); // still there
Assert.True(expectedSize == actualSize);
}
}
}

@ -0,0 +1,307 @@
using Model;
using Model.Dice;
using Model.Dice.Faces;
using Model.Games;
using Model.Players;
using System;
using System.Collections.Generic;
using System.Linq;
using Xunit;
using Data;
namespace Tests.Model_UTs.Games
{
public class GameRunnerTest
{
private readonly GameRunner stubGameRunner = new Stub().LoadApp();
[Fact]
public void TestConstructorWhenNoGamesThenNewIEnumerable()
{
// Arrange
GameRunner gameRunner = new(new PlayerManager(), new DieManager());
IEnumerable<Game> expected;
IEnumerable<Game> actual;
// Act
expected = new List<Game>().AsEnumerable();
actual = gameRunner.GetAll();
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public void TestConstructorWhenGamesThenGamesIEnumerable()
{
// Arrange
GameRunner gameRunner = new(new PlayerManager(), new DieManager(), stubGameRunner.GetAll().ToList());
IEnumerable<Game> expected;
IEnumerable<Game> actual;
// Act
expected = stubGameRunner.GetAll();
actual = gameRunner.GetAll();
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public void TestAddWhenGamesThenDoAddAndReturnGames()
{
// Arrange
GameRunner gameRunner = new(new PlayerManager(), new DieManager());
Game game1 = stubGameRunner.GetAll().First();
Game game2 = stubGameRunner.GetAll().Last();
// Act
IEnumerable<Game> expected = new List<Game>() { game1, game2 }.AsEnumerable();
IEnumerable<Game> actual = new List<Game>()
{
gameRunner.Add(game1),
gameRunner.Add(game2)
};
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public void TestAddWhenNullThenThrowsException()
{
// Arrange
GameRunner gameRunner = stubGameRunner;
// Act
void action() => gameRunner.Add(null);// Add() returns the added element if succesful
// Assert
Assert.Throws<ArgumentNullException>(action);
Assert.DoesNotContain(null, stubGameRunner.GetAll());
}
[Theory]
[InlineData("")]
[InlineData(null)]
[InlineData(" ")]
public void TestGetOneByNameWhenInvalidThenThrowsException(string name)
{
// Arrange
GameRunner gameRunner = stubGameRunner;
// Act
void action() => gameRunner.GetOneByName(name);
// Assert
Assert.Throws<ArgumentException>(action);
}
[Fact]
public void TestGetOneByNameWhenValidButNotExistThenReturnNull()
{
// Arrange
GameRunner gameRunner = stubGameRunner;
// Act
Game result = gameRunner.GetOneByName("thereisbasicallynowaythatthisgamenamealreadyexists");
// Assert
Assert.Null(result);
}
[Fact]
public void TestGetOneByNameWhenValidThenReturnGame()
{
// Arrange
GameRunner gameRunner = new(new PlayerManager(), new DieManager());
Game game = stubGameRunner.GetAll().First();
// Act
Game actual = gameRunner.Add(game);
Game expected = game;
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public void TestWhenRemoveExistsThenSucceeds()
{
// Arrange
GameRunner gameRunner = stubGameRunner;
Game game = new("blargh", new PlayerManager(), gameRunner.GetAll().First().Dice);
gameRunner.Add(game);
// Act
gameRunner.Remove(game);
// Assert
Assert.DoesNotContain(game, gameRunner.GetAll());
}
[Fact]
public void TestRemoveWhenGivenNullThenThrowsException()
{
// Arrange
GameRunner gameRunner = stubGameRunner;
// Act
void action() => gameRunner.Remove(null);
// Assert
Assert.Throws<ArgumentNullException>(action);
}
[Fact]
public void TestRemoveWhenGiveenNonExistentThenFailsSilently()
{
// Arrange
GameRunner gameRunner = stubGameRunner;
Game notGame = new("blargh", new PlayerManager(), gameRunner.GetAll().First().Dice);
IEnumerable<Game> expected = gameRunner.GetAll();
// Act
gameRunner.Remove(notGame);
IEnumerable<Game> actual = gameRunner.GetAll();
// Assert
Assert.Equal(actual, expected);
}
[Fact]
public void TestUpdateWhenValidThenSucceeds()
{
// Arrange
string oldName = "blargh";
string newName = "blargh2.0";
GameRunner gameRunner = new(new PlayerManager(), new DieManager());
Game game = new(oldName, new PlayerManager(), stubGameRunner.GetAll().First().Dice);
game.PlayerManager.Add(new("Alice"));
gameRunner.Add(game);
Game oldGame = gameRunner.GetAll().First();
Game newGame = new(newName, oldGame.PlayerManager, oldGame.Dice);
// Act
int oldSize = gameRunner.GetAll().Count();
gameRunner.Update(oldGame, newGame);
int newSize = gameRunner.GetAll().Count();
// Assert
Assert.NotEqual(oldName, newName);
Assert.DoesNotContain(oldGame, gameRunner.GetAll());
Assert.Contains(newGame, gameRunner.GetAll());
Assert.Equal(oldSize, newSize);
}
[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData(null)]
public void TestUpdateWhenValidBeforeAndInvalidAfterThenDoesNotGo(string badName)
{
// Arrange
GameRunner gameRunner = stubGameRunner;
int expectedSize = gameRunner.GetAll().Count();
Game oldGame = gameRunner.GetAll().First();
// Act
void action() => gameRunner.Update(oldGame, new(badName, oldGame.PlayerManager, oldGame.Dice));
int actualSize = gameRunner.GetAll().Count();
// Assert
Assert.Throws<ArgumentException>(action); // thrown by constructor
Assert.Contains(oldGame, gameRunner.GetAll()); // still there
Assert.True(expectedSize == actualSize);
}
[Fact]
public void TestUpdateWhenValidBeforeAndNullAfterThenDoesNotGo()
{
// Arrange
GameRunner gameRunner = stubGameRunner;
int expectedSize = gameRunner.GetAll().Count();
Game oldGame = gameRunner.GetAll().First();
// Act
void action() => gameRunner.Update(oldGame, null);
int actualSize = gameRunner.GetAll().Count();
// Assert
Assert.Throws<ArgumentNullException>(action); // thrown by constructor
Assert.Contains(oldGame, gameRunner.GetAll()); // still there
Assert.True(expectedSize == actualSize);
}
[Fact]
public void TestUpdateDoesNotGoWithValidAfterAndNullBefore()
{
// Arrange
GameRunner gameRunner = stubGameRunner;
int expectedSize = gameRunner.GetAll().Count();
Game oldGame = gameRunner.GetAll().First();
// Act
void action() => gameRunner.Update(null, new("newgamename", oldGame.PlayerManager, oldGame.Dice));
int actualSize = gameRunner.GetAll().Count();
// Assert
Assert.Throws<ArgumentNullException>(action); // thrown by constructor
Assert.Contains(oldGame, gameRunner.GetAll()); // still there
Assert.True(expectedSize == actualSize);
}
[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData(null)]
public void TestUpdateWhenInvalidBeforeAndValidAfterThenDoesNotGo(string badName)
{
// Arrange
GameRunner gameRunner = stubGameRunner;
int expectedSize = gameRunner.GetAll().Count();
Game oldGame = gameRunner.GetAll().First();
// Act
void action() => gameRunner.Update(new(badName, oldGame.PlayerManager, oldGame.Dice), new("valid", oldGame.PlayerManager, oldGame.Dice));
int actualSize = gameRunner.GetAll().Count();
// Assert
Assert.Throws<ArgumentException>(action); // thrown by constructor
Assert.Contains(oldGame, gameRunner.GetAll()); // still there
Assert.True(expectedSize == actualSize);
}
[Fact]
public void TestPlayGameWhenPlayThenAddNewTurnToHistory()
{
// Arrange
GameRunner gameRunner = stubGameRunner;
Game game = gameRunner.GetAll().First();
// Act
int turnsBefore = game.GetHistory().Count();
GameRunner.PlayGame(game);
int turnsAfter = game.GetHistory().Count();
// Assert
Assert.Equal(turnsBefore + 1, turnsAfter);
}
[Fact]
public void TestStartNewGame()
{
// Arrange
GameRunner gameRunner = stubGameRunner;
string name = "blargh";
// Act
Assert.DoesNotContain(gameRunner.GetOneByName(name), gameRunner.GetAll());
gameRunner.StartNewGame(name, new PlayerManager(), stubGameRunner.GetAll().First().Dice);
// Assert
Assert.Contains(gameRunner.GetOneByName(name), gameRunner.GetAll());
}
}
}

@ -5,26 +5,27 @@ using Model.Games;
using Model.Players;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
namespace Tests.Model_UTs.Games
{
public class GameTest
{
private readonly MasterOfCeremonies stubMasterOfCeremonies = new Stub().LoadApp()?.Result;
private readonly GameRunner stubGameRunner = new Stub().LoadApp();
private static readonly string GAME_NAME = "my game";
private static readonly Player PLAYER_1 = new("Alice"), PLAYER_2 = new("Bob"), PLAYER_3 = new("Clyde");
private readonly IEnumerable<Die> DICE_1, DICE_2;
public GameTest()
{
IEnumerable<DiceGroup> diceGroups = stubMasterOfCeremonies.DiceGroupManager.GetAll()?.Result;
DICE_1 = diceGroups.First().Dice;
DICE_2 = diceGroups.Last().Dice;
DICE_1 = stubGameRunner.GlobalDieManager.GetAll().First().Value;
DICE_2 = stubGameRunner.GlobalDieManager.GetAll().Last().Value;
}
[Fact]
public void TestNamePropertyGet()
{
@ -77,17 +78,13 @@ namespace Tests.Model_UTs.Games
}
[Fact]
public async Task TestGetHistory()
public void TestGetHistory()
{
// Arrange
IEnumerable<KeyValuePair<Die, Face>> diceNFaces =
(await stubMasterOfCeremonies.GameManager.GetAll())
.First()
.GetHistory()
.First().DiceNFaces;
Dictionary<Die, Face> diceNFaces = (Dictionary<Die, Face>)stubGameRunner.GetAll().First().GetHistory().First().DiceNFaces;
Turn turn1 = Turn.CreateWithSpecifiedTime(new(1, 2, 3), PLAYER_1, diceNFaces);
Turn turn2 = Turn.CreateWithSpecifiedTime(new(1, 2, 3), PLAYER_2, diceNFaces); // yeah they rolled the same
Turn turn1 = Turn.CreateWithDefaultTime(PLAYER_1, diceNFaces);
Turn turn2 = Turn.CreateWithDefaultTime(PLAYER_2, diceNFaces); // yeah they rolled the same
IEnumerable<Turn> expected = new List<Turn>() { turn1, turn2 };
@ -121,28 +118,30 @@ namespace Tests.Model_UTs.Games
}
[Fact]
public async Task TestPerformTurnDoesAddOneTurnAsync()
public void TestPerformTurnDoesAddOneTurn()
{
// Arrange
Game game = new(name: GAME_NAME,
playerManager: new PlayerManager(),
dice: DICE_1);
await game.PlayerManager.Add(PLAYER_1);
await game.PlayerManager.Add(PLAYER_2);
game.PlayerManager.Add(PLAYER_1);
game.PlayerManager.Add(PLAYER_2);
int n = 5;
Player currentPlayer;
for (int i = 0; i < n; i++)
{
currentPlayer = await game.GetWhoPlaysNow();
currentPlayer = game.GetWhoPlaysNow();
game.PerformTurn(currentPlayer);
await game.PrepareNextPlayer(currentPlayer);
game.PrepareNextPlayer(currentPlayer);
}
Debug.WriteLine(game);
// Act
int actual = game.GetHistory().Count;
int actual = game.GetHistory().Count();
int expected = n;
// Assert
@ -150,23 +149,23 @@ namespace Tests.Model_UTs.Games
}
[Fact]
public async Task TestGetWhoPlaysNowWhenValidThenCorrectAsync()
public void TestGetWhoPlaysNowWhenValidThenCorrect()
{
// Arrange
Game game = new(name: GAME_NAME,
playerManager: new PlayerManager(),
dice: DICE_1);
await game.PlayerManager.Add(PLAYER_1);
await game.PlayerManager.Add(PLAYER_2);
game.PlayerManager.Add(PLAYER_1);
game.PlayerManager.Add(PLAYER_2);
// Act
Player actual = await game.GetWhoPlaysNow();
Player actual = game.GetWhoPlaysNow();
Player expected = PLAYER_1;
await game.PrepareNextPlayer(actual);
game.PrepareNextPlayer(actual);
Player actual2 = await game.GetWhoPlaysNow();
Player actual2 = game.GetWhoPlaysNow();
Player expected2 = PLAYER_2;
// Assert
@ -184,10 +183,10 @@ namespace Tests.Model_UTs.Games
dice: DICE_1);
// Act
async Task actionAsync() => await game.GetWhoPlaysNow(); // on an empty collection of players
void action() => game.GetWhoPlaysNow(); // on an empty collection of players
// Assert
Assert.ThrowsAsync<MemberAccessException>(actionAsync);
Assert.Throws<MemberAccessException>(action);
}
[Fact]
@ -198,10 +197,10 @@ namespace Tests.Model_UTs.Games
playerManager: new PlayerManager(),
dice: DICE_1);
// Act
async Task actionAsync() => await game.PrepareNextPlayer(PLAYER_1); // on an empty collection of players
void action() => game.PrepareNextPlayer(PLAYER_1); // on an empty collection of players
// Assert
Assert.ThrowsAsync<MemberAccessException>(actionAsync);
Assert.Throws<MemberAccessException>(action);
}
[Fact]
@ -215,10 +214,10 @@ namespace Tests.Model_UTs.Games
game.PlayerManager.Add(PLAYER_1);
// Act
async Task actionAsync() => await game.PrepareNextPlayer(null);
void action() => game.PrepareNextPlayer(null);
// Assert
Assert.ThrowsAsync<ArgumentNullException>(actionAsync);
Assert.Throws<ArgumentNullException>(action);
}
[Fact]
@ -232,59 +231,59 @@ namespace Tests.Model_UTs.Games
game.PlayerManager.Add(PLAYER_2);
// Act
async Task actionAsync() => await game.PrepareNextPlayer(PLAYER_3);
void action() => game.PrepareNextPlayer(PLAYER_3);
// Assert
Assert.ThrowsAsync<ArgumentException>(actionAsync);
Assert.Throws<ArgumentException>(action);
}
[Fact]
public async Task TestPrepareNextPlayerWhenValidThenCorrectWithSeveralPlayersAsync()
public void TestPrepareNextPlayerWhenValidThenCorrectWithSeveralPlayers()
{
// Arrange
Game game = new(name: GAME_NAME,
playerManager: new PlayerManager(),
dice: DICE_2);
await game.PlayerManager.Add(PLAYER_1);
await game.PlayerManager.Add(PLAYER_2);
game.PlayerManager.Add(PLAYER_1);
game.PlayerManager.Add(PLAYER_2);
// Act
Player expected = PLAYER_2;
Assert.Equal(PLAYER_1, await game.GetWhoPlaysNow());
await game.PrepareNextPlayer(PLAYER_1);
Assert.Equal(PLAYER_1, game.GetWhoPlaysNow());
game.PrepareNextPlayer(PLAYER_1);
Player actual = await game.GetWhoPlaysNow();
Player actual = game.GetWhoPlaysNow();
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public async Task TestPrepareNextPlayerWhenValidThenCorrectWithOnePlayerAsync()
public void TestPrepareNextPlayerWhenValidThenCorrectWithOnePlayer()
{
// Arrange
Game game = new(name: GAME_NAME,
playerManager: new PlayerManager(),
dice: DICE_1);
await game.PlayerManager.Add(PLAYER_1);
game.PlayerManager.Add(PLAYER_1);
// Act
Player expected = PLAYER_1;
Assert.Equal(PLAYER_1, await game.GetWhoPlaysNow());
await game.PrepareNextPlayer(PLAYER_1);
Assert.Equal(PLAYER_1, game.GetWhoPlaysNow());
game.PrepareNextPlayer(PLAYER_1);
Player actual = await game.GetWhoPlaysNow();
Player actual = game.GetWhoPlaysNow();
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public async Task TestAddPlayerToGameAsync()
public void TestAddPlayerToGame()
{
// Arrange
Game game = new(name: GAME_NAME,
@ -293,14 +292,14 @@ namespace Tests.Model_UTs.Games
// Act
Player expected = PLAYER_1;
Player actual = await game.PlayerManager.Add(PLAYER_1);
Player actual = game.PlayerManager.Add(PLAYER_1);
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public async Task TestGetPlayersFromGameAsync()
public void TestGetPlayersFromGame()
{
// Arrange
Game game = new(name: GAME_NAME,
@ -308,46 +307,46 @@ namespace Tests.Model_UTs.Games
dice: DICE_1);
// Act
Assert.Empty(await game.PlayerManager.GetAll());
await game.PlayerManager.Add(PLAYER_1);
Assert.Empty(game.PlayerManager.GetAll());
game.PlayerManager.Add(PLAYER_1);
// Assert
Assert.Single(await game.PlayerManager.GetAll());
Assert.Single(game.PlayerManager.GetAll());
}
[Fact]
public async Task TestUpdatePlayerInGameAsync()
public void TestUpdatePlayerInGame()
{
// Arrange
Game game = new(name: GAME_NAME,
playerManager: new PlayerManager(),
dice: DICE_2);
await game.PlayerManager.Add(PLAYER_1);
game.PlayerManager.Add(PLAYER_1);
// Act
Player expected = PLAYER_2;
Player actual = await game.PlayerManager.Update(PLAYER_1, PLAYER_2);
Player actual = game.PlayerManager.Update(PLAYER_1, PLAYER_2);
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public async Task TestRemovePlayerFromGameAsync()
public void TestRemovePlayerFromGame()
{
// Arrange
Game game = new(name: GAME_NAME,
playerManager: new PlayerManager(),
dice: DICE_1);
await game.PlayerManager.Add(PLAYER_1);
await game.PlayerManager.Add(PLAYER_2);
game.PlayerManager.Add(PLAYER_1);
game.PlayerManager.Add(PLAYER_2);
game.PlayerManager.Remove(PLAYER_1);
// Act
IEnumerable<Player> expected = new List<Player>() { PLAYER_2 }.AsEnumerable();
IEnumerable<Player> actual = await game.PlayerManager.GetAll();
IEnumerable<Player> actual = game.PlayerManager.GetAll();
// Assert
Assert.Equal(expected, actual);

@ -1,59 +0,0 @@
using Data;
using Model.Dice;
using Model.Games;
using Model.Players;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
namespace Tests.Model_UTs.Games
{
public class MasterOfCeremoniesTest
{
private readonly MasterOfCeremonies stubMasterOfCeremonies = new Stub().LoadApp()?.Result;
[Fact]
public async Task TestPlayGameWhenPlayThenAddNewTurnToHistoryAsync()
{
// Arrange
MasterOfCeremonies masterOfCeremonies = stubMasterOfCeremonies;
Game game = (await masterOfCeremonies.GameManager.GetAll()).First();
// Act
int turnsBefore = game.GetHistory().Count;
await MasterOfCeremonies.PlayGame(game);
int turnsAfter = game.GetHistory().Count;
// Assert
Assert.Equal(turnsBefore + 1, turnsAfter);
}
[Fact]
public async Task TestStartNewGame()
{
// Arrange
MasterOfCeremonies masterOfCeremonies = stubMasterOfCeremonies;
string name = "blargh";
// Act
Assert.DoesNotContain(
await masterOfCeremonies.GameManager.GetOneByName(name),
await masterOfCeremonies.GameManager.GetAll()
);
await masterOfCeremonies.StartNewGame(
name,
new PlayerManager(),
stubMasterOfCeremonies.GameManager.GetAll()?.Result.First().Dice
);
// Assert
Assert.Contains(
await masterOfCeremonies.GameManager.GetOneByName(name),
await masterOfCeremonies.GameManager.GetAll()
);
}
}
}

@ -1,245 +1,245 @@
using Data;
using Model.Dice;
using Model.Dice.Faces;
using Model.Games;
using Model.Players;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Xunit;
using Model.Dice;
using Model.Dice.Faces;
using Model.Games;
using Model.Players;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Xunit;
namespace Tests.Model_UTs.Games
{
public class TurnTest
{
private readonly MasterOfCeremonies stubMasterOfCeremonies = new Stub().LoadApp()?.Result;
private readonly ReadOnlyDictionary<Die, Face> DICE_N_FACES_1;
private readonly ReadOnlyDictionary<Die, Face> DICE_N_FACES_2;
public TurnTest()
{
DICE_N_FACES_1 = stubMasterOfCeremonies.GameManager.GetAll()?.Result.First().GetHistory().First().DiceNFaces;
DICE_N_FACES_2 = stubMasterOfCeremonies.GameManager.GetAll()?.Result.Last().GetHistory().Last().DiceNFaces;
}
[Fact]
public void TestCreateWithSpecifiedTimeNotUTCThenValid()
{
// Arrange
DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Local);
Player player = new("Alice");
Assert.NotEqual(DateTimeKind.Utc, dateTime.Kind);
// Act
Turn turn = Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1);
// Assert
Assert.Equal(DateTimeKind.Utc, turn.When.Kind);
Assert.Equal(dateTime.ToUniversalTime(), turn.When);
}
[Fact]
public void TestCreateWithSpecifiedTimeUTCThenValid()
{
// Arrange
DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc);
Player player = new("Bobby");
Assert.Equal(DateTimeKind.Utc, dateTime.Kind);
// Act
Turn turn = Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1);
// Assert
Assert.Equal(DateTimeKind.Utc, turn.When.Kind);
Assert.Equal(dateTime.ToUniversalTime(), turn.When);
}
[Fact]
public void TestCreateWithSpecifiedTimeNullPlayerThenException()
{
// Arrange
DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc);
// Act
void action() => Turn.CreateWithSpecifiedTime(dateTime, null, DICE_N_FACES_1);
// Assert
Assert.Throws<ArgumentNullException>(action);
}
[Fact]
public void TestCreateWithSpecifiedTimeNullFacesThenException()
{
// Arrange
DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc);
Player player = new("Chucky");
// Act
void action() => Turn.CreateWithSpecifiedTime(dateTime, player, null);
// Assert
Assert.Throws<ArgumentNullException>(action);
}
[Fact]
public void TestCreateWithSpecifiedTimeEmptyFacesThenException()
{
// Arrange
DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc);
Player player = new("Chucky");
// Act
void action() => Turn.CreateWithSpecifiedTime(dateTime, player, new Dictionary<Die, Face>());
// Assert
Assert.Throws<ArgumentException>(action);
}
[Fact]
public void TestCreateWithDefaultTimeThenValid()
{
// Arrange
Player player = new("Chloe");
// Act
Turn turn = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1);
// Assert
Assert.Equal(DateTimeKind.Utc, turn.When.Kind);
Assert.Equal(DateTime.Now.ToUniversalTime().Date, turn.When.Date);
// N.B.: might fail between 11:59:59PM and 00:00:00AM
}
[Fact]
public void TestDiceNFacesProperty()
{
// Arrange
Player player = new("Erika");
// Act
Turn turn = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1);
{
public class TurnTest
{
private readonly GameRunner stubGameRunner = new Stub().LoadApp();
Dictionary<Die, Face> DICE_N_FACES_1, DICE_N_FACES_2;
public TurnTest()
{
DICE_N_FACES_1 = (Dictionary<Die, Face>)stubGameRunner.GetAll().First().GetHistory().First().DiceNFaces;
DICE_N_FACES_2 = (Dictionary<Die, Face>)stubGameRunner.GetAll().Last().GetHistory().Last().DiceNFaces;
}
[Fact]
public void TestCreateWithSpecifiedTimeNotUTCThenValid()
{
// Arrange
DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Local);
Player player = new("Alice");
Assert.NotEqual(DateTimeKind.Utc, dateTime.Kind);
// Act
Turn turn = Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1);
// Assert
Assert.Equal(DateTimeKind.Utc, turn.When.Kind);
Assert.Equal(dateTime.ToUniversalTime(), turn.When);
}
[Fact]
public void TestCreateWithSpecifiedTimeUTCThenValid()
{
// Arrange
DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc);
Player player = new("Bobby");
Assert.Equal(DateTimeKind.Utc, dateTime.Kind);
// Act
Turn turn = Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1);
// Assert
Assert.Equal(DateTimeKind.Utc, turn.When.Kind);
Assert.Equal(dateTime.ToUniversalTime(), turn.When);
}
[Fact]
public void TestCreateWithSpecifiedTimeNullPlayerThenException()
{
// Arrange
DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc);
// Act
void action() => Turn.CreateWithSpecifiedTime(dateTime, null, DICE_N_FACES_1);
// Assert
Assert.Throws<ArgumentNullException>(action);
}
[Fact]
public void TestCreateWithSpecifiedTimeNullFacesThenException()
{
// Arrange
DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc);
Player player = new("Chucky");
// Act
void action() => Turn.CreateWithSpecifiedTime(dateTime, player, null);
// Assert
Assert.Throws<ArgumentNullException>(action);
}
[Fact]
public void TestCreateWithSpecifiedTimeEmptyFacesThenException()
{
// Arrange
DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc);
Player player = new("Chucky");
DICE_N_FACES_1.Clear();
// Act
void action() => Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1);
// Assert
Assert.Throws<ArgumentException>(action);
}
[Fact]
public void TestCreateWithDefaultTimeThenValid()
{
// Arrange
Player player = new("Chloe");
// Act
Turn turn = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1);
// Assert
Assert.Equal(DateTimeKind.Utc, turn.When.Kind);
Assert.Equal(DateTime.Now.ToUniversalTime().Date, turn.When.Date);
// N.B.: might fail between 11:59:59PM and 00:00:00AM
}
[Fact]
public void TestDiceNFacesProperty()
{
// Arrange
Player player = new("Erika");
// Act
Turn turn = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1);
IEnumerable<KeyValuePair<Die, Face>> expected = DICE_N_FACES_1.AsEnumerable();
// Assert
Assert.Equal(expected, turn.DiceNFaces);
// Assert
Assert.Equal(expected, turn.DiceNFaces);
}
[Fact]
public void TestEqualsFalseIfNotTurn()
{
// Arrange
Point point;
Turn turn;
Player player = new("Freddie");
// Act
point = new(1, 2);
turn = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1);
// Assert
Assert.False(point.Equals(turn));
Assert.False(point.GetHashCode().Equals(turn.GetHashCode()));
Assert.False(turn.Equals(point));
Assert.False(turn.GetHashCode().Equals(point.GetHashCode()));
}
[Fact]
public void TestGoesThruToSecondMethodIfObjIsTypeTurn()
{
// Arrange
[Fact]
public void TestEqualsFalseIfNotTurn()
{
// Arrange
Point point;
Turn turn;
Player player = new("Freddie");
// Act
point = new(1, 2);
turn = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1);
// Assert
Assert.False(point.Equals(turn));
Assert.False(point.GetHashCode().Equals(turn.GetHashCode()));
Assert.False(turn.Equals(point));
Assert.False(turn.GetHashCode().Equals(point.GetHashCode()));
}
[Fact]
public void TestGoesThruToSecondMethodIfObjIsTypeTurn()
{
// Arrange
object t1;
Turn t2;
Player player1 = new Player("Marvin");
Player player2 = new Player("Noah");
// Act
t1 = Turn.CreateWithDefaultTime(player1, DICE_N_FACES_1);
t2 = Turn.CreateWithDefaultTime(player2, DICE_N_FACES_2);
// Assert
Assert.False(t1.Equals(t2));
Assert.False(t1.GetHashCode().Equals(t2.GetHashCode()));
Assert.False(t2.Equals(t1));
Assert.False(t2.GetHashCode().Equals(t1.GetHashCode()));
}
[Fact]
public void TestEqualsFalseIfNotSamePlayer()
{
// Arrange
Turn t2;
Player player1 = new Player("Marvin");
Player player2 = new Player("Noah");
// Act
t1 = Turn.CreateWithDefaultTime(player1, DICE_N_FACES_1);
t2 = Turn.CreateWithDefaultTime(player2, DICE_N_FACES_2);
// Assert
Assert.False(t1.Equals(t2));
Assert.False(t1.GetHashCode().Equals(t2.GetHashCode()));
Assert.False(t2.Equals(t1));
Assert.False(t2.GetHashCode().Equals(t1.GetHashCode()));
}
[Fact]
public void TestEqualsFalseIfNotSamePlayer()
{
// Arrange
Player player1 = new("Panama");
Player player2 = new("Clyde");
// Act
Turn t1 = Turn.CreateWithDefaultTime(player1, DICE_N_FACES_2);
Turn t2 = Turn.CreateWithDefaultTime(player2, DICE_N_FACES_2);
// Assert
Assert.False(t1.Equals(t2));
Assert.False(t1.GetHashCode().Equals(t2.GetHashCode()));
Assert.False(t2.Equals(t1));
Assert.False(t2.GetHashCode().Equals(t1.GetHashCode()));
}
[Fact]
public void TestEqualsFalseIfNotSameTime()
{
// Arrange
Player player = new("Oscar");
// Act
Turn t1 = Turn.CreateWithSpecifiedTime(new DateTime(1994, 07, 10), player, DICE_N_FACES_1);
Turn t2 = Turn.CreateWithSpecifiedTime(new DateTime(1991, 08, 20), player, DICE_N_FACES_1);
// Assert
Assert.False(t1.Equals(t2));
Assert.False(t1.GetHashCode().Equals(t2.GetHashCode()));
Assert.False(t2.Equals(t1));
Assert.False(t2.GetHashCode().Equals(t1.GetHashCode()));
// Act
Turn t1 = Turn.CreateWithDefaultTime(player1, DICE_N_FACES_2);
Turn t2 = Turn.CreateWithDefaultTime(player2, DICE_N_FACES_2);
// Assert
Assert.False(t1.Equals(t2));
Assert.False(t1.GetHashCode().Equals(t2.GetHashCode()));
Assert.False(t2.Equals(t1));
Assert.False(t2.GetHashCode().Equals(t1.GetHashCode()));
}
[Fact]
public void TestEqualsFalseIfNotSameDiceNFaces()
{
// Arrange
Player player = new("Django");
// Act
Turn t1 = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1);
Turn t2 = Turn.CreateWithDefaultTime(player, DICE_N_FACES_2);
// Assert
Assert.False(t1.Equals(t2));
Assert.False(t1.GetHashCode().Equals(t2.GetHashCode()));
Assert.False(t2.Equals(t1));
Assert.False(t2.GetHashCode().Equals(t1.GetHashCode()));
[Fact]
public void TestEqualsFalseIfNotSameTime()
{
// Arrange
Player player = new("Oscar");
// Act
Turn t1 = Turn.CreateWithSpecifiedTime(new DateTime(1994, 07, 10), player, DICE_N_FACES_1);
Turn t2 = Turn.CreateWithSpecifiedTime(new DateTime(1991, 08, 20), player, DICE_N_FACES_1);
// Assert
Assert.False(t1.Equals(t2));
Assert.False(t1.GetHashCode().Equals(t2.GetHashCode()));
Assert.False(t2.Equals(t1));
Assert.False(t2.GetHashCode().Equals(t1.GetHashCode()));
}
[Fact]
public void TestEqualsTrueIfExactlySameProperties()
{
// Arrange
Player player = new("Elyse");
// Act
Turn t1 = Turn.CreateWithSpecifiedTime(new DateTime(1990, 04, 29), player, DICE_N_FACES_1);
Turn t2 = Turn.CreateWithSpecifiedTime(new DateTime(1990, 04, 29), player, DICE_N_FACES_1);
// Assert
Assert.True(t1.Equals(t2));
Assert.True(t1.GetHashCode().Equals(t2.GetHashCode()));
Assert.True(t2.Equals(t1));
Assert.True(t2.GetHashCode().Equals(t1.GetHashCode()));
}
}
}
[Fact]
public void TestEqualsFalseIfNotSameDiceNFaces()
{
// Arrange
Player player = new("Django");
// Act
Turn t1 = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1);
Turn t2 = Turn.CreateWithDefaultTime(player, DICE_N_FACES_2);
// Assert
Assert.False(t1.Equals(t2));
Assert.False(t1.GetHashCode().Equals(t2.GetHashCode()));
Assert.False(t2.Equals(t1));
Assert.False(t2.GetHashCode().Equals(t1.GetHashCode()));
}
[Fact]
public void TestEqualsTrueIfExactlySameProperties()
{
// Arrange
Player player = new("Elyse");
// Act
Turn t1 = Turn.CreateWithSpecifiedTime(new DateTime(1990, 04, 29), player, DICE_N_FACES_1);
Turn t2 = Turn.CreateWithSpecifiedTime(new DateTime(1990, 04, 29), player, DICE_N_FACES_1);
// Assert
Assert.True(t1.Equals(t2));
Assert.True(t1.GetHashCode().Equals(t2.GetHashCode()));
Assert.True(t2.Equals(t1));
Assert.True(t2.GetHashCode().Equals(t1.GetHashCode()));
}
}
}

@ -3,7 +3,6 @@ using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
namespace Tests.Model_UTs.Players
@ -11,7 +10,7 @@ namespace Tests.Model_UTs.Players
public class PlayerManagerTest
{
[Fact]
public async Task TestConstructorReturnsEmptyEnumerableAsync()
public void TestConstructorReturnsEmptyEnumerable()
{
// Arrange
PlayerManager playerManager = new();
@ -20,14 +19,14 @@ namespace Tests.Model_UTs.Players
// Act
expected = new Collection<Player>();
actual = await playerManager.GetAll();
actual = playerManager.GetAll();
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public async Task TestAddIfPlayersThenDoAddAndReturnPlayersAsync()
public void TestAddIfPlayersThenDoAddAndReturnPlayers()
{
// Arrange
PlayerManager playerManager = new();
@ -38,8 +37,8 @@ namespace Tests.Model_UTs.Players
Collection<Player> expected = new() { alice, bob };
Collection<Player> actual = new()
{
await playerManager.Add(alice),
await playerManager.Add(bob)
playerManager.Add(alice),
playerManager.Add(bob)
};
// Assert
@ -47,7 +46,7 @@ namespace Tests.Model_UTs.Players
}
[Fact]
public async Task TestAddIfNullThrowsException()
public void TestAddIfNullThrowsException()
{
// Arrange
PlayerManager playerManager = new();
@ -55,59 +54,44 @@ namespace Tests.Model_UTs.Players
// Act
expected = null;
async Task actionAsync() => await playerManager.Add(expected);// Add() returns the added element if succesful
void action() => playerManager.Add(expected);// Add() returns the added element if succesful
// Assert
Assert.Null(expected);
await Assert.ThrowsAsync<ArgumentNullException>(actionAsync);
Assert.DoesNotContain(expected, await playerManager.GetAll());
}
[Fact]
public async Task TestAddIfAlreadyExistsThrowsException()
{
// Arrange
PlayerManager playerManager = new();
// Act
await playerManager.Add(new("Kevin"));
async Task actionAsync() => await playerManager.Add(new("Kevin"));
// Assert
await Assert.ThrowsAsync<ArgumentException>(actionAsync);
Assert.Throws<ArgumentNullException>(action);
Assert.DoesNotContain(expected, playerManager.GetAll());
}
[Fact]
public void TestGetOneByIdThrowsException()
public void TestAddIfAlreadyExistsThrowsException()
{
// Arrange
PlayerManager playerManager = new();
// Act
void action() => playerManager.GetOneByID(new("1a276327-75fc-45b9-8854-e7c4101088f8"));
playerManager.Add(new("Kevin"));
void action() => playerManager.Add(new("Kevin"));
// Assert
Assert.Throws<NotImplementedException>(action);
Assert.Throws<ArgumentException>(action);
}
[Theory]
[InlineData("")]
[InlineData(null)]
[InlineData(" ")]
public async Task TestGetOneByNameIfInvalidThrowsException(string name)
public void TestGetOneByNameIfInvalidThrowsException(string name)
{
// Arrange
PlayerManager playerManager = new();
Player player = new("Bob");
await playerManager.Add(player);
playerManager.Add(player);
// Act
async Task actionAsync() => await playerManager.GetOneByName(name);
void action() => playerManager.GetOneByName(name);
// Assert
await Assert.ThrowsAsync<ArgumentException>(actionAsync);
Assert.Throws<ArgumentException>(action);
}
[Fact]
@ -119,7 +103,7 @@ namespace Tests.Model_UTs.Players
playerManager.Add(player);
// Act
Player result = playerManager.GetOneByName("Clyde")?.Result;
Player result = playerManager.GetOneByName("Clyde");
// Assert
Assert.Null(result);
@ -138,33 +122,33 @@ namespace Tests.Model_UTs.Players
playerManager.Add(expected);
// Act
Player actual = playerManager.GetOneByName(name)?.Result;
Player actual = playerManager.GetOneByName(name);
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public async Task TestRemoveWorksIfExists()
public void TestRemoveWorksIfExists()
{
// Arrange
PlayerManager playerManager = new();
Player p1 = new("Dylan");
await playerManager.Add(p1);
playerManager.Add(p1);
// Act
playerManager.Remove(p1);
// Assert
Assert.DoesNotContain(p1, await playerManager.GetAll());
Assert.DoesNotContain(p1, playerManager.GetAll());
}
[Fact]
public async Task TestRemoveThrowsExceptionIfGivenNull()
public void TestRemoveThrowsExceptionIfGivenNull()
{
// Arrange
PlayerManager playerManager = new();
await playerManager.Add(new Player("Dylan"));
playerManager.Add(new Player("Dylan"));
// Act
void action() => playerManager.Remove(null);
@ -174,37 +158,39 @@ namespace Tests.Model_UTs.Players
}
[Fact]
public async Task TestRemoveFailsSilentlyIfGivenNonExistent()
public void TestRemoveFailsSilentlyIfGivenNonExistent()
{
// Arrange
PlayerManager playerManager = new();
Player player = new("Dylan");
await playerManager.Add(player);
playerManager.Add(player);
Player notPlayer = new("Eric");
IEnumerable<Player> expected = new Collection<Player> { player };
// Act
playerManager.Remove(notPlayer);
IEnumerable<Player> actual = playerManager.GetAll();
// Assert
Assert.DoesNotContain(notPlayer, await playerManager.GetAll());
Assert.Equal(actual, expected);
}
[Fact]
public async Task TestUpdateWorksIfValid()
public void TestUpdateWorksIfValid()
{
// Arrange
PlayerManager playerManager = new();
Player oldPlayer = new("Dylan");
await playerManager.Add(oldPlayer);
playerManager.Add(oldPlayer);
Player newPlayer = new("Eric");
// Act
await playerManager.Update(oldPlayer, newPlayer);
playerManager.Update(oldPlayer, newPlayer);
// Assert
Assert.DoesNotContain(oldPlayer, await playerManager.GetAll());
Assert.Contains(newPlayer, await playerManager.GetAll());
Assert.True((await playerManager.GetAll()).Count == 1);
Assert.DoesNotContain(oldPlayer, playerManager.GetAll());
Assert.Contains(newPlayer, playerManager.GetAll());
Assert.True(playerManager.GetAll().Count() == 1);
}
[Theory]
@ -212,20 +198,20 @@ namespace Tests.Model_UTs.Players
[InlineData("Filibert", " fiLibert")]
[InlineData("Filibert", "FIlibert ")]
[InlineData(" Filibert", " filiBErt ")]
public async Task TestUpdateDiscreetlyUpdatesCaseAndIgnoresExtraSpaceIfOtherwiseSame(string n1, string n2)
public void TestUpdateDiscreetlyUpdatesCaseAndIgnoresExtraSpaceIfOtherwiseSame(string n1, string n2)
{
// Arrange
PlayerManager playerManager = new();
Player oldPlayer = new(n1);
await playerManager.Add(oldPlayer);
playerManager.Add(oldPlayer);
Player newPlayer = new(n2);
// Act
await playerManager.Update(oldPlayer, newPlayer);
playerManager.Update(oldPlayer, newPlayer);
// Assert
Assert.Contains(oldPlayer, await playerManager.GetAll());
Assert.Contains(newPlayer, await playerManager.GetAll());
Assert.Contains(oldPlayer, playerManager.GetAll());
Assert.Contains(newPlayer, playerManager.GetAll());
Assert.Equal(oldPlayer, newPlayer);
}
@ -233,62 +219,62 @@ namespace Tests.Model_UTs.Players
[InlineData("")]
[InlineData(" ")]
[InlineData(null)]
public async Task TestUpdateDoesNotGoWithValidBeforeAndInvalidAfter(string badName)
public void TestUpdateDoesNotGoWithValidBeforeAndInvalidAfter(string badName)
{
// Arrange
PlayerManager playerManager = new();
Player oldPlayer = new("Ni!");
await playerManager.Add(oldPlayer);
int size1 = (await playerManager.GetAll()).Count;
playerManager.Add(oldPlayer);
int size1 = playerManager.GetAll().Count();
// Act
Assert.Contains(oldPlayer, await playerManager.GetAll());
async Task actionAsync() => await playerManager.Update(oldPlayer, new Player(badName));// this is really testing the Player class...
int size2 = (await playerManager.GetAll()).Count;
Assert.Contains(oldPlayer, playerManager.GetAll());
void action() => playerManager.Update(oldPlayer, new Player(badName));// this is really testing the Player class...
int size2 = playerManager.GetAll().Count();
// Assert
await Assert.ThrowsAsync<ArgumentException>(actionAsync); // thrown by Player constructor
Assert.Contains(oldPlayer, await playerManager.GetAll()); // still there
Assert.Throws<ArgumentException>(action); // thrown by Player constructor
Assert.Contains(oldPlayer, playerManager.GetAll()); // still there
Assert.True(size1 == size2);
}
[Fact]
public async Task TestUpdateDoesNotGoWithValidBeforeAndNullAfter()
public void TestUpdateDoesNotGoWithValidBeforeAndNullAfter()
{
// Arrange
PlayerManager playerManager = new();
Player oldPlayer = new("Ni!");
await playerManager.Add(oldPlayer);
int size1 = (await playerManager.GetAll()).Count;
playerManager.Add(oldPlayer);
int size1 = playerManager.GetAll().Count();
// Act
Assert.Contains(oldPlayer, await playerManager.GetAll());
async Task actionAsync() => await playerManager.Update(oldPlayer, null);
int size2 = (await playerManager.GetAll()).Count;
Assert.Contains(oldPlayer, playerManager.GetAll());
void action() => playerManager.Update(oldPlayer, null);
int size2 = playerManager.GetAll().Count();
// Assert
await Assert.ThrowsAsync<ArgumentNullException>(actionAsync); // thrown by Update()
Assert.Contains(oldPlayer, await playerManager.GetAll()); // still there
Assert.Throws<ArgumentNullException>(action); // thrown by Update()
Assert.Contains(oldPlayer, playerManager.GetAll()); // still there
Assert.True(size1 == size2);
}
[Fact]
public async Task TestUpdateDoesNotGoWithValidAfterAndNullBefore()
public void TestUpdateDoesNotGoWithValidAfterAndNullBefore()
{
// Arrange
PlayerManager playerManager = new();
Player newPlayer = new("Kevin");
Player oldPlayer = new("Ursula");
await playerManager.Add(oldPlayer);
int size1 = (await playerManager.GetAll()).Count;
playerManager.Add(oldPlayer);
int size1 = playerManager.GetAll().Count();
// Act
async Task actionAsync() => await playerManager.Update(null, newPlayer);
int size2 = (await playerManager.GetAll()).Count;
void action() => playerManager.Update(null, newPlayer);
int size2 = playerManager.GetAll().Count();
// Assert
await Assert.ThrowsAsync<ArgumentNullException>(actionAsync); // thrown by Update()
Assert.Contains(oldPlayer, await playerManager.GetAll()); // still there
Assert.Throws<ArgumentNullException>(action); // thrown by Update()
Assert.Contains(oldPlayer, playerManager.GetAll()); // still there
Assert.True(size1 == size2);
}
@ -296,21 +282,21 @@ namespace Tests.Model_UTs.Players
[InlineData("")]
[InlineData(" ")]
[InlineData(null)]
public async Task TestUpdateDoesNotGoWithValidAfterAndInvalidBefore(string name)
public void TestUpdateDoesNotGoWithValidAfterAndInvalidBefore(string name)
{
// Arrange
PlayerManager playerManager = new();
Player oldPlayer = new("Ursula");
await playerManager.Add(oldPlayer);
int size1 = (await playerManager.GetAll()).Count;
playerManager.Add(oldPlayer);
int size1 = playerManager.GetAll().Count();
// Act
async Task actionAsync() => await playerManager.Update(new Player(name), new Player("Vicky"));
int size2 = (await playerManager.GetAll()).Count;
void action() => playerManager.Update(new Player(name), new Player("Vicky"));
int size2 = playerManager.GetAll().Count();
// Assert
await Assert.ThrowsAsync<ArgumentException>(actionAsync); // thrown by Player constructor
Assert.Contains(oldPlayer, await playerManager.GetAll()); // still there
Assert.Throws<ArgumentException>(action); // thrown by Player constructor
Assert.Contains(oldPlayer, playerManager.GetAll()); // still there
Assert.True(size1 == size2);
}
}

@ -65,6 +65,20 @@ namespace Tests.Model_UTs.Players
Assert.Throws<ArgumentException>(action);
}
[Fact]
public void TestToStringCorrectName()
{
// Arrange
string expected = "Bob";
Player player = new(expected);
// Act
string actual = player.ToString();
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public void TestEqualsFalseIfNotPlayer()
{

@ -0,0 +1,13 @@
namespace Tests.Model_UTs
{
public class Point
{
public int X { get; private set; }
public int Y { get; private set; }
public Point(int x, int y)
{
X = x; Y = y;
}
}
}

@ -1,13 +0,0 @@
namespace Tests
{
public class Point
{
public int X { get; private set; }
public int Y { get; private set; }
public Point(int x, int y)
{
X = x; Y = y;
}
}
}

@ -1,121 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Utils;
using Xunit;
namespace Tests.Utils_UTs
{
public class EnumerablesTest
{
[Fact]
public void TestFeedListsToDict()
{
// Arrange
string str1 = "blah";
string str2 = "blahblah";
string str3 = "azfyoaz";
int int1 = 5;
int int2 = 12;
int int3 = 3;
Dictionary<string, int> expected = new()
{
{ str1, int1 },
{ str2, int2 },
{ str3, int3 }
};
List<string> strings = new() { str2, str3 };
List<int> ints = new() { int2, int3 };
Dictionary<string, int> actual = new()
{
{str1, int1 }
}; // we will add on top of this
// Act
actual = Enumerables.FeedListsToDict(actual, strings, ints);
// Assert
Assert.Equal(expected, actual);
}
[Fact]
public void TestGetDictFromLists()
{
// Arrange
string str1 = "blah";
string str2 = "blahblah";
int int1 = 5;
int int2 = 12;
Dictionary<string, int> expected = new()
{
{ str1, int1 },
{ str2, int2 }
};
List<string> strings = new() { str1, str2 };
List<int> ints = new() { int1, int2 };
// Act
Dictionary<string, int> actual = Enumerables.GetDictFromLists(strings, ints);
// Assert
Assert.Equal(expected, actual);
}
public static IEnumerable<object[]> EmptyList()
{
yield return new object[] { new List<string>() };
}
[Theory]
[InlineData(null)]
[MemberData(nameof(EmptyList))]
public void TestGetDictFromListsWhenKeysNullOrEmptyThenNew(List<string> strings)
{
// Arrange
int int1 = 5;
int int2 = 12;
Dictionary<string, int> expected = new();
List<int> ints = new() { int1, int2 };
// Act
Dictionary<string, int> actual = Enumerables.GetDictFromLists(strings, ints);
// Assert
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(null)]
[MemberData(nameof(EmptyList))]
public void TestGetDictFromListsWhenValuesNullOrEmptyThenNew(List<string> stringsB)
{
// Arrange
string str1 = "blah";
string str2 = "blahblah";
Dictionary<string, string> expected = new();
List<string> strings = new() { str1, str2 };
// Act
Dictionary<string, string> actual = Enumerables.GetDictFromLists(strings, stringsB);
// Assert
Assert.Equal(expected, actual);
}
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save