Merge pull request '🔊 Implement logger' (#192) from implement-logger into main
continuous-integration/drone/push Build is passing Details

Reviewed-on: #192
pull/199/head
Alexis Drai 3 years ago
commit 7c6b3ee663

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

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

@ -10,12 +10,17 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace App
{
internal static class Program
{
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
static async Task Main(string[] args)
{
// MODEL stuff
@ -27,8 +32,7 @@ namespace App
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
logger.Warn(ex);
masterOfCeremonies = new(new PlayerManager(), new DiceGroupManager(), null);
}
@ -43,22 +47,18 @@ namespace App
PlayerDbManager playerDbManager = new(db);
IEnumerable<PlayerEntity> entities = await playerDbManager.GetAll();
Debug.WriteLine("Loading players");
foreach (PlayerEntity entity in entities)
{
try
{
// persist them as models !
await masterOfCeremonies.GlobalPlayerManager.Add(entity.ToModel());
Debug.WriteLine($"{entity.ID} -- {entity.Name}");
}
catch (Exception ex) { Debug.WriteLine($"{ex.Message}\n... Never mind"); }
catch (Exception ex) { Console.WriteLine($"{ex.Message}\n... Never mind"); }
}
}
}
catch (Exception ex) { Debug.WriteLine($"{ex.Message}\n... Couldn't use the database"); }
catch (Exception ex) { Console.WriteLine($"{ex.Message}\n... Couldn't use the database"); }
string menuChoice = "nothing";
@ -186,22 +186,21 @@ namespace App
// create a PlayerDbManager (and inject it with the DB)
PlayerDbManager playerDbManager = new(db);
Debug.WriteLine("Saving players");
foreach (Player model in models)
{
try // to persist them
{ // as entities !
PlayerEntity entity = model.ToEntity();
await playerDbManager.Add(entity);
Debug.WriteLine($"{entity.ID} -- {entity.Name}");
}
// 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 (ArgumentException ex) { Console.WriteLine($"{ex.Message}\n... Never mind"); }
}
}
// flushing and closing NLog before quitting completely
NLog.LogManager.Shutdown();
}
catch (Exception ex) { Debug.WriteLine($"{ex.Message}\n... Couldn't use the database"); }
catch (Exception ex) { Console.WriteLine($"{ex.Message}\n... Couldn't use the database"); }
}
private static async Task Play(MasterOfCeremonies masterOfCeremonies, string name)
@ -210,7 +209,7 @@ namespace App
while (menuChoicePlay != "q")
{
Game game = await masterOfCeremonies.GameManager.GetOneByName(name);
Console.WriteLine($"{game.GetWhoPlaysNow()}'s turn\n" +
Console.WriteLine($"{PlayerToString(await game.GetWhoPlaysNow())}'s turn\n" +
"q... quit\n" +
"h... show history\n" +
"s... save\n" +
@ -221,17 +220,14 @@ namespace App
case "q":
break;
case "h":
foreach (Turn turn in game.GetHistory())
{
Console.WriteLine(turn);
}
foreach (Turn turn in game.GetHistory()) { Console.WriteLine(TurnToString(turn)); }
break;
case "s":
await masterOfCeremonies.GameManager.Add(game);
break;
default:
await MasterOfCeremonies.PlayGame(game);
Console.WriteLine(game.GetHistory().Last());
Console.WriteLine(TurnToString(game.GetHistory().Last()));
break;
}
}
@ -243,7 +239,7 @@ namespace App
Console.WriteLine("which of these games?\n(choose by name)\n>");
foreach (Game game in await masterOfCeremonies.GameManager.GetAll())
{
Console.WriteLine(game);
Console.WriteLine(GameToString(game));
}
name = Console.ReadLine();
return name;
@ -254,7 +250,7 @@ namespace App
Console.WriteLine("Look at all them players!");
foreach (Player player in await masterOfCeremonies.GlobalPlayerManager.GetAll())
{
Console.WriteLine(player);
Console.WriteLine(PlayerToString(player));
}
}
@ -262,7 +258,7 @@ namespace App
{
foreach ((string name, IEnumerable<Die> dice) in await masterOfCeremonies.DiceGroupManager.GetAll())
{
Console.WriteLine($"{name} -- {dice}");
Console.WriteLine($"{name} -- {dice}"); // maybe code a quick and dirty DieToString()
}
}
@ -335,11 +331,13 @@ 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);
}
}
}
@ -356,7 +354,7 @@ namespace App
if (menuChoice.Equals("ok") && count == 0)
{
Console.WriteLine("create at least one valid face");
menuChoice = ""; // persiste en dehors du scope de cette fonction
menuChoice = ""; // persists outside the scope of this function
}
}
@ -396,7 +394,7 @@ namespace App
Player player = new(menuChoicePlayers);
if (!(await masterOfCeremonies.GlobalPlayerManager.GetAll()).Contains(player))
{
// if the player didn't exist, now it does... this is temporary
// if the player didn't exist, now it does...
await masterOfCeremonies.GlobalPlayerManager.Add(player);
}
// almost no checks, this is temporary
@ -404,12 +402,57 @@ namespace App
{
await result.Add(player);
}
catch (ArgumentException ex) { Debug.WriteLine($"{ex.Message}\n... Never mind"); }
catch (ArgumentException ex) { Console.WriteLine($"{ex.Message}\n... Never mind"); }
}
}
return result;
}
private static string TurnToString(Turn turn)
{
string[] datetime = turn.When.ToString("s", System.Globalization.CultureInfo.InvariantCulture).Split("T");
string date = datetime[0];
string time = datetime[1];
StringBuilder sb = new();
sb.AppendFormat("{0} {1} -- {2} rolled:",
date,
time,
PlayerToString(turn.Player));
foreach (KeyValuePair<Die, Face> kvp in turn.DiceNFaces)
{
sb.Append(" " + kvp.Value.StringValue);
}
return sb.ToString();
}
private async static Task<string> GameToString(Game game)
{
StringBuilder sb = new();
sb.Append($"Game: {game.Name}");
sb.Append("\nPlayers:");
foreach (Player player in game.PlayerManager.GetAll()?.Result)
{
sb.Append($" {PlayerToString(player)}");
}
sb.Append($"\nNext: {PlayerToString(await game.GetWhoPlaysNow())}");
sb.Append("\nLog:\n");
foreach (Turn turn in game.GetHistory())
{
sb.Append($"\t{TurnToString(turn)}\n");
}
return sb.ToString();
}
private static string PlayerToString(Player player)
{
return player.Name;
}
}
}

@ -13,6 +13,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="NLog" Version="5.0.4" />
</ItemGroup>
<ItemGroup>

@ -6,13 +6,17 @@ 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)
{
throw new ArgumentNullException(nameof(db), "param should not be 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;
}
@ -27,11 +31,15 @@ namespace Data.EF.Players
{
if (entity is null)
{
throw new ArgumentNullException(nameof(entity), "param should not be null");
ArgumentNullException ex = new(nameof(entity), "param should not be null");
logger.Warn(ex);
throw ex;
}
if (string.IsNullOrWhiteSpace(entity.Name))
{
throw new ArgumentException("Name property should not be null or whitespace", nameof(entity));
ArgumentException ex = new("Name property should not be null or whitespace", nameof(entity));
logger.Warn(ex);
throw ex;
}
entity.Name = entity.Name.Trim();
}
@ -49,7 +57,9 @@ namespace Data.EF.Players
if (db.PlayerEntity.Where(entity => entity.Name == toAdd.Name).Any())
{
throw new ArgumentException("this username is already taken", nameof(toAdd));
ArgumentException ex = new("this username is already taken", nameof(toAdd));
logger.Warn(ex);
throw ex;
}
return InternalAdd(toAdd);
@ -59,6 +69,7 @@ namespace Data.EF.Players
{
EntityEntry ee = await db.PlayerEntity.AddAsync(toAdd);
await db.SaveChangesAsync();
logger.Info("Added {0}", ee.Entity.ToString());
return (PlayerEntity)ee.Entity;
}
@ -116,6 +127,7 @@ namespace Data.EF.Players
if (isPresent)
{
db.PlayerEntity.Remove(toRemove);
logger.Info("Removed {0}", toRemove.ToString());
db.SaveChanges();
}
}
@ -139,11 +151,12 @@ namespace Data.EF.Players
if (before.ID != after.ID)
{
throw new ArgumentException("ID cannot be updated", nameof(after));
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)

@ -6,13 +6,17 @@ 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)
{
throw new ArgumentNullException(nameof(db), "param should not be 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;
}
@ -27,11 +31,15 @@ namespace Data.EF.Players
{
if (entity is null)
{
throw new ArgumentNullException(nameof(entity), "param should not be null");
ArgumentNullException ex = new(nameof(entity), "param should not be null");
logger.Warn(ex);
throw ex;
}
if (string.IsNullOrWhiteSpace(entity.Name))
{
throw new ArgumentException("Name property should not be null or whitespace", nameof(entity));
ArgumentException ex = new("Name property should not be null or whitespace", nameof(entity));
logger.Warn(ex);
throw ex;
}
entity.Name = entity.Name.Trim();
}
@ -49,7 +57,9 @@ namespace Data.EF.Players
if (db.PlayerEntity.Where(entity => entity.Name == toAdd.Name).Any())
{
throw new ArgumentException("this username is already taken", nameof(toAdd));
ArgumentException ex = new("this username is already taken", nameof(toAdd));
logger.Warn(ex);
throw ex;
}
return InternalAdd(toAdd);
@ -59,6 +69,7 @@ namespace Data.EF.Players
{
EntityEntry ee = await db.PlayerEntity.AddAsync(toAdd);
await db.SaveChangesAsync();
logger.Info("Added {0}", ee.Entity.ToString());
return (PlayerEntity)ee.Entity;
}
@ -116,6 +127,7 @@ namespace Data.EF.Players
if (isPresent)
{
db.PlayerEntity.Remove(toRemove);
logger.Info("Removed {0}", toRemove.ToString());
db.SaveChanges();
}
}
@ -139,11 +151,12 @@ namespace Data.EF.Players
if (before.ID != after.ID)
{
throw new ArgumentException("ID cannot be updated", nameof(after));
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)

@ -11,7 +11,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Data", "Data\Data.csproj", "{E9683741-E603-4ED3-8088-4099D67FCA6D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utils", "Utils\Utils\Utils.csproj", "{9300910D-9D32-4C79-8868-67D0ED56E2F3}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Utils", "Utils\Utils\Utils.csproj", "{9300910D-9D32-4C79-8868-67D0ED56E2F3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution

@ -16,7 +16,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Data", "Data\Data.csproj", "{E9683741-E603-4ED3-8088-4099D67FCA6D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utils", "Utils\Utils\Utils.csproj", "{9300910D-9D32-4C79-8868-67D0ED56E2F3}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Utils", "Utils\Utils\Utils.csproj", "{9300910D-9D32-4C79-8868-67D0ED56E2F3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution

@ -169,31 +169,5 @@ 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()?.Result)
{
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();
}
}
}

@ -87,30 +87,6 @@ namespace Model.Games
return CreateWithSpecifiedTime(DateTime.UtcNow, player, diceNFaces);
}
/// <summary>
/// represents a turn in string format
/// </summary>
/// <returns>a turn in string format</returns>
public override string ToString()
{
string[] datetime = When.ToString("s", System.Globalization.CultureInfo.InvariantCulture).Split("T");
string date = datetime[0];
string time = datetime[1];
StringBuilder sb = new();
sb.AppendFormat("{0} {1} -- {2} rolled:",
date,
time,
Player.ToString());
foreach (Face face in this.diceNFaces.Values)
{
sb.Append(" " + face.StringValue);
}
return sb.ToString();
}
public bool Equals(Turn other)
{
return Player.Equals(other.Player)

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

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

@ -142,8 +142,6 @@ namespace Tests.Model_UTs.Games
await game.PrepareNextPlayer(currentPlayer);
}
Debug.WriteLine(game);
// Act
int actual = game.GetHistory().Count();
int expected = n;

@ -65,20 +65,6 @@ 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()
{

Loading…
Cancel
Save