Compare commits

..

5 Commits

Author SHA1 Message Date
Ismail TAHA JANAN 1ee0e762b4 test fore dices
continuous-integration/drone/push Build is passing Details
3 years ago
Ismail TAHA JANAN f2957f06e2 Faces Test implemented
continuous-integration/drone/push Build is passing Details
3 years ago
Ismail TAHA JANAN 190c2adba6 Merge pull request '♻️ Turn Theory into Fact' (#109) from fix-TU-faces into TU_faces
continuous-integration/drone/push Build is passing Details
3 years ago
Alexis Drai 67edaf0e9b ♻️ Turn Theory into Fact
continuous-integration/drone/push Build is passing Details
3 years ago
istahajana 206786271a code with error
continuous-integration/drone/push Build is failing Details
3 years ago

@ -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
@ -45,24 +42,3 @@ steps:
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: {}

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

@ -34,13 +34,11 @@ However, you do need to create the migrations and DB (and you probably should de
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 `DiceAppDbContext` *and* and `DiceAppDbContextWithStub`, 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
```
@ -52,10 +50,6 @@ You may not want to read tables in the debug window -- in which case, just downl
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)
@ -101,8 +95,3 @@ 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.

@ -6,19 +6,11 @@
<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>

@ -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,5 +1,4 @@
using Data;
using Data.EF;
using Data.EF.Players;
using Model.Dice;
using Model.Dice.Faces;
@ -7,57 +6,61 @@ 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)
static void Main(string[] args)
{
// MODEL stuff
ILoader loader = new Stub();
MasterOfCeremonies masterOfCeremonies;
/*
* the DB stuff and the Model stuff are completely separate here
*
* that will change
*/
// DB stuff
// if you've run the 'dotnet' 'ef' commands, you should have a DB with 1 table, and 4 players in it
using PlayerDBManager playerDBManager = new();
// we'll add a 5th player from the App
PlayerEntity playerEntity = new Player("Ernesto").ToEntity();
try
{
masterOfCeremonies = await loader.LoadApp();
}
catch (Exception ex)
{
logger.Warn(ex);
masterOfCeremonies = new(new PlayerManager(), new DiceGroupManager(), new GameManager());
}
playerDBManager.Add(playerEntity);
} // 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"); }
catch (Exception ex) { Debug.WriteLine($"{ex.Message}\n... Did you make sure that the DATABASE exists?"); }
try
{
// DB stuff when the app opens
using (DiceAppDbContext db = new())
IEnumerable<PlayerEntity> allPlayersFromDB = playerDBManager.GetAll();
foreach (PlayerEntity entity in allPlayersFromDB)
{
// Later, we'll use the DiceAppDbContext to get a GameDbRunner
Debug.WriteLine(entity);
}
}
catch (Exception ex) { Debug.WriteLine($"{ex.Message}\n... Did you make sure that the DATABASE exists?"); }
// get all the players from the DB
PlayerDbManager playerDbManager = new(db);
IEnumerable<PlayerEntity> entities = await playerDbManager.GetAll();
foreach (PlayerEntity entity in entities)
{
// Model stuff
ILoader loader = new Stub();
GameRunner gameRunner;
try
{
// persist them as models !
await masterOfCeremonies.GlobalPlayerManager.Add(entity.ToModel());
}
catch (Exception ex) { Debug.WriteLine($"{ex.Message}\n... Never mind"); }
}
gameRunner = loader.LoadApp();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
gameRunner = new(new PlayerManager(), new DieManager(), null);
}
catch (Exception ex) { Console.WriteLine($"{ex.Message}\n... Couldn't use the database"); }
string menuChoice = "nothing";
@ -67,10 +70,7 @@ namespace App
"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" +
">"
);
@ -83,38 +83,35 @@ namespace App
break;
case "l":
string loadName = await ChooseGame(masterOfCeremonies);
if (masterOfCeremonies.GameManager.GetOneByName(loadName) != null)
string loadName = ChooseGame(gameRunner);
if (gameRunner.GetOneByName(loadName) != null)
{
await Play(masterOfCeremonies, loadName);
Play(gameRunner, loadName);
}
break;
case "n":
if (!(await masterOfCeremonies.DiceGroupManager.GetAll()).Any())
if (!gameRunner.GlobalDieManager.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);
IEnumerable<Die> newGameDice = PrepareDice(gameRunner);
string newGameName;
Console.WriteLine("give this new game a name\n>");
newGameName = Console.ReadLine();
PlayerManager playerManager = PreparePlayers(gameRunner);
Console.WriteLine("add players to the game");
PlayerManager playerManager = await PreparePlayers(masterOfCeremonies);
await masterOfCeremonies.StartNewGame(newGameName, playerManager, newGameDice);
await Play(masterOfCeremonies, newGameName);
gameRunner.StartNewGame(newGameName, playerManager, newGameDice);
Play(gameRunner, newGameName);
break;
case "d":
string deleteName = await ChooseGame(masterOfCeremonies);
masterOfCeremonies.GameManager.Remove(await masterOfCeremonies.GameManager.GetOneByName(deleteName));
string deleteName = ChooseGame(gameRunner);
gameRunner.Remove(gameRunner.GetOneByName(deleteName));
break;
case "c":
@ -153,19 +150,7 @@ namespace App
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);
gameRunner.GlobalDieManager.Add(new KeyValuePair<string, IEnumerable<Die>>(newGroupName, newGroupDice));
break;
default:
@ -174,41 +159,15 @@ namespace App
}
}
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)
private static void Play(GameRunner gameRunner, string name)
{
string menuChoicePlay = "";
while (menuChoicePlay != "q")
{
Game game = await masterOfCeremonies.GameManager.GetOneByName(name);
Console.WriteLine($"{PlayerToString(await game.GetWhoPlaysNow())}'s turn\n" +
Game game = gameRunner.GetOneByName(name);
Console.WriteLine($"{game.GetWhoPlaysNow()}'s turn\n" +
"q... quit\n" +
"h... show history\n" +
"s... save\n" +
@ -219,48 +178,34 @@ namespace App
case "q":
break;
case "h":
foreach (Turn turn in game.GetHistory()) { Console.WriteLine(TurnToString(turn)); }
foreach (Turn turn in game.GetHistory())
{
Console.WriteLine(turn);
}
break;
case "s":
await masterOfCeremonies.GameManager.Add(game);
gameRunner.Add(game);
break;
default:
await MasterOfCeremonies.PlayGame(game);
Console.WriteLine(TurnToString(game.GetHistory().Last()));
GameRunner.PlayGame(game);
Console.WriteLine(game.GetHistory().Last());
break;
}
}
}
private static async Task<string> ChooseGame(MasterOfCeremonies masterOfCeremonies)
private static string ChooseGame(GameRunner gameRunner)
{
string name;
Console.WriteLine("which of these games?\n(choose by name)\n>");
foreach (Game game in await masterOfCeremonies.GameManager.GetAll())
foreach (Game game in gameRunner.GetAll())
{
Console.WriteLine(GameToString(game));
Console.WriteLine(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;
@ -272,17 +217,13 @@ namespace App
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..]);
die = new NumberDie(faces.ToArray());
return die;
}
@ -296,15 +237,10 @@ namespace App
{
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..]);
die = new ColorDie(faces.ToArray());
return die;
}
@ -319,8 +255,6 @@ namespace App
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
@ -330,46 +264,36 @@ namespace App
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..]);
die = new ImageDie(faces.ToArray());
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)
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:");
await ShowDice(masterOfCeremonies);
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 = (await masterOfCeremonies.DiceGroupManager.GetOneByName(menuChoiceDice)).Dice;
IEnumerable<Die> chosenDice = gameRunner.GlobalDieManager.GetOneByName(menuChoiceDice).Value;
foreach (Die die in chosenDice)
{
result.Add(die);
@ -378,80 +302,34 @@ namespace App
}
return result.AsEnumerable();
}
private async static Task<PlayerManager> PreparePlayers(MasterOfCeremonies masterOfCeremonies)
private static PlayerManager PreparePlayers(GameRunner gameRunner)
{
PlayerManager result = new();
Console.WriteLine("add players to the game");
Console.WriteLine("all known players:");
await ShowPlayers(masterOfCeremonies);
foreach (Player player in gameRunner.GlobalPlayerManager.GetAll())
{
Console.WriteLine(player);
}
string menuChoicePlayers = "";
while (!(menuChoicePlayers.Equals("ok") && (await result.GetAll()).Any()))
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 (!(await masterOfCeremonies.GlobalPlayerManager.GetAll()).Contains(player))
if (!gameRunner.GlobalPlayerManager.GetAll().Contains(player))
{
// if the player didn't exist, now it does...
await masterOfCeremonies.GlobalPlayerManager.Add(player);
// if the player didn't exist, now it does... this is temporary
gameRunner.GlobalPlayerManager.Add(player);
}
// almost no checks, this is temporary
try
{
await result.Add(player);
}
catch (ArgumentException ex) { Console.WriteLine($"{ex.Message}\n... Never mind"); }
result.Add(player);
}
}
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;
}
}
}

@ -3,6 +3,7 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<StartWorkingDirectory>$(MSBuildProjectDirectory)</StartWorkingDirectory>
</PropertyGroup>
@ -13,12 +14,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,14 @@
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;
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
=> optionsBuilder.UseSqlite("Data Source=EFDice.DiceApp.db");
// 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 })
);
}
}
}

@ -1,112 +1,20 @@
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;
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,52 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Model;
using System.Collections.ObjectModel;
namespace Data.EF.Players
{
public sealed class PlayerDbManager : IManager<PlayerEntity>
public sealed class PlayerDBManager : IManager<PlayerEntity>, IDisposable
{
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private readonly DiceAppDbContext db = new DiceAppDbContextWithStub();
private readonly DiceAppDbContext db;
public PlayerDbManager(DiceAppDbContext db)
{
if (db is null)
public void Dispose()
{
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;
db.Dispose();
}
/// <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))
public PlayerEntity Add(PlayerEntity toAdd)
{
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())
if (db.Players!.Where(entity => entity.Name == toAdd.Name).Any())
{
ArgumentException ex = new("this username is already taken", nameof(toAdd));
logger.Warn(ex);
throw ex;
throw new ArgumentException("this username is already taken", nameof(toAdd));
}
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());
EntityEntry ee = db.Players!.Add(toAdd);
db.SaveChanges();
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)
public IEnumerable<PlayerEntity> GetAll()
{
return await db.PlayerEntity.Where(p => p.Name == name).FirstAsync();
return db.Players!.AsEnumerable();
}
public async Task<bool> IsPresentByName(string name)
public PlayerEntity GetOneByName(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
return false;
}
name = name.Trim();
return await db.PlayerEntity.Where(p => p.Name == name).FirstOrDefaultAsync() is not null;
throw new NotImplementedException();
}
/// <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);
throw new NotImplementedException();
}
/// <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)
public PlayerEntity Update(PlayerEntity before, PlayerEntity after)
{
return await db.PlayerEntity.FirstAsync(p => p.ID == ID);
throw new NotImplementedException();
}
public async Task<bool> IsPresentByID(Guid ID)
public PlayerEntity GetOneByID(Guid ID)
{
return await db.PlayerEntity.FirstOrDefaultAsync(p => p.ID == ID) is not null;
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,4 @@
using Data.EF.Games;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace Data.EF.Players
{
@ -8,11 +7,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 +18,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 +28,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());
}
}
}

@ -4,6 +4,6 @@ namespace Data
{
public interface ILoader
{
public Task<MasterOfCeremonies> LoadApp();
public GameRunner LoadApp();
}
}

@ -8,15 +8,15 @@ 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 +27,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 +40,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 +52,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 +61,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,80 @@
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)
{
}
}

@ -4,8 +4,7 @@ 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,8 @@ using Model.Dice.Faces;
using Model.Players;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using System.Text;
namespace Model.Games
{
@ -20,7 +19,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 +34,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 +55,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 +70,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 +112,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 +128,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 +143,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 +168,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,57 +1,52 @@
using System;
using Model.Dice;
using Model.Players;
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>
public class GameRunner : IManager<Game>
{
/// <summary>
/// the games managed by this instance
/// </summary>
private readonly List<Game> games = new();
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) { }
/// <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));
public IEnumerable<Game> GetAll() => games.AsEnumerable();
/// <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
/// 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 Task<Game> GetOneByName(string name)
public Game GetOneByName(string name)
{
if (!string.IsNullOrWhiteSpace(name))
{
return Task.FromResult(games.FirstOrDefault(g => g.Name == name)); // may return null
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>
/// 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)
public Game Add(Game toAdd)
{
if (toAdd is null)
{
@ -61,14 +56,18 @@ namespace Model.Games
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);
return toAdd;
}
/// <summary>
/// removes a game. does nothing if the game doesn't exist
/// creates a new game
/// </summary>
/// <param name="toRemove">game to remove</param>
/// <exception cref="ArgumentNullException"></exception>
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)
@ -78,14 +77,7 @@ namespace Model.Games
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)
public Game Update(Game before, Game after)
{
Game[] args = { before, after };
@ -100,7 +92,23 @@ namespace Model.Games
}
}
Remove(before);
return (Add(after));
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);
}
}
}

@ -3,14 +3,17 @@ using Model.Dice.Faces;
using Model.Players;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
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,23 +76,6 @@ namespace Model.Games
when = when.ToUniversalTime();
}
When = when;
Player = player;
this.diceNFaces = diceNFaces.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
/// <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, IEnumerable<KeyValuePair<Die, Face>> diceNFaces)
{
return new Turn(when, player, diceNFaces);
}
@ -82,47 +85,41 @@ namespace Model.Games
/// <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)
public static Turn CreateWithDefaultTime(Player player, Dictionary<Die, Face> diceNFaces)
{
return CreateWithSpecifiedTime(DateTime.UtcNow, player, diceNFaces);
}
public bool Equals(Turn other)
{
if (other is null
||
!(Player.Equals(other.Player)
&& When.Equals(other.When)
&& DiceNFaces.Count == other.DiceNFaces.Count))
/// <summary>
/// represents a turn in string format
/// </summary>
/// <returns>a turn in string format</returns>
public override string ToString()
{
return false;
}
string[] datetime = When.ToString("s", System.Globalization.CultureInfo.InvariantCulture).Split("T");
string date = datetime[0];
string time = datetime[1];
// 🤮
for (int i = 0; i < DiceNFaces.Count; i++)
{
if (DiceNFaces.ElementAt(i).Key.Faces.Count
!= other.DiceNFaces.ElementAt(i).Key.Faces.Count)
StringBuilder sb = new();
sb.AppendFormat("{0} {1} -- {2} rolled:",
date,
time,
Player.ToString());
foreach (Face face in this.diceNFaces.Values)
{
return false;
sb.Append(" " + face.ToString());
}
if (!other.DiceNFaces.ElementAt(i).Value.StringValue
.Equals(DiceNFaces.ElementAt(i).Value.StringValue))
{
return false;
return sb.ToString();
}
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))
public bool Equals(Turn other)
{
return false;
}
}
}
return true;
return Player.Equals(other.Player)
&& When.Equals(other.When)
&& DiceNFaces.SequenceEqual(other.DiceNFaces);
}
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))
if (!string.IsNullOrWhiteSpace(name))
{
throw new ArgumentException("param should not be null or blank", nameof(name));
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)
}
Player result = players.FirstOrDefault(p => p.Name.ToUpper().Equals(name.ToUpper().Trim()));
if (result == null)
{
return Task.FromResult<Player>(null);
}
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,5 +1,6 @@
using Data.EF.Players;
using System;
using Tests.Model_UTs;
using Xunit;
namespace Tests.Data_UTs.Players
@ -26,7 +27,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 +107,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 +127,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 +145,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 +165,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,8 +1,12 @@
using Model.Dice.Faces;
using Model.Dice;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
using System.Drawing;
namespace Tests.Model_UTs.Dice
{

@ -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,11 +1,15 @@
using Model.Dice.Faces;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
using Model.Dice.Faces;
using System.Drawing;
namespace Tests.Model_UTs.Dice.Faces
{
public class ColorFaceTest
public class FaceColorTest
{
public static IEnumerable<object[]> Data_Colors()
{
@ -24,7 +28,7 @@ namespace Tests.Model_UTs.Dice.Faces
[Theory]
[MemberData(nameof(Data_Colors))]
public void ColorFaceValueTest(Color clrA, Color clrB)
public void ColorFaceValueTest(Color clrA,Color clrB)
{

@ -1,11 +1,15 @@
using Model.Dice.Faces;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
namespace Tests.Model_UTs.Dice.Faces
{
public class ImageFaceTest
public class FaceImageTest
{
public static IEnumerable<object[]> Data_Colors()
{

@ -1,10 +1,18 @@
using Model.Dice.Faces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
namespace Tests.Model_UTs.Dice.Faces
{
public class NumberFaceTest
public class FaceNumber
{
[Fact]
public void NumberFaceValueTest()
{

@ -2,14 +2,18 @@
using Model.Dice;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
using System.Drawing;
using Model.Dice.Faces;
namespace Tests.Model_UTs.Dice
{
public class ImageDieTest
{
public static IEnumerable<object[]> Data_Uri()
{
yield return new object[]

@ -1,13 +1,17 @@
using Model.Dice;
using Model.Dice.Faces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
using Model.Dice.Faces;
using System.Diagnostics;
namespace Tests.Model_UTs.Dice
{
public class NumberDieTest
{
[Fact]
public void RndmFaceTest()
{
@ -33,7 +37,7 @@ namespace Tests.Model_UTs.Dice
//Assert
Assert.Contains(listFaces, face => face == actual);
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,305 @@
using Data;
using Model.Dice;
using Model.Games;
using Model.Players;
using System;
using System.Collections.Generic;
using System.Linq;
using Xunit;
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()
);
}
}
}

@ -5,7 +5,6 @@ using Model.Games;
using Model.Players;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Xunit;
@ -14,15 +13,14 @@ 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;
private readonly GameRunner stubGameRunner = new Stub().LoadApp();
Dictionary<Die, Face> DICE_N_FACES_1, 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;
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]
@ -94,9 +92,10 @@ namespace Tests.Model_UTs.Games
// 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, new Dictionary<Die, Face>());
void action() => Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1);
// Assert
Assert.Throws<ArgumentException>(action);

@ -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()
{

@ -1,4 +1,4 @@
namespace Tests
namespace Tests.Model_UTs
{
public class Point
{

@ -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);
}
}
}

@ -1,29 +0,0 @@
namespace Utils
{
public static class Enumerables
{
public static Dictionary<K, V> GetDictFromLists<K, V>(List<K> keys, List<V> values)
{
if (keys == null || values == null || keys.Count == 0 || values.Count == 0)
{
return new Dictionary<K, V>();
}
return keys.Zip(
values,
(key, value) => new { key, value })
.ToDictionary(kvp => kvp.key, kvp => kvp.value
);
}
public static Dictionary<K, V> FeedListsToDict<K, V>(Dictionary<K, V> kvps, List<K> keys, List<V> values)
{
foreach (KeyValuePair<K, V> kvp in GetDictFromLists(keys, values))
{
kvps.Add(kvp.Key, kvp.Value);
}
return kvps;
}
}
}

@ -1,8 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
</Project>
Loading…
Cancel
Save