From e3687b206e5ee7028daeb9339b1cff52ae5eaa3b Mon Sep 17 00:00:00 2001 From: Alexis DRAI Date: Fri, 30 Sep 2022 13:05:39 +0200 Subject: [PATCH 01/20] :construction: WIP on EF BP --- Sources/Data/Data.csproj | 27 ++++++++----- Sources/Data/EF/Players/PlayerDBContext.cs | 20 ++++++++++ Sources/Data/EF/Players/PlayerDBManager.cs | 42 +++++++++++++++++++++ Sources/Data/EF/Players/PlayerEntity.cs | 14 +++++++ Sources/Data/EF/Players/PlayerExtensions.cs | 27 +++++++++++++ 5 files changed, 120 insertions(+), 10 deletions(-) create mode 100644 Sources/Data/EF/Players/PlayerDBContext.cs create mode 100644 Sources/Data/EF/Players/PlayerDBManager.cs create mode 100644 Sources/Data/EF/Players/PlayerEntity.cs create mode 100644 Sources/Data/EF/Players/PlayerExtensions.cs diff --git a/Sources/Data/Data.csproj b/Sources/Data/Data.csproj index ac52241..749750b 100644 --- a/Sources/Data/Data.csproj +++ b/Sources/Data/Data.csproj @@ -1,13 +1,20 @@ + + net6.0 + enable + enable + $(MSBuildProjectDirectory) + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + - - net6.0 - enable - enable - - - - - - + + + diff --git a/Sources/Data/EF/Players/PlayerDBContext.cs b/Sources/Data/EF/Players/PlayerDBContext.cs new file mode 100644 index 0000000..228d52a --- /dev/null +++ b/Sources/Data/EF/Players/PlayerDBContext.cs @@ -0,0 +1,20 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Data.EF.Players +{ + internal class PlayerDBContext : DbContext + { + public DbSet PlayersSet { get; set; } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + optionsBuilder.UseSqlite("Data Source=EFDice.DiceApp.db"); + } + + } +} diff --git a/Sources/Data/EF/Players/PlayerDBManager.cs b/Sources/Data/EF/Players/PlayerDBManager.cs new file mode 100644 index 0000000..663a725 --- /dev/null +++ b/Sources/Data/EF/Players/PlayerDBManager.cs @@ -0,0 +1,42 @@ +using Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Data.EF.Players +{ + internal class PlayerDBManager : IManager + { + PlayerDBContext context = new PlayerDBContext(); + + public PlayerEntity Add(PlayerEntity toAdd) + { + // just to check... + + context.PlayersSet.Add(toAdd); + throw new NotImplementedException(); + } + + public IEnumerable GetAll() + { + throw new NotImplementedException(); + } + + public PlayerEntity GetOneByName(string name) + { + throw new NotImplementedException(); + } + + public void Remove(PlayerEntity toRemove) + { + throw new NotImplementedException(); + } + + public PlayerEntity Update(PlayerEntity before, PlayerEntity after) + { + throw new NotImplementedException(); + } + } +} diff --git a/Sources/Data/EF/Players/PlayerEntity.cs b/Sources/Data/EF/Players/PlayerEntity.cs new file mode 100644 index 0000000..2e178e7 --- /dev/null +++ b/Sources/Data/EF/Players/PlayerEntity.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Data.EF.Players +{ + internal class PlayerEntity + { + public Guid ID { get; set; } + public string Name { get; set; } + } +} diff --git a/Sources/Data/EF/Players/PlayerExtensions.cs b/Sources/Data/EF/Players/PlayerExtensions.cs new file mode 100644 index 0000000..9aa0441 --- /dev/null +++ b/Sources/Data/EF/Players/PlayerExtensions.cs @@ -0,0 +1,27 @@ +using Model.Players; + +namespace Data.EF.Players +{ + internal static class PlayerExtensions + { + public static Player ToModel(this PlayerEntity entity) + { + return new Player(name: entity.Name); + } + + public static IEnumerable ToModels(this IEnumerable entities) + { + return entities.Select(entity => entity.ToModel()); + } + + public static PlayerEntity ToEntity(this Player model) + { + return new PlayerEntity() { Name = model.Name }; + } + + public static IEnumerable ToEntities(this IEnumerable models) + { + return models.Select(model => model.ToEntity()); + } + } +} From 6a47b33f440bb9a6f60cbc7860c7647a9b43d533 Mon Sep 17 00:00:00 2001 From: Alexis DRAI Date: Sat, 1 Oct 2022 00:16:10 +0200 Subject: [PATCH 02/20] :construction: WIP --- .gitignore | 7 +++ Sources/Data/EF/DiceAppDbContext.cs | 56 +++++++++++++++++++++ Sources/Data/EF/Players/PlayerDBContext.cs | 20 -------- Sources/Data/EF/Players/PlayerDBManager.cs | 6 +-- Sources/Data/EF/Players/PlayerEntity.cs | 2 +- Sources/Data/EF/Players/PlayerExtensions.cs | 2 +- 6 files changed, 66 insertions(+), 27 deletions(-) create mode 100644 Sources/Data/EF/DiceAppDbContext.cs delete mode 100644 Sources/Data/EF/Players/PlayerDBContext.cs diff --git a/.gitignore b/.gitignore index e28a900..18f8a66 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,13 @@ ## ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore +# Migrations and DB files +# useful while the DB is still fluid, in the early stages +[Mm]igrations/ +*.db +*.db-wal +*.db-shm + # User-specific files *.rsuser *.suo diff --git a/Sources/Data/EF/DiceAppDbContext.cs b/Sources/Data/EF/DiceAppDbContext.cs new file mode 100644 index 0000000..9422a45 --- /dev/null +++ b/Sources/Data/EF/DiceAppDbContext.cs @@ -0,0 +1,56 @@ +using Data.EF.Players; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Data.EF +{ + public class DiceAppDbContext : DbContext + { + public DbSet Players { get; set; } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + => optionsBuilder.UseSqlite("Data Source=EFDice.DiceApp.db"); + + /* test with this + + > dotnet ef migrations add person_test + + > dotnet ef database update + + ... + + using (DiceAppDbContext db = new()) + { + db.Players.AddRange(PlayerExtensions.ToEntities(new Player[] { + new("Alice"), + new("Bob"), + new("Clyde"), + new("Fucking Kevin GOSH") + })); + + Console.WriteLine("Added, not saved"); + if (db.Players is not null) + { + foreach (PlayerEntity p in db.Players) + { + Console.WriteLine(p.ID + " - " + p.Name); + } + } + + db.SaveChanges(); + + Console.WriteLine("Saved"); + foreach (PlayerEntity p in db.Players) + { + Console.WriteLine(p.ID + " - " + p.Name); + } + } + */ + + + } +} diff --git a/Sources/Data/EF/Players/PlayerDBContext.cs b/Sources/Data/EF/Players/PlayerDBContext.cs deleted file mode 100644 index 228d52a..0000000 --- a/Sources/Data/EF/Players/PlayerDBContext.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Data.EF.Players -{ - internal class PlayerDBContext : DbContext - { - public DbSet PlayersSet { get; set; } - - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - optionsBuilder.UseSqlite("Data Source=EFDice.DiceApp.db"); - } - - } -} diff --git a/Sources/Data/EF/Players/PlayerDBManager.cs b/Sources/Data/EF/Players/PlayerDBManager.cs index 663a725..72d5cd4 100644 --- a/Sources/Data/EF/Players/PlayerDBManager.cs +++ b/Sources/Data/EF/Players/PlayerDBManager.cs @@ -7,15 +7,11 @@ using System.Threading.Tasks; namespace Data.EF.Players { - internal class PlayerDBManager : IManager + public class PlayerDBManager : IManager { - PlayerDBContext context = new PlayerDBContext(); public PlayerEntity Add(PlayerEntity toAdd) { - // just to check... - - context.PlayersSet.Add(toAdd); throw new NotImplementedException(); } diff --git a/Sources/Data/EF/Players/PlayerEntity.cs b/Sources/Data/EF/Players/PlayerEntity.cs index 2e178e7..7d5a34f 100644 --- a/Sources/Data/EF/Players/PlayerEntity.cs +++ b/Sources/Data/EF/Players/PlayerEntity.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; namespace Data.EF.Players { - internal class PlayerEntity + public class PlayerEntity { public Guid ID { get; set; } public string Name { get; set; } diff --git a/Sources/Data/EF/Players/PlayerExtensions.cs b/Sources/Data/EF/Players/PlayerExtensions.cs index 9aa0441..3aa188d 100644 --- a/Sources/Data/EF/Players/PlayerExtensions.cs +++ b/Sources/Data/EF/Players/PlayerExtensions.cs @@ -2,7 +2,7 @@ namespace Data.EF.Players { - internal static class PlayerExtensions + public static class PlayerExtensions { public static Player ToModel(this PlayerEntity entity) { From 32d07e1e3c4ae9e1c2b1ce8f72b5854ff2d1c2c8 Mon Sep 17 00:00:00 2001 From: Alexis DRAI Date: Sat, 1 Oct 2022 22:33:41 +0200 Subject: [PATCH 03/20] :adhesive_bandage: Add default value for layer name --- Sources/Model/Players/Player.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Model/Players/Player.cs b/Sources/Model/Players/Player.cs index e89c98c..428cf55 100644 --- a/Sources/Model/Players/Player.cs +++ b/Sources/Model/Players/Player.cs @@ -12,7 +12,7 @@ namespace Model.Players /// /// a player's unique username /// - public string Name { get; private set; } + public string Name { get; private set; } = "John Doe"; public Player(string name) { if (!string.IsNullOrWhiteSpace(name)) From 8514606fa623f5a834604b4d96f8b4b5506556ab Mon Sep 17 00:00:00 2001 From: Alexis DRAI Date: Sat, 1 Oct 2022 22:36:05 +0200 Subject: [PATCH 04/20] =?UTF-8?q?=E2=9E=96=E2=9E=95=20Juggle=20with=20depe?= =?UTF-8?q?ndencies=20to=20make=20it=20make=20sense?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Sources/App/App.csproj | 1 - Sources/App/Program.cs | 4 +- Sources/DiceApp.sln | 12 +- Sources/DiceAppConsole.sln | 12 +- Sources/Tests/Model_UTs/GameRunnerTest.cs | 6 +- Sources/Tests/Model_UTs/GameTest.cs | 10 +- Sources/Tests/Model_UTs/PlayerManagerTest.cs | 1 - Sources/Tests/Model_UTs/Point.cs | 8 +- Sources/Tests/Model_UTs/TurnTest.cs | 632 +++++++++---------- Sources/Tests/Tests.csproj | 1 - 10 files changed, 337 insertions(+), 350 deletions(-) diff --git a/Sources/App/App.csproj b/Sources/App/App.csproj index a9bd887..428ab87 100644 --- a/Sources/App/App.csproj +++ b/Sources/App/App.csproj @@ -7,7 +7,6 @@ - diff --git a/Sources/App/Program.cs b/Sources/App/Program.cs index badbca6..183b286 100644 --- a/Sources/App/Program.cs +++ b/Sources/App/Program.cs @@ -1,11 +1,11 @@ -using Data; -using Model.Dice; +using Model.Dice; using Model.Dice.Faces; using Model.Games; using Model.Players; using System; using System.Collections.Generic; using System.Linq; +using Data; namespace App { diff --git a/Sources/DiceApp.sln b/Sources/DiceApp.sln index 7545479..7041b1a 100644 --- a/Sources/DiceApp.sln +++ b/Sources/DiceApp.sln @@ -7,10 +7,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Model", "Model\Model.csproj EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Tests\Tests.csproj", "{11BDDDA8-CBED-46EE-A224-144C3CD545A7}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Data", "Data\Data.csproj", "{3047BFD8-EF44-4095-9E54-45D47C7AB212}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{953D2D67-BCE7-412C-B7BB-7C63B5592359}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Data", "Data\Data.csproj", "{E9683741-E603-4ED3-8088-4099D67FCA6D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -25,10 +25,10 @@ Global {11BDDDA8-CBED-46EE-A224-144C3CD545A7}.Debug|Any CPU.Build.0 = Debug|Any CPU {11BDDDA8-CBED-46EE-A224-144C3CD545A7}.Release|Any CPU.ActiveCfg = Release|Any CPU {11BDDDA8-CBED-46EE-A224-144C3CD545A7}.Release|Any CPU.Build.0 = Release|Any CPU - {3047BFD8-EF44-4095-9E54-45D47C7AB212}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3047BFD8-EF44-4095-9E54-45D47C7AB212}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3047BFD8-EF44-4095-9E54-45D47C7AB212}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3047BFD8-EF44-4095-9E54-45D47C7AB212}.Release|Any CPU.Build.0 = Release|Any CPU + {E9683741-E603-4ED3-8088-4099D67FCA6D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {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 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Sources/DiceAppConsole.sln b/Sources/DiceAppConsole.sln index a6b9d77..b7e99f6 100644 --- a/Sources/DiceAppConsole.sln +++ b/Sources/DiceAppConsole.sln @@ -12,10 +12,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "App", "App\App.csproj", "{8 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Tests\Tests.csproj", "{11BDDDA8-CBED-46EE-A224-144C3CD545A7}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Data", "Data\Data.csproj", "{3047BFD8-EF44-4095-9E54-45D47C7AB212}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{953D2D67-BCE7-412C-B7BB-7C63B5592359}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Data", "Data\Data.csproj", "{E9683741-E603-4ED3-8088-4099D67FCA6D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -34,10 +34,10 @@ Global {11BDDDA8-CBED-46EE-A224-144C3CD545A7}.Debug|Any CPU.Build.0 = Debug|Any CPU {11BDDDA8-CBED-46EE-A224-144C3CD545A7}.Release|Any CPU.ActiveCfg = Release|Any CPU {11BDDDA8-CBED-46EE-A224-144C3CD545A7}.Release|Any CPU.Build.0 = Release|Any CPU - {3047BFD8-EF44-4095-9E54-45D47C7AB212}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3047BFD8-EF44-4095-9E54-45D47C7AB212}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3047BFD8-EF44-4095-9E54-45D47C7AB212}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3047BFD8-EF44-4095-9E54-45D47C7AB212}.Release|Any CPU.Build.0 = Release|Any CPU + {E9683741-E603-4ED3-8088-4099D67FCA6D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {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 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Sources/Tests/Model_UTs/GameRunnerTest.cs b/Sources/Tests/Model_UTs/GameRunnerTest.cs index e62d157..b440ba8 100644 --- a/Sources/Tests/Model_UTs/GameRunnerTest.cs +++ b/Sources/Tests/Model_UTs/GameRunnerTest.cs @@ -1,5 +1,4 @@ -using Data; -using Model; +using Model; using Model.Dice; using Model.Dice.Faces; using Model.Games; @@ -8,13 +7,14 @@ using System; using System.Collections.Generic; using System.Linq; using Xunit; +using Data; namespace Tests.Model_UTs { public class GameRunnerTest { private readonly GameRunner stubGameRunner = new Stub().LoadApp(); - + [Fact] public void TestConstructorWhenNoGamesThenNewIEnumerable() { diff --git a/Sources/Tests/Model_UTs/GameTest.cs b/Sources/Tests/Model_UTs/GameTest.cs index 6eddc05..7a9f979 100644 --- a/Sources/Tests/Model_UTs/GameTest.cs +++ b/Sources/Tests/Model_UTs/GameTest.cs @@ -1,16 +1,12 @@ -using Model.Dice.Faces; -using Model.Dice; +using Model.Dice; +using Model.Dice.Faces; using Model.Games; using Model.Players; -using Model; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Xunit; -using static System.Collections.Specialized.BitVector32; -using System.Diagnostics; namespace Tests.Model_UTs { diff --git a/Sources/Tests/Model_UTs/PlayerManagerTest.cs b/Sources/Tests/Model_UTs/PlayerManagerTest.cs index fe94980..5d8e1b1 100644 --- a/Sources/Tests/Model_UTs/PlayerManagerTest.cs +++ b/Sources/Tests/Model_UTs/PlayerManagerTest.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; -using System.Xml.Linq; using Xunit; namespace Tests.Model_UTs diff --git a/Sources/Tests/Model_UTs/Point.cs b/Sources/Tests/Model_UTs/Point.cs index a9274f7..89b5f7f 100644 --- a/Sources/Tests/Model_UTs/Point.cs +++ b/Sources/Tests/Model_UTs/Point.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Tests.Model_UTs +namespace Tests.Model_UTs { public class Point { diff --git a/Sources/Tests/Model_UTs/TurnTest.cs b/Sources/Tests/Model_UTs/TurnTest.cs index b9e8310..cdfbfea 100644 --- a/Sources/Tests/Model_UTs/TurnTest.cs +++ b/Sources/Tests/Model_UTs/TurnTest.cs @@ -1,322 +1,322 @@ -using Model.Dice; -using Model.Dice.Faces; -using Model.Games; -using Model.Players; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using Xunit; - -namespace Tests.Model_UTs -{ - public class TurnTest - - { - private readonly Dictionary, AbstractDieFace> DICE_N_FACES_1; - private readonly Dictionary, AbstractDieFace> DICE_N_FACES_2; - - private static readonly AbstractDieFace FACE_ONE = new NumberDieFace(1); - private static readonly AbstractDieFace FACE_TWO = new NumberDieFace(12); - private static readonly AbstractDieFace FACE_THREE = new ImageDieFace(54); - private static readonly AbstractDieFace FACE_FOUR = new ColorDieFace(16548); - - private readonly static NumberDieFace[] FACES1 = new NumberDieFace[] - { - FACE_ONE as NumberDieFace, - new NumberDieFace(2), - new NumberDieFace(3), - new NumberDieFace(4) - }; - - private readonly static NumberDieFace[] FACES2 = new NumberDieFace[] { - new NumberDieFace(9), - new NumberDieFace(10), - new NumberDieFace(11), - FACE_TWO as NumberDieFace, - new NumberDieFace(13), - new NumberDieFace(14) - }; - - private readonly static ImageDieFace[] FACES3 = new ImageDieFace[] { - new ImageDieFace(13), - new ImageDieFace(27), - new ImageDieFace(38), - FACE_THREE as ImageDieFace - }; - - private readonly static ColorDieFace[] FACES4 = new ColorDieFace[] { - new(11651), - new(24651), - FACE_FOUR as ColorDieFace, - new(412) - }; - - private readonly AbstractDie NUM1 = new NumberDie(FACES1); - private readonly AbstractDie NUM2 = new NumberDie(FACES2); - private readonly AbstractDie IMG1 = new ImageDie(FACES3); - private readonly AbstractDie CLR1 = new ColorDie(FACES4); - - public TurnTest() - { - DICE_N_FACES_1 = new() - { - { NUM1, FACE_ONE }, - { NUM2, FACE_TWO }, - { IMG1, FACE_THREE }, - { CLR1, FACE_FOUR } - }; - DICE_N_FACES_2 = new() - { - { NUM1, FACE_TWO }, - { IMG1, FACE_THREE }, - { CLR1, FACE_FOUR } - }; - } - - - - [Fact] - public void TestCreateWithSpecifiedTimeNotUTCThenValid() - { - // Arrange - DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Local); - Player player = new("Alice"); - Assert.NotEqual(DateTimeKind.Utc, dateTime.Kind); - - // Act - Turn turn = Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1); - - // Assert - Assert.Equal(DateTimeKind.Utc, turn.When.Kind); - Assert.Equal(dateTime.ToUniversalTime(), turn.When); - } - - - - [Fact] - public void TestCreateWithSpecifiedTimeUTCThenValid() - { - // Arrange - DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc); - Player player = new("Bobby"); - Assert.Equal(DateTimeKind.Utc, dateTime.Kind); - - // Act - Turn turn = Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1); - - // Assert - Assert.Equal(DateTimeKind.Utc, turn.When.Kind); - Assert.Equal(dateTime.ToUniversalTime(), turn.When); - } - - - [Fact] - public void TestCreateWithSpecifiedTimeNullPlayerThenException() - { - // Arrange - DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc); - - // Act - void action() => Turn.CreateWithSpecifiedTime(dateTime, null, DICE_N_FACES_1); - - // Assert - Assert.Throws(action); - } - - [Fact] - public void TestCreateWithSpecifiedTimeNullFacesThenException() - { - // Arrange - DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc); - Player player = new("Chucky"); - - // Act - void action() => Turn.CreateWithSpecifiedTime(dateTime, player, null); - - // Assert - Assert.Throws(action); - } - - - [Fact] - public void TestCreateWithSpecifiedTimeEmptyFacesThenException() - { - // Arrange - DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc); - Player player = new("Chucky"); - DICE_N_FACES_1.Clear(); - - // Act - void action() => Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1); - - // Assert - Assert.Throws(action); - } - - - - [Fact] - public void TestCreateWithDefaultTimeThenValid() - { - // Arrange - Player player = new("Chloe"); - - // Act - Turn turn = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1); - - // Assert - Assert.Equal(DateTimeKind.Utc, turn.When.Kind); - Assert.Equal(DateTime.Now.ToUniversalTime().Date, turn.When.Date); - // N.B.: might fail between 11:59:59PM and 00:00:00AM - } - - - - [Fact] - public void TestToStringValidIfAllNormal() - { - // Arrange - DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc); - string name = "Bobby"; - Player player = new(name); - string expected = $"2018-06-15 16:30:00 -- {name} rolled: " - + FACE_ONE.ToString() + " " - + FACE_TWO.ToString() + " " - + FACE_THREE.ToString() + " " - + FACE_FOUR.ToString(); - - Turn turn = Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1); - - // Act - string actual = turn.ToString(); - Debug.WriteLine(actual); - - // Assert - Assert.Equal(expected, actual); - } - - [Fact] - public void TestDiceNFacesProperty() - { - // Arrange - Player player = new("Erika"); - - // Act - Turn turn = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1); - IEnumerable, AbstractDieFace>> expected = DICE_N_FACES_1.AsEnumerable(); - - // Assert - Assert.Equal(expected, turn.DiceNFaces); +using Model.Dice; +using Model.Dice.Faces; +using Model.Games; +using Model.Players; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using Xunit; + +namespace Tests.Model_UTs +{ + public class TurnTest + + { + private readonly Dictionary, AbstractDieFace> DICE_N_FACES_1; + private readonly Dictionary, AbstractDieFace> DICE_N_FACES_2; + + private static readonly AbstractDieFace FACE_ONE = new NumberDieFace(1); + private static readonly AbstractDieFace FACE_TWO = new NumberDieFace(12); + private static readonly AbstractDieFace FACE_THREE = new ImageDieFace(54); + private static readonly AbstractDieFace FACE_FOUR = new ColorDieFace(16548); + + private readonly static NumberDieFace[] FACES1 = new NumberDieFace[] + { + FACE_ONE as NumberDieFace, + new NumberDieFace(2), + new NumberDieFace(3), + new NumberDieFace(4) + }; + + private readonly static NumberDieFace[] FACES2 = new NumberDieFace[] { + new NumberDieFace(9), + new NumberDieFace(10), + new NumberDieFace(11), + FACE_TWO as NumberDieFace, + new NumberDieFace(13), + new NumberDieFace(14) + }; + + private readonly static ImageDieFace[] FACES3 = new ImageDieFace[] { + new ImageDieFace(13), + new ImageDieFace(27), + new ImageDieFace(38), + FACE_THREE as ImageDieFace + }; + + private readonly static ColorDieFace[] FACES4 = new ColorDieFace[] { + new(11651), + new(24651), + FACE_FOUR as ColorDieFace, + new(412) + }; + + private readonly AbstractDie NUM1 = new NumberDie(FACES1); + private readonly AbstractDie NUM2 = new NumberDie(FACES2); + private readonly AbstractDie IMG1 = new ImageDie(FACES3); + private readonly AbstractDie CLR1 = new ColorDie(FACES4); + + public TurnTest() + { + DICE_N_FACES_1 = new() + { + { NUM1, FACE_ONE }, + { NUM2, FACE_TWO }, + { IMG1, FACE_THREE }, + { CLR1, FACE_FOUR } + }; + DICE_N_FACES_2 = new() + { + { NUM1, FACE_TWO }, + { IMG1, FACE_THREE }, + { CLR1, FACE_FOUR } + }; + } + + + + [Fact] + public void TestCreateWithSpecifiedTimeNotUTCThenValid() + { + // Arrange + DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Local); + Player player = new("Alice"); + Assert.NotEqual(DateTimeKind.Utc, dateTime.Kind); + + // Act + Turn turn = Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1); + + // Assert + Assert.Equal(DateTimeKind.Utc, turn.When.Kind); + Assert.Equal(dateTime.ToUniversalTime(), turn.When); + } + + + + [Fact] + public void TestCreateWithSpecifiedTimeUTCThenValid() + { + // Arrange + DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc); + Player player = new("Bobby"); + Assert.Equal(DateTimeKind.Utc, dateTime.Kind); + + // Act + Turn turn = Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1); + + // Assert + Assert.Equal(DateTimeKind.Utc, turn.When.Kind); + Assert.Equal(dateTime.ToUniversalTime(), turn.When); + } + + + [Fact] + public void TestCreateWithSpecifiedTimeNullPlayerThenException() + { + // Arrange + DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc); + + // Act + void action() => Turn.CreateWithSpecifiedTime(dateTime, null, DICE_N_FACES_1); + + // Assert + Assert.Throws(action); + } + + [Fact] + public void TestCreateWithSpecifiedTimeNullFacesThenException() + { + // Arrange + DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc); + Player player = new("Chucky"); + + // Act + void action() => Turn.CreateWithSpecifiedTime(dateTime, player, null); + + // Assert + Assert.Throws(action); + } + + + [Fact] + public void TestCreateWithSpecifiedTimeEmptyFacesThenException() + { + // Arrange + DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc); + Player player = new("Chucky"); + DICE_N_FACES_1.Clear(); + + // Act + void action() => Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1); + + // Assert + Assert.Throws(action); + } + + + + [Fact] + public void TestCreateWithDefaultTimeThenValid() + { + // Arrange + Player player = new("Chloe"); + + // Act + Turn turn = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1); + + // Assert + Assert.Equal(DateTimeKind.Utc, turn.When.Kind); + Assert.Equal(DateTime.Now.ToUniversalTime().Date, turn.When.Date); + // N.B.: might fail between 11:59:59PM and 00:00:00AM + } + + + + [Fact] + public void TestToStringValidIfAllNormal() + { + // Arrange + DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc); + string name = "Bobby"; + Player player = new(name); + string expected = $"2018-06-15 16:30:00 -- {name} rolled: " + + FACE_ONE.ToString() + " " + + FACE_TWO.ToString() + " " + + FACE_THREE.ToString() + " " + + FACE_FOUR.ToString(); + + Turn turn = Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1); + + // Act + string actual = turn.ToString(); + Debug.WriteLine(actual); + + // Assert + Assert.Equal(expected, actual); + } + + [Fact] + public void TestDiceNFacesProperty() + { + // Arrange + Player player = new("Erika"); + + // Act + Turn turn = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1); + IEnumerable, AbstractDieFace>> expected = DICE_N_FACES_1.AsEnumerable(); + + // Assert + Assert.Equal(expected, turn.DiceNFaces); + } + + [Fact] + public void TestEqualsFalseIfNotTurn() + { + // Arrange + Point point; + Turn turn; + Player player = new("Freddie"); + + // Act + point = new(1, 2); + turn = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1); + + // Assert + Assert.False(point.Equals(turn)); + Assert.False(point.GetHashCode().Equals(turn.GetHashCode())); + Assert.False(turn.Equals(point)); + Assert.False(turn.GetHashCode().Equals(point.GetHashCode())); + } + + [Fact] + public void TestGoesThruToSecondMethodIfObjIsTypeTurn() + { + // Arrange + Object t1; + Turn t2; + Player player1 = new Player("Marvin"); + Player player2 = new Player("Noah"); + + // Act + t1 = Turn.CreateWithDefaultTime(player1, DICE_N_FACES_1); + t2 = Turn.CreateWithDefaultTime(player2, DICE_N_FACES_2); + + // Assert + Assert.False(t1.Equals(t2)); + Assert.False(t1.GetHashCode().Equals(t2.GetHashCode())); + Assert.False(t2.Equals(t1)); + Assert.False(t2.GetHashCode().Equals(t1.GetHashCode())); + } + + + [Fact] + public void TestEqualsFalseIfNotSamePlayer() + { + // Arrange + Player player1= new("Panama"); + Player player2= new("Clyde"); + + // Act + Turn t1 = Turn.CreateWithDefaultTime(player1, DICE_N_FACES_2); + Turn t2 = Turn.CreateWithDefaultTime(player2, DICE_N_FACES_2); + + // Assert + Assert.False(t1.Equals(t2)); + Assert.False(t1.GetHashCode().Equals(t2.GetHashCode())); + Assert.False(t2.Equals(t1)); + Assert.False(t2.GetHashCode().Equals(t1.GetHashCode())); } - [Fact] - public void TestEqualsFalseIfNotTurn() - { - // Arrange - Point point; - Turn turn; - Player player = new("Freddie"); - - // Act - point = new(1, 2); - turn = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1); - - // Assert - Assert.False(point.Equals(turn)); - Assert.False(point.GetHashCode().Equals(turn.GetHashCode())); - Assert.False(turn.Equals(point)); - Assert.False(turn.GetHashCode().Equals(point.GetHashCode())); - } - - [Fact] - public void TestGoesThruToSecondMethodIfObjIsTypeTurn() - { - // Arrange - Object t1; - Turn t2; - Player player1 = new Player("Marvin"); - Player player2 = new Player("Noah"); - - // Act - t1 = Turn.CreateWithDefaultTime(player1, DICE_N_FACES_1); - t2 = Turn.CreateWithDefaultTime(player2, DICE_N_FACES_2); - - // Assert - Assert.False(t1.Equals(t2)); - Assert.False(t1.GetHashCode().Equals(t2.GetHashCode())); - Assert.False(t2.Equals(t1)); - Assert.False(t2.GetHashCode().Equals(t1.GetHashCode())); - } - - - [Fact] - public void TestEqualsFalseIfNotSamePlayer() - { - // Arrange - Player player1= new("Panama"); - Player player2= new("Clyde"); - - // Act - Turn t1 = Turn.CreateWithDefaultTime(player1, DICE_N_FACES_2); - Turn t2 = Turn.CreateWithDefaultTime(player2, DICE_N_FACES_2); - - // Assert - Assert.False(t1.Equals(t2)); - Assert.False(t1.GetHashCode().Equals(t2.GetHashCode())); - Assert.False(t2.Equals(t1)); - Assert.False(t2.GetHashCode().Equals(t1.GetHashCode())); + [Fact] + public void TestEqualsFalseIfNotSameTime() + { + // Arrange + Player player = new("Oscar"); + + // Act + Turn t1 = Turn.CreateWithSpecifiedTime(new DateTime(1994, 07, 10), player, DICE_N_FACES_1); + Turn t2 = Turn.CreateWithSpecifiedTime(new DateTime(1991, 08, 20), player, DICE_N_FACES_1); + + // Assert + Assert.False(t1.Equals(t2)); + Assert.False(t1.GetHashCode().Equals(t2.GetHashCode())); + Assert.False(t2.Equals(t1)); + Assert.False(t2.GetHashCode().Equals(t1.GetHashCode())); } - [Fact] - public void TestEqualsFalseIfNotSameTime() - { - // Arrange - Player player = new("Oscar"); - - // Act - Turn t1 = Turn.CreateWithSpecifiedTime(new DateTime(1994, 07, 10), player, DICE_N_FACES_1); - Turn t2 = Turn.CreateWithSpecifiedTime(new DateTime(1991, 08, 20), player, DICE_N_FACES_1); - - // Assert - Assert.False(t1.Equals(t2)); - Assert.False(t1.GetHashCode().Equals(t2.GetHashCode())); - Assert.False(t2.Equals(t1)); - Assert.False(t2.GetHashCode().Equals(t1.GetHashCode())); + [Fact] + public void TestEqualsFalseIfNotSameDiceNFaces() + { + // Arrange + Player player = new("Django"); + + // Act + Turn t1 = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1); + Turn t2 = Turn.CreateWithDefaultTime(player, DICE_N_FACES_2); + + // Assert + Assert.False(t1.Equals(t2)); + Assert.False(t1.GetHashCode().Equals(t2.GetHashCode())); + Assert.False(t2.Equals(t1)); + Assert.False(t2.GetHashCode().Equals(t1.GetHashCode())); } - [Fact] - public void TestEqualsFalseIfNotSameDiceNFaces() - { - // Arrange - Player player = new("Django"); - - // Act - Turn t1 = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1); - Turn t2 = Turn.CreateWithDefaultTime(player, DICE_N_FACES_2); - - // Assert - Assert.False(t1.Equals(t2)); - Assert.False(t1.GetHashCode().Equals(t2.GetHashCode())); - Assert.False(t2.Equals(t1)); - Assert.False(t2.GetHashCode().Equals(t1.GetHashCode())); - } - - [Fact] - public void TestEqualsTrueIfExactlySameProperties() - { - // Arrange - Player player = new("Elyse"); - - // Act - Turn t1 = Turn.CreateWithSpecifiedTime(new DateTime(1990, 04, 29), player, DICE_N_FACES_1); - Turn t2 = Turn.CreateWithSpecifiedTime(new DateTime(1990, 04, 29), player, DICE_N_FACES_1); - - // Assert - Assert.True(t1.Equals(t2)); - Assert.True(t1.GetHashCode().Equals(t2.GetHashCode())); - Assert.True(t2.Equals(t1)); - Assert.True(t2.GetHashCode().Equals(t1.GetHashCode())); - } - } -} + [Fact] + public void TestEqualsTrueIfExactlySameProperties() + { + // Arrange + Player player = new("Elyse"); + + // Act + Turn t1 = Turn.CreateWithSpecifiedTime(new DateTime(1990, 04, 29), player, DICE_N_FACES_1); + Turn t2 = Turn.CreateWithSpecifiedTime(new DateTime(1990, 04, 29), player, DICE_N_FACES_1); + + // Assert + Assert.True(t1.Equals(t2)); + Assert.True(t1.GetHashCode().Equals(t2.GetHashCode())); + Assert.True(t2.Equals(t1)); + Assert.True(t2.GetHashCode().Equals(t1.GetHashCode())); + } + } +} diff --git a/Sources/Tests/Tests.csproj b/Sources/Tests/Tests.csproj index 2d2506b..2075e70 100644 --- a/Sources/Tests/Tests.csproj +++ b/Sources/Tests/Tests.csproj @@ -21,7 +21,6 @@ - From 7c4c7bcfcb2541cc874c7899fa235805fd158b52 Mon Sep 17 00:00:00 2001 From: Alexis DRAI Date: Sat, 1 Oct 2022 22:37:01 +0200 Subject: [PATCH 05/20] =?UTF-8?q?=F0=9F=94=A7=F0=9F=97=83=EF=B8=8F=20Make?= =?UTF-8?q?=20Data/Program.cs=20executable,=20add=20Db=20stub,=20improve?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Sources/Data/Data.csproj | 18 ++++++---- Sources/Data/EF/DiceAppDbContext.cs | 39 +-------------------- Sources/Data/EF/DiceAppDbContextWithStub.cs | 25 +++++++++++++ Sources/Data/EF/Players/PlayerEntity.cs | 5 ++- Sources/Data/Program.cs | 30 ++++++++++++++++ 5 files changed, 71 insertions(+), 46 deletions(-) create mode 100644 Sources/Data/EF/DiceAppDbContextWithStub.cs create mode 100644 Sources/Data/Program.cs diff --git a/Sources/Data/Data.csproj b/Sources/Data/Data.csproj index 749750b..7e30ad7 100644 --- a/Sources/Data/Data.csproj +++ b/Sources/Data/Data.csproj @@ -1,20 +1,24 @@ - + + + Exe net6.0 enable enable $(MSBuildProjectDirectory) + - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/Sources/Data/EF/DiceAppDbContext.cs b/Sources/Data/EF/DiceAppDbContext.cs index 9422a45..2140253 100644 --- a/Sources/Data/EF/DiceAppDbContext.cs +++ b/Sources/Data/EF/DiceAppDbContext.cs @@ -10,47 +10,10 @@ namespace Data.EF { public class DiceAppDbContext : DbContext { - public DbSet Players { get; set; } + public DbSet? Players { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseSqlite("Data Source=EFDice.DiceApp.db"); - /* test with this - - > dotnet ef migrations add person_test - - > dotnet ef database update - - ... - - using (DiceAppDbContext db = new()) - { - db.Players.AddRange(PlayerExtensions.ToEntities(new Player[] { - new("Alice"), - new("Bob"), - new("Clyde"), - new("Fucking Kevin GOSH") - })); - - Console.WriteLine("Added, not saved"); - if (db.Players is not null) - { - foreach (PlayerEntity p in db.Players) - { - Console.WriteLine(p.ID + " - " + p.Name); - } - } - - db.SaveChanges(); - - Console.WriteLine("Saved"); - foreach (PlayerEntity p in db.Players) - { - Console.WriteLine(p.ID + " - " + p.Name); - } - } - */ - - } } diff --git a/Sources/Data/EF/DiceAppDbContextWithStub.cs b/Sources/Data/EF/DiceAppDbContextWithStub.cs new file mode 100644 index 0000000..89e2672 --- /dev/null +++ b/Sources/Data/EF/DiceAppDbContextWithStub.cs @@ -0,0 +1,25 @@ +using Data.EF.Players; +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Data.EF +{ + internal class DiceAppDbContextWithStub : DiceAppDbContext + { + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.Entity().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" } + ); + } + } +} diff --git a/Sources/Data/EF/Players/PlayerEntity.cs b/Sources/Data/EF/Players/PlayerEntity.cs index 7d5a34f..aa2d14c 100644 --- a/Sources/Data/EF/Players/PlayerEntity.cs +++ b/Sources/Data/EF/Players/PlayerEntity.cs @@ -1,4 +1,5 @@ -using System; +using Microsoft.EntityFrameworkCore; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -6,9 +7,11 @@ using System.Threading.Tasks; namespace Data.EF.Players { + [Index(nameof(Name), IsUnique = true)] public class PlayerEntity { public Guid ID { get; set; } + public string Name { get; set; } } } diff --git a/Sources/Data/Program.cs b/Sources/Data/Program.cs new file mode 100644 index 0000000..b448831 --- /dev/null +++ b/Sources/Data/Program.cs @@ -0,0 +1,30 @@ + +using Data.EF; +using Data.EF.Players; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Internal; +using Model.Players; +using System.Collections; +using System.ComponentModel; +using System.Diagnostics; +using System.Runtime.Intrinsics.Arm; + +namespace Data +{ + class Program + { + static void Main(string[] args) + { + using (DiceAppDbContext db = new DiceAppDbContextWithStub()) // we will remove the "WithStub" bit when we release + { + if (db.Players is not null) + { + foreach (PlayerEntity entity in db.Players) + { + Debug.WriteLine($"{entity.ID} -- {entity.Name}"); + } + } + } + } + } +} \ No newline at end of file From c60935b79340508c37c9d5cffcd49ae330d5540b Mon Sep 17 00:00:00 2001 From: Alexis Drai Date: Sat, 1 Oct 2022 20:21:28 +0000 Subject: [PATCH 06/20] Update 'README.md' --- README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/README.md b/README.md index 8bbb37b..69e6130 100644 --- a/README.md +++ b/README.md @@ -14,12 +14,40 @@ ## To use the app +### Console prototype + Open the *DiceAppConsole.sln* solution and navigate to the *App* project. The *Program.cs* file has a `Main()` method that can be launched. *If you simply load DiceApp.sln, Visual Studio will not load the App project...* The console prototype loads a stub with a few small games that you can test, and you can create new everything (with a little patience). +### DiceApp DB context with stub + +We also now have a budding persistence solution, using Entity Framework. + +Open the any of our *solutions* and navigate to the *Data* project. The *Program.cs* file has a `Main()` method that can be launched. + +The NuGet packages are managed in files that are versioned, so you shouldn't need to manage the dependencies yourself. *"The Line"* is taken care of too. + +However, you do need to create the migrations and DB. + +First, in Visual Studio's terminal ("Developer PowerShell"), go to *DiceApp/Sources/Data*, and make sure Entity Framework is installed and / or updated. +``` +dotnet tool install --global dotnet-ef +dotnet tool update --global dotnet-ef +``` +Now the migrations and DB. Since we have a `DbContext` *and* and `DbContextWithStub`, you will need to specify which one to use. Make sure you are in *DiceApp/Sources/Data*. +``` +dotnet ef migrations add dice_app_db --context DiceAppDbContextWithStub +dotnet ef database update --context DiceAppDbContextWithStub +``` +You can now run the *Data* program, and check out your local DB. + +You may not want to read tables in the debug window -- in which case, just download [DB Brower for SQLite](https://sqlitebrowser.org/dl/) and open the *.db* file in it. + +Ta-da. + ## 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) From a65edca2fd148a5f8a22690ad7ca594f7f1a0d6e Mon Sep 17 00:00:00 2001 From: Alexis DRAI Date: Sat, 1 Oct 2022 22:43:14 +0200 Subject: [PATCH 07/20] :adhesive_bandage: Make Program internal and static --- Sources/Data/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Data/Program.cs b/Sources/Data/Program.cs index b448831..1d57fda 100644 --- a/Sources/Data/Program.cs +++ b/Sources/Data/Program.cs @@ -11,7 +11,7 @@ using System.Runtime.Intrinsics.Arm; namespace Data { - class Program + internal static class Program { static void Main(string[] args) { From 753789bcd47b0217d6fdfb4a5a688e799ec1b6d0 Mon Sep 17 00:00:00 2001 From: Alexis DRAI Date: Sun, 2 Oct 2022 00:22:09 +0200 Subject: [PATCH 08/20] :construction: Make data classes internal, start implementing DBManager --- Sources/Data/EF/DiceAppDbContext.cs | 2 +- Sources/Data/EF/Players/PlayerDBManager.cs | 24 ++++++++++++++---- Sources/Data/EF/Players/PlayerEntity.cs | 9 +++++-- Sources/Data/EF/Players/PlayerExtensions.cs | 2 +- Sources/Data/Program.cs | 28 ++++++++++++++++----- Sources/Model/Players/Player.cs | 2 +- Sources/Model/Players/PlayerManager.cs | 2 +- 7 files changed, 52 insertions(+), 17 deletions(-) diff --git a/Sources/Data/EF/DiceAppDbContext.cs b/Sources/Data/EF/DiceAppDbContext.cs index 2140253..867d2d6 100644 --- a/Sources/Data/EF/DiceAppDbContext.cs +++ b/Sources/Data/EF/DiceAppDbContext.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; namespace Data.EF { - public class DiceAppDbContext : DbContext + internal class DiceAppDbContext : DbContext { public DbSet? Players { get; set; } diff --git a/Sources/Data/EF/Players/PlayerDBManager.cs b/Sources/Data/EF/Players/PlayerDBManager.cs index 72d5cd4..7509c3b 100644 --- a/Sources/Data/EF/Players/PlayerDBManager.cs +++ b/Sources/Data/EF/Players/PlayerDBManager.cs @@ -1,4 +1,5 @@ -using Model; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using Model; using System; using System.Collections.Generic; using System.Linq; @@ -7,17 +8,30 @@ using System.Threading.Tasks; namespace Data.EF.Players { - public class PlayerDBManager : IManager + internal class PlayerDBManager : IManager, IDisposable { - + private readonly DiceAppDbContext db = new DiceAppDbContextWithStub(); + + public void Dispose() + { + db.Dispose(); + } + public PlayerEntity Add(PlayerEntity toAdd) { - throw new NotImplementedException(); + if (db.Players!.Where(entity => entity.Name == toAdd.Name).Any()) + { + throw new ArgumentException("this username is already taken", nameof(toAdd)); + } + EntityEntry ee = db.Players!.Add(toAdd); + db.SaveChanges(); + return (PlayerEntity)ee.Entity; } + public IEnumerable GetAll() { - throw new NotImplementedException(); + return db.Players!.AsEnumerable(); } public PlayerEntity GetOneByName(string name) diff --git a/Sources/Data/EF/Players/PlayerEntity.cs b/Sources/Data/EF/Players/PlayerEntity.cs index aa2d14c..5464a3f 100644 --- a/Sources/Data/EF/Players/PlayerEntity.cs +++ b/Sources/Data/EF/Players/PlayerEntity.cs @@ -8,10 +8,15 @@ using System.Threading.Tasks; namespace Data.EF.Players { [Index(nameof(Name), IsUnique = true)] - public class PlayerEntity + internal class PlayerEntity { public Guid ID { get; set; } - public string Name { get; set; } + public string? Name { get; set; } + + public override string? ToString() + { + return $"{ID} -- {Name}"; + } } } diff --git a/Sources/Data/EF/Players/PlayerExtensions.cs b/Sources/Data/EF/Players/PlayerExtensions.cs index 3aa188d..9aa0441 100644 --- a/Sources/Data/EF/Players/PlayerExtensions.cs +++ b/Sources/Data/EF/Players/PlayerExtensions.cs @@ -2,7 +2,7 @@ namespace Data.EF.Players { - public static class PlayerExtensions + internal static class PlayerExtensions { public static Player ToModel(this PlayerEntity entity) { diff --git a/Sources/Data/Program.cs b/Sources/Data/Program.cs index 1d57fda..0daa7d0 100644 --- a/Sources/Data/Program.cs +++ b/Sources/Data/Program.cs @@ -15,14 +15,30 @@ namespace Data { static void Main(string[] args) { - using (DiceAppDbContext db = new DiceAppDbContextWithStub()) // we will remove the "WithStub" bit when we release + using (PlayerDBManager playerDBManager = new()) { - if (db.Players is not null) + PrintTable(playerDBManager.GetAll(), "Before"); + try { - foreach (PlayerEntity entity in db.Players) - { - Debug.WriteLine($"{entity.ID} -- {entity.Name}"); - } + playerDBManager.Add(PlayerExtensions.ToEntity(new Player("Ernesto"))); + + } + catch (ArgumentException ex) + { + Debug.WriteLine($"{ex.Message}\n... Never mind"); + } + PrintTable(playerDBManager.GetAll(), "After"); + } + } + + static void PrintTable(IEnumerable table, string description) + { + Debug.WriteLine(description); + if (table is not null) + { + foreach (var entity in table) + { + Debug.WriteLine(entity); } } } diff --git a/Sources/Model/Players/Player.cs b/Sources/Model/Players/Player.cs index 428cf55..e89c98c 100644 --- a/Sources/Model/Players/Player.cs +++ b/Sources/Model/Players/Player.cs @@ -12,7 +12,7 @@ namespace Model.Players /// /// a player's unique username /// - public string Name { get; private set; } = "John Doe"; + public string Name { get; private set; } public Player(string name) { if (!string.IsNullOrWhiteSpace(name)) diff --git a/Sources/Model/Players/PlayerManager.cs b/Sources/Model/Players/PlayerManager.cs index c5637da..aa4db9b 100644 --- a/Sources/Model/Players/PlayerManager.cs +++ b/Sources/Model/Players/PlayerManager.cs @@ -19,7 +19,7 @@ namespace Model.Players /// add a new player /// /// player to be added - /// added player, or null if was null + /// added player public Player Add(Player toAdd) { if (toAdd is null) From e14f5e01a6dd04dfef42c47e23c61309d380ed35 Mon Sep 17 00:00:00 2001 From: Alexis DRAI Date: Sun, 2 Oct 2022 00:36:45 +0200 Subject: [PATCH 09/20] :adhesive_bandage: Seal PlayerDBManager --- Sources/Data/EF/Players/PlayerDBManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Data/EF/Players/PlayerDBManager.cs b/Sources/Data/EF/Players/PlayerDBManager.cs index 7509c3b..d84cdfa 100644 --- a/Sources/Data/EF/Players/PlayerDBManager.cs +++ b/Sources/Data/EF/Players/PlayerDBManager.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; namespace Data.EF.Players { - internal class PlayerDBManager : IManager, IDisposable + internal sealed class PlayerDBManager : IManager, IDisposable { private readonly DiceAppDbContext db = new DiceAppDbContextWithStub(); From 678d1f7de582e6a7c47ac94e47e4c60e86622d5b Mon Sep 17 00:00:00 2001 From: "mohammad_zafir.jeeawody" Date: Sat, 1 Oct 2022 23:44:20 +0200 Subject: [PATCH 10/20] validation method --- Sources/Model/Dice/DieManager.cs | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/Sources/Model/Dice/DieManager.cs b/Sources/Model/Dice/DieManager.cs index 71654cf..c1a1aae 100644 --- a/Sources/Model/Dice/DieManager.cs +++ b/Sources/Model/Dice/DieManager.cs @@ -12,6 +12,15 @@ namespace Model.Dice public KeyValuePair>> Add(KeyValuePair>> toAdd) { // on trim la clé d'abord + if (toAdd.Key == null) + { + throw new ArgumentNullException(nameof(toAdd), "param should not be null"); + + } + if (diceGroups.Contains(toAdd)) + { + throw new ArgumentException("this username is already taken", nameof(toAdd)); + } diceGroups.Add(toAdd.Key.Trim(), toAdd.Value); return toAdd; } @@ -30,12 +39,28 @@ namespace Model.Dice { // les groupes de dés nommés : // ils sont case-sensistive, mais "mon jeu" == "mon jeu " == " mon jeu" - return new KeyValuePair>>(name, diceGroups[name]); + if (name != null) + { + return new KeyValuePair>>(name, diceGroups[name]); + } + else { + throw new ArgumentNullException(nameof(name), "param should not be null"); + + + } } public void Remove(KeyValuePair>> toRemove) { - diceGroups.Remove(toRemove.Key); + if (toRemove.Key != null) + { + throw new ArgumentNullException(nameof(toRemove), "param should not be null"); } + else + { + diceGroups.Remove(toRemove.Key); + } + + } public KeyValuePair>> Update(KeyValuePair>> before, KeyValuePair>> after) From 1683414231f855a71989f0feac28b7519d1f4597 Mon Sep 17 00:00:00 2001 From: Alexis DRAI Date: Sun, 2 Oct 2022 00:47:34 +0200 Subject: [PATCH 11/20] :art: :bug: fix bug in Remove, use affirmative statements, reformat --- Sources/Model/Dice/DieManager.cs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Sources/Model/Dice/DieManager.cs b/Sources/Model/Dice/DieManager.cs index c1a1aae..5c13ea3 100644 --- a/Sources/Model/Dice/DieManager.cs +++ b/Sources/Model/Dice/DieManager.cs @@ -12,9 +12,9 @@ namespace Model.Dice public KeyValuePair>> Add(KeyValuePair>> toAdd) { // on trim la clé d'abord - if (toAdd.Key == null) + if (string.IsNullOrWhiteSpace(toAdd.Key)) { - throw new ArgumentNullException(nameof(toAdd), "param should not be null"); + throw new ArgumentNullException(nameof(toAdd), "param should not be null or empty"); } if (diceGroups.Contains(toAdd)) @@ -39,22 +39,22 @@ namespace Model.Dice { // les groupes de dés nommés : // ils sont case-sensistive, mais "mon jeu" == "mon jeu " == " mon jeu" - if (name != null) + if (string.IsNullOrWhiteSpace(name)) { - return new KeyValuePair>>(name, diceGroups[name]); + throw new ArgumentNullException(nameof(name), "param should not be null or empty"); } - else { - throw new ArgumentNullException(nameof(name), "param should not be null"); - - + else + { + return new KeyValuePair>>(name, diceGroups[name]); } } public void Remove(KeyValuePair>> toRemove) { - if (toRemove.Key != null) - { - throw new ArgumentNullException(nameof(toRemove), "param should not be null"); } + if (toRemove.Key is null) + { + throw new ArgumentNullException(nameof(toRemove), "param should not be null"); + } else { diceGroups.Remove(toRemove.Key); From a0d3caf91cc9b5a209607dbb672928f35994b4ce Mon Sep 17 00:00:00 2001 From: Alexis DRAI Date: Fri, 30 Sep 2022 12:54:20 +0200 Subject: [PATCH 12/20] :poop: Include methods that throw NotSupportedExceptions for now --- Sources/Model/Dice/DieManager.cs | 5 +++++ Sources/Model/Games/GameRunner.cs | 5 +++++ Sources/Model/IManager.cs | 4 +++- Sources/Model/Players/PlayerManager.cs | 5 +++++ 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Sources/Model/Dice/DieManager.cs b/Sources/Model/Dice/DieManager.cs index 06e3a52..71654cf 100644 --- a/Sources/Model/Dice/DieManager.cs +++ b/Sources/Model/Dice/DieManager.cs @@ -21,6 +21,11 @@ namespace Model.Dice return diceGroups.AsEnumerable(); } + public KeyValuePair>> GetOneByID(Guid ID) + { + throw new NotImplementedException(); + } + public KeyValuePair>> GetOneByName(string name) { // les groupes de dés nommés : diff --git a/Sources/Model/Games/GameRunner.cs b/Sources/Model/Games/GameRunner.cs index eb24f80..d58085e 100644 --- a/Sources/Model/Games/GameRunner.cs +++ b/Sources/Model/Games/GameRunner.cs @@ -108,5 +108,10 @@ namespace Model.Games game.PerformTurn(current); game.PrepareNextPlayer(current); } + + public Game GetOneByID(Guid ID) + { + throw new NotImplementedException(); + } } } diff --git a/Sources/Model/IManager.cs b/Sources/Model/IManager.cs index 67eafe0..8261ffa 100644 --- a/Sources/Model/IManager.cs +++ b/Sources/Model/IManager.cs @@ -1,10 +1,12 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace Model { public interface IManager { public T Add(T toAdd); public T GetOneByName(string name); + public T GetOneByID(Guid ID); public IEnumerable GetAll(); public T Update(T before, T after); public void Remove(T toRemove); diff --git a/Sources/Model/Players/PlayerManager.cs b/Sources/Model/Players/PlayerManager.cs index aa4db9b..1b65565 100644 --- a/Sources/Model/Players/PlayerManager.cs +++ b/Sources/Model/Players/PlayerManager.cs @@ -95,5 +95,10 @@ namespace Model.Players // the built-in Remove() method will use our redefined Equals(), using Name only players.Remove(toRemove); } + + public Player GetOneByID(Guid ID) + { + throw new NotImplementedException(); + } } } From 23dbbbfb2136113376cea92fec460e1e56f9b572 Mon Sep 17 00:00:00 2001 From: Alexis Drai Date: Sat, 1 Oct 2022 20:21:28 +0000 Subject: [PATCH 13/20] Update 'README.md' --- README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/README.md b/README.md index 8bbb37b..69e6130 100644 --- a/README.md +++ b/README.md @@ -14,12 +14,40 @@ ## To use the app +### Console prototype + Open the *DiceAppConsole.sln* solution and navigate to the *App* project. The *Program.cs* file has a `Main()` method that can be launched. *If you simply load DiceApp.sln, Visual Studio will not load the App project...* The console prototype loads a stub with a few small games that you can test, and you can create new everything (with a little patience). +### DiceApp DB context with stub + +We also now have a budding persistence solution, using Entity Framework. + +Open the any of our *solutions* and navigate to the *Data* project. The *Program.cs* file has a `Main()` method that can be launched. + +The NuGet packages are managed in files that are versioned, so you shouldn't need to manage the dependencies yourself. *"The Line"* is taken care of too. + +However, you do need to create the migrations and DB. + +First, in Visual Studio's terminal ("Developer PowerShell"), go to *DiceApp/Sources/Data*, and make sure Entity Framework is installed and / or updated. +``` +dotnet tool install --global dotnet-ef +dotnet tool update --global dotnet-ef +``` +Now the migrations and DB. Since we have a `DbContext` *and* and `DbContextWithStub`, you will need to specify which one to use. Make sure you are in *DiceApp/Sources/Data*. +``` +dotnet ef migrations add dice_app_db --context DiceAppDbContextWithStub +dotnet ef database update --context DiceAppDbContextWithStub +``` +You can now run the *Data* program, and check out your local DB. + +You may not want to read tables in the debug window -- in which case, just download [DB Brower for SQLite](https://sqlitebrowser.org/dl/) and open the *.db* file in it. + +Ta-da. + ## 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) From b84818610e340b536012df5757ff20c5d4077579 Mon Sep 17 00:00:00 2001 From: "mohammad_zafir.jeeawody" Date: Sat, 1 Oct 2022 23:44:20 +0200 Subject: [PATCH 14/20] validation method --- Sources/Model/Dice/DieManager.cs | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/Sources/Model/Dice/DieManager.cs b/Sources/Model/Dice/DieManager.cs index 71654cf..c1a1aae 100644 --- a/Sources/Model/Dice/DieManager.cs +++ b/Sources/Model/Dice/DieManager.cs @@ -12,6 +12,15 @@ namespace Model.Dice public KeyValuePair>> Add(KeyValuePair>> toAdd) { // on trim la clé d'abord + if (toAdd.Key == null) + { + throw new ArgumentNullException(nameof(toAdd), "param should not be null"); + + } + if (diceGroups.Contains(toAdd)) + { + throw new ArgumentException("this username is already taken", nameof(toAdd)); + } diceGroups.Add(toAdd.Key.Trim(), toAdd.Value); return toAdd; } @@ -30,12 +39,28 @@ namespace Model.Dice { // les groupes de dés nommés : // ils sont case-sensistive, mais "mon jeu" == "mon jeu " == " mon jeu" - return new KeyValuePair>>(name, diceGroups[name]); + if (name != null) + { + return new KeyValuePair>>(name, diceGroups[name]); + } + else { + throw new ArgumentNullException(nameof(name), "param should not be null"); + + + } } public void Remove(KeyValuePair>> toRemove) { - diceGroups.Remove(toRemove.Key); + if (toRemove.Key != null) + { + throw new ArgumentNullException(nameof(toRemove), "param should not be null"); } + else + { + diceGroups.Remove(toRemove.Key); + } + + } public KeyValuePair>> Update(KeyValuePair>> before, KeyValuePair>> after) From 55436e15a9d32349f767135bf87758240dcb057d Mon Sep 17 00:00:00 2001 From: Alexis DRAI Date: Sun, 2 Oct 2022 00:47:34 +0200 Subject: [PATCH 15/20] :art: :bug: fix bug in Remove, use affirmative statements, reformat --- Sources/Model/Dice/DieManager.cs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Sources/Model/Dice/DieManager.cs b/Sources/Model/Dice/DieManager.cs index c1a1aae..5c13ea3 100644 --- a/Sources/Model/Dice/DieManager.cs +++ b/Sources/Model/Dice/DieManager.cs @@ -12,9 +12,9 @@ namespace Model.Dice public KeyValuePair>> Add(KeyValuePair>> toAdd) { // on trim la clé d'abord - if (toAdd.Key == null) + if (string.IsNullOrWhiteSpace(toAdd.Key)) { - throw new ArgumentNullException(nameof(toAdd), "param should not be null"); + throw new ArgumentNullException(nameof(toAdd), "param should not be null or empty"); } if (diceGroups.Contains(toAdd)) @@ -39,22 +39,22 @@ namespace Model.Dice { // les groupes de dés nommés : // ils sont case-sensistive, mais "mon jeu" == "mon jeu " == " mon jeu" - if (name != null) + if (string.IsNullOrWhiteSpace(name)) { - return new KeyValuePair>>(name, diceGroups[name]); + throw new ArgumentNullException(nameof(name), "param should not be null or empty"); } - else { - throw new ArgumentNullException(nameof(name), "param should not be null"); - - + else + { + return new KeyValuePair>>(name, diceGroups[name]); } } public void Remove(KeyValuePair>> toRemove) { - if (toRemove.Key != null) - { - throw new ArgumentNullException(nameof(toRemove), "param should not be null"); } + if (toRemove.Key is null) + { + throw new ArgumentNullException(nameof(toRemove), "param should not be null"); + } else { diceGroups.Remove(toRemove.Key); From cb4851c0cab8e4ac01de1dc63a84f89aa41ba6ff Mon Sep 17 00:00:00 2001 From: Alexis DRAI Date: Sun, 2 Oct 2022 00:58:13 +0200 Subject: [PATCH 16/20] :rotating_light: Implement IManager --- Sources/Data/EF/Players/PlayerDBManager.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Sources/Data/EF/Players/PlayerDBManager.cs b/Sources/Data/EF/Players/PlayerDBManager.cs index d84cdfa..50f4054 100644 --- a/Sources/Data/EF/Players/PlayerDBManager.cs +++ b/Sources/Data/EF/Players/PlayerDBManager.cs @@ -48,5 +48,10 @@ namespace Data.EF.Players { throw new NotImplementedException(); } + + public PlayerEntity GetOneByID(Guid ID) + { + throw new NotImplementedException(); + } } } From 937a57ec11232f1ff1a6f84192f28a54afe6b500 Mon Sep 17 00:00:00 2001 From: Alexis DRAI Date: Sun, 2 Oct 2022 01:08:41 +0200 Subject: [PATCH 17/20] :fire: Shrink the debug program --- Sources/Data/Program.cs | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/Sources/Data/Program.cs b/Sources/Data/Program.cs index 0daa7d0..936aae1 100644 --- a/Sources/Data/Program.cs +++ b/Sources/Data/Program.cs @@ -15,32 +15,10 @@ namespace Data { static void Main(string[] args) { - using (PlayerDBManager playerDBManager = new()) - { - PrintTable(playerDBManager.GetAll(), "Before"); - try - { - playerDBManager.Add(PlayerExtensions.ToEntity(new Player("Ernesto"))); - - } - catch (ArgumentException ex) - { - Debug.WriteLine($"{ex.Message}\n... Never mind"); - } - PrintTable(playerDBManager.GetAll(), "After"); - } - } - - static void PrintTable(IEnumerable table, string description) - { - Debug.WriteLine(description); - if (table is not null) - { - foreach (var entity in table) - { - Debug.WriteLine(entity); - } - } + using PlayerDBManager playerDBManager = new(); + try { playerDBManager.Add(PlayerExtensions.ToEntity(new Player("Ernesto"))); } + catch (ArgumentException ex) { Debug.WriteLine($"{ex.Message}\n... Never mind"); } + foreach (PlayerEntity entity in playerDBManager.GetAll()) { Debug.WriteLine(entity); } } } } \ No newline at end of file From fc6a71801fab6ef963ec477438937f599396e959 Mon Sep 17 00:00:00 2001 From: Alexis DRAI Date: Sun, 2 Oct 2022 01:51:07 +0200 Subject: [PATCH 18/20] :white_check_mark: Get UTs done --- Sources/Data/EF/DiceAppDbContext.cs | 2 +- Sources/Data/EF/DiceAppDbContextWithStub.cs | 2 +- Sources/Data/EF/Players/PlayerDBManager.cs | 2 +- Sources/Data/EF/Players/PlayerEntity.cs | 26 ++- Sources/Data/EF/Players/PlayerExtensions.cs | 2 +- Sources/Data/Program.cs | 2 +- Sources/Model/Players/Player.cs | 2 +- Sources/Tests/Model_UTs/PlayerEntityTest.cs | 182 ++++++++++++++++++ .../Tests/Model_UTs/PlayerExtensionsTest.cs | 93 +++++++++ Sources/Tests/Model_UTs/PlayerTest.cs | 13 ++ 10 files changed, 318 insertions(+), 8 deletions(-) create mode 100644 Sources/Tests/Model_UTs/PlayerEntityTest.cs create mode 100644 Sources/Tests/Model_UTs/PlayerExtensionsTest.cs diff --git a/Sources/Data/EF/DiceAppDbContext.cs b/Sources/Data/EF/DiceAppDbContext.cs index 867d2d6..2140253 100644 --- a/Sources/Data/EF/DiceAppDbContext.cs +++ b/Sources/Data/EF/DiceAppDbContext.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; namespace Data.EF { - internal class DiceAppDbContext : DbContext + public class DiceAppDbContext : DbContext { public DbSet? Players { get; set; } diff --git a/Sources/Data/EF/DiceAppDbContextWithStub.cs b/Sources/Data/EF/DiceAppDbContextWithStub.cs index 89e2672..51f225b 100644 --- a/Sources/Data/EF/DiceAppDbContextWithStub.cs +++ b/Sources/Data/EF/DiceAppDbContextWithStub.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; namespace Data.EF { - internal class DiceAppDbContextWithStub : DiceAppDbContext + public class DiceAppDbContextWithStub : DiceAppDbContext { protected override void OnModelCreating(ModelBuilder modelBuilder) { diff --git a/Sources/Data/EF/Players/PlayerDBManager.cs b/Sources/Data/EF/Players/PlayerDBManager.cs index 50f4054..7b8e00d 100644 --- a/Sources/Data/EF/Players/PlayerDBManager.cs +++ b/Sources/Data/EF/Players/PlayerDBManager.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; namespace Data.EF.Players { - internal sealed class PlayerDBManager : IManager, IDisposable + public sealed class PlayerDBManager : IManager, IDisposable { private readonly DiceAppDbContext db = new DiceAppDbContextWithStub(); diff --git a/Sources/Data/EF/Players/PlayerEntity.cs b/Sources/Data/EF/Players/PlayerEntity.cs index 5464a3f..1629f8b 100644 --- a/Sources/Data/EF/Players/PlayerEntity.cs +++ b/Sources/Data/EF/Players/PlayerEntity.cs @@ -1,4 +1,5 @@ using Microsoft.EntityFrameworkCore; +using Model.Players; using System; using System.Collections.Generic; using System.Linq; @@ -8,15 +9,36 @@ using System.Threading.Tasks; namespace Data.EF.Players { [Index(nameof(Name), IsUnique = true)] - internal class PlayerEntity + public sealed class PlayerEntity : IEquatable { public Guid ID { get; set; } public string? Name { get; set; } + public override bool Equals(object? obj) + { + if (obj is not Player) + { + return false; + } + return Equals(obj as Player); + } + + public bool Equals(PlayerEntity? other) + { + return other is not null && this.ID == other!.ID && this.Name == other.Name; + } + + public override int GetHashCode() + { + return HashCode.Combine(ID, Name); + } + public override string? ToString() { - return $"{ID} -- {Name}"; + return $"{ID.ToString().ToUpper()} -- {Name}"; } + + } } diff --git a/Sources/Data/EF/Players/PlayerExtensions.cs b/Sources/Data/EF/Players/PlayerExtensions.cs index 9aa0441..3aa188d 100644 --- a/Sources/Data/EF/Players/PlayerExtensions.cs +++ b/Sources/Data/EF/Players/PlayerExtensions.cs @@ -2,7 +2,7 @@ namespace Data.EF.Players { - internal static class PlayerExtensions + public static class PlayerExtensions { public static Player ToModel(this PlayerEntity entity) { diff --git a/Sources/Data/Program.cs b/Sources/Data/Program.cs index 936aae1..2de2b23 100644 --- a/Sources/Data/Program.cs +++ b/Sources/Data/Program.cs @@ -16,7 +16,7 @@ namespace Data static void Main(string[] args) { using PlayerDBManager playerDBManager = new(); - try { playerDBManager.Add(PlayerExtensions.ToEntity(new Player("Ernesto"))); } + try { playerDBManager.Add(new Player("Ernesto").ToEntity()); } catch (ArgumentException ex) { Debug.WriteLine($"{ex.Message}\n... Never mind"); } foreach (PlayerEntity entity in playerDBManager.GetAll()) { Debug.WriteLine(entity); } } diff --git a/Sources/Model/Players/Player.cs b/Sources/Model/Players/Player.cs index e89c98c..86d214f 100644 --- a/Sources/Model/Players/Player.cs +++ b/Sources/Model/Players/Player.cs @@ -37,7 +37,7 @@ namespace Model.Players public bool Equals(Player other) { - return Name.ToUpper() == other.Name.ToUpper(); // equality is case insensitive + return other is not null && Name.ToUpper() == other.Name.ToUpper(); // equality is case insensitive } public override bool Equals(object obj) diff --git a/Sources/Tests/Model_UTs/PlayerEntityTest.cs b/Sources/Tests/Model_UTs/PlayerEntityTest.cs new file mode 100644 index 0000000..2f990e0 --- /dev/null +++ b/Sources/Tests/Model_UTs/PlayerEntityTest.cs @@ -0,0 +1,182 @@ +using Model.Players; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; +using Data.EF.Players; + +namespace Tests.Model_UTs +{ + public class PlayerEntityTest + { + [Fact] + public void TestGetSetName() + { + // Arrange + PlayerEntity player = new(); + string expected = "Alice"; + + // Act + player.Name = expected; + string actual = player.Name; + + // Assert + Assert.Equal(expected, actual); + } + + [Fact] + public void TestGetSetID() + { + // Arrange + PlayerEntity player = new(); + Guid expected = new("c8f60957-dd36-4e47-a7ce-1281f4f8bea4"); + + // Act + player.ID = expected; + Guid actual = player.ID; + + // Assert + Assert.Equal(expected, actual); + } + + [Fact] + public void TestToString() + { + // Arrange + PlayerEntity player = new(); + string IDString = "c8f60957-dd36-4e47-a7ce-1281f4f8bea4"; + string nameString = "Bob"; + player.ID = new Guid(IDString); + player.Name = nameString; + + // Act + string expected = $"{IDString.ToUpper()} -- {nameString}"; + + // Assert + Assert.Equal(expected, player.ToString()); + } + + [Fact] + public void TestEqualsWhenNotPlayerEntityThenFalse() + { + // Arrange + Point point; + PlayerEntity entity; + + // Act + point = new(1, 2); + entity = new() { Name = "Clyde" }; + + // Assert + Assert.False(point.Equals(entity)); + Assert.False(entity.Equals(point)); + } + + [Fact] + public void TestEqualsWhenNullThenFalse() + { + // Arrange + PlayerEntity entity; + + // Act + entity = new() { Name = "Clyde" }; + + // Assert + Assert.False(entity.Equals(null)); + } + + [Fact] + public void TestGoesThruToSecondMethodIfObjIsTypePlayerEntity() + { + // Arrange + Object p1; + PlayerEntity p2; + + // Act + p1 = new PlayerEntity() { Name = "Marvin" }; + p2 = new() { Name = "Clyde" }; + + // Assert + Assert.False(p1.Equals(p2)); + Assert.False(p2.Equals(p1)); + } + + [Fact] + public void TestEqualsFalseIfNotSameNameOrID() + { + // Arrange + PlayerEntity p1; + PlayerEntity p2; + PlayerEntity p3; + + // Act + 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)); + Assert.False(p1.Equals(p3)); + Assert.False(p2.Equals(p1)); + Assert.False(p2.Equals(p3)); + Assert.False(p3.Equals(p1)); + Assert.False(p3.Equals(p2)); + } + + [Fact] + public void TestEqualsTrueIfSameIDAndName() + { + // Arrange + PlayerEntity p1; + PlayerEntity p2; + + // Act + 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)); + Assert.True(p2.Equals(p1)); + } + + [Fact] + public void TestSameHashFalseIfNotSameNameOrID() + { + // Arrange + PlayerEntity p1; + PlayerEntity p2; + PlayerEntity p3; + + // Act + 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())); + Assert.False(p1.GetHashCode().Equals(p3.GetHashCode())); + Assert.False(p2.GetHashCode().Equals(p1.GetHashCode())); + Assert.False(p2.GetHashCode().Equals(p3.GetHashCode())); + Assert.False(p3.GetHashCode().Equals(p1.GetHashCode())); + Assert.False(p3.GetHashCode().Equals(p2.GetHashCode())); + } + + [Fact] + public void TestSameHashTrueIfSame() + { + // Arrange + PlayerEntity p1; + PlayerEntity p2; + + // Act + 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())); + Assert.True(p2.GetHashCode().Equals(p1.GetHashCode())); + } + } +} diff --git a/Sources/Tests/Model_UTs/PlayerExtensionsTest.cs b/Sources/Tests/Model_UTs/PlayerExtensionsTest.cs new file mode 100644 index 0000000..deb1b63 --- /dev/null +++ b/Sources/Tests/Model_UTs/PlayerExtensionsTest.cs @@ -0,0 +1,93 @@ +using Data.EF.Players; +using Model.Players; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace Tests.Model_UTs +{ + public class PlayerExtensionsTest + { + [Fact] + public void TestToModel() + { + // Arrange + string name = "Alice"; + PlayerEntity entity = new() { Name = name }; + Player expected = new(name); + + // Act + Player actual = entity.ToModel(); + + // Assert + Assert.Equal(expected, actual); + } + + [Fact] + public void TestToEntity() + { + // Arrange + string name = "Bob"; + Player model = new(name); + PlayerEntity expected = new() { Name = name }; + + // Act + PlayerEntity actual = model.ToEntity(); + + // Assert + Assert.Equal(expected, actual); + } + + [Fact] + public void TestToModels() + { + // Arrange + string n1 = "Alice", n2 = "Bob", n3 = "Clyde"; + PlayerEntity[] entities = new PlayerEntity[] { + new() {Name = n1 }, + new() {Name = n2 }, + new() {Name = n3 }, + }; + + IEnumerable expected = new Player[] { + new(n1), + new(n2), + new(n3) + }.AsEnumerable(); + + // Act + IEnumerable actual = entities.ToModels(); + + // Assert + Assert.Equal(expected, actual); + } + + [Fact] + public void TestToEntities() + { + // Arrange + string n1 = "Alice", n2 = "Bob", n3 = "Clyde"; + Player[] models = new Player[] { + new(n1), + new(n2), + new(n3) + }; + + IEnumerable expected = new PlayerEntity[] { + new() {Name = n1 }, + new() {Name = n2 }, + new() {Name = n3 }, + }.AsEnumerable(); + + // Act + IEnumerable actual = models.ToEntities(); + + // Assert + Assert.Equal(expected, actual); + } + + } +} diff --git a/Sources/Tests/Model_UTs/PlayerTest.cs b/Sources/Tests/Model_UTs/PlayerTest.cs index e0c14ee..d800d5d 100644 --- a/Sources/Tests/Model_UTs/PlayerTest.cs +++ b/Sources/Tests/Model_UTs/PlayerTest.cs @@ -128,6 +128,19 @@ namespace Tests.Model_UTs Assert.False(p2.Equals(p1)); } + [Fact] + public void TestEqualsFalseIfNull() + { + // Arrange + Player player; + + // Act + player = new("Panama"); + + // Assert + Assert.False(player.Equals(null)); + } + [Theory] [InlineData("devoN")] [InlineData(" devon")] From ca6b62574e187960726c7018b758ccf7a68953be Mon Sep 17 00:00:00 2001 From: Alexis DRAI Date: Sun, 2 Oct 2022 01:55:12 +0200 Subject: [PATCH 19/20] :bug: Fix class mixup --- Sources/Data/EF/Players/PlayerEntity.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Data/EF/Players/PlayerEntity.cs b/Sources/Data/EF/Players/PlayerEntity.cs index 1629f8b..6a504cc 100644 --- a/Sources/Data/EF/Players/PlayerEntity.cs +++ b/Sources/Data/EF/Players/PlayerEntity.cs @@ -17,11 +17,11 @@ namespace Data.EF.Players public override bool Equals(object? obj) { - if (obj is not Player) + if (obj is not PlayerEntity) { return false; } - return Equals(obj as Player); + return Equals(obj as PlayerEntity); } public bool Equals(PlayerEntity? other) From b8ea8a020e9567fe15fa84603a2b7e86aa9678d8 Mon Sep 17 00:00:00 2001 From: Alexis DRAI Date: Sun, 2 Oct 2022 01:59:22 +0200 Subject: [PATCH 20/20] =?UTF-8?q?=F0=9F=9A=9A=20Organize=20UTs=20in=20fold?= =?UTF-8?q?ers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Players}/PlayerEntityTest.cs | 5 +- .../Players}/PlayerExtensionsTest.cs | 2 +- .../Model_UTs/{ => Games}/GameRunnerTest.cs | 614 ++++++++--------- .../Tests/Model_UTs/{ => Games}/GameTest.cs | 2 +- .../Tests/Model_UTs/{ => Games}/TurnTest.cs | 644 +++++++++--------- .../{ => Players}/PlayerManagerTest.cs | 2 +- .../Model_UTs/{ => Players}/PlayerTest.cs | 4 +- 7 files changed, 637 insertions(+), 636 deletions(-) rename Sources/Tests/{Model_UTs => Data_UTs/Players}/PlayerEntityTest.cs (98%) rename Sources/Tests/{Model_UTs => Data_UTs/Players}/PlayerExtensionsTest.cs (98%) rename Sources/Tests/Model_UTs/{ => Games}/GameRunnerTest.cs (96%) rename Sources/Tests/Model_UTs/{ => Games}/GameTest.cs (99%) rename Sources/Tests/Model_UTs/{ => Games}/TurnTest.cs (95%) rename Sources/Tests/Model_UTs/{ => Players}/PlayerManagerTest.cs (99%) rename Sources/Tests/Model_UTs/{ => Players}/PlayerTest.cs (99%) diff --git a/Sources/Tests/Model_UTs/PlayerEntityTest.cs b/Sources/Tests/Data_UTs/Players/PlayerEntityTest.cs similarity index 98% rename from Sources/Tests/Model_UTs/PlayerEntityTest.cs rename to Sources/Tests/Data_UTs/Players/PlayerEntityTest.cs index 2f990e0..c6df368 100644 --- a/Sources/Tests/Model_UTs/PlayerEntityTest.cs +++ b/Sources/Tests/Data_UTs/Players/PlayerEntityTest.cs @@ -6,8 +6,9 @@ using System.Text; using System.Threading.Tasks; using Xunit; using Data.EF.Players; +using Tests.Model_UTs; -namespace Tests.Model_UTs +namespace Tests.Data_UTs.Players { public class PlayerEntityTest { @@ -91,7 +92,7 @@ namespace Tests.Model_UTs public void TestGoesThruToSecondMethodIfObjIsTypePlayerEntity() { // Arrange - Object p1; + object p1; PlayerEntity p2; // Act diff --git a/Sources/Tests/Model_UTs/PlayerExtensionsTest.cs b/Sources/Tests/Data_UTs/Players/PlayerExtensionsTest.cs similarity index 98% rename from Sources/Tests/Model_UTs/PlayerExtensionsTest.cs rename to Sources/Tests/Data_UTs/Players/PlayerExtensionsTest.cs index deb1b63..bfa109e 100644 --- a/Sources/Tests/Model_UTs/PlayerExtensionsTest.cs +++ b/Sources/Tests/Data_UTs/Players/PlayerExtensionsTest.cs @@ -7,7 +7,7 @@ using System.Text; using System.Threading.Tasks; using Xunit; -namespace Tests.Model_UTs +namespace Tests.Data_UTs.Players { public class PlayerExtensionsTest { diff --git a/Sources/Tests/Model_UTs/GameRunnerTest.cs b/Sources/Tests/Model_UTs/Games/GameRunnerTest.cs similarity index 96% rename from Sources/Tests/Model_UTs/GameRunnerTest.cs rename to Sources/Tests/Model_UTs/Games/GameRunnerTest.cs index b440ba8..7c48169 100644 --- a/Sources/Tests/Model_UTs/GameRunnerTest.cs +++ b/Sources/Tests/Model_UTs/Games/GameRunnerTest.cs @@ -1,307 +1,307 @@ -using Model; -using Model.Dice; -using Model.Dice.Faces; -using Model.Games; -using Model.Players; -using System; -using System.Collections.Generic; -using System.Linq; -using Xunit; -using Data; - -namespace Tests.Model_UTs -{ - public class GameRunnerTest - { - private readonly GameRunner stubGameRunner = new Stub().LoadApp(); - - [Fact] - public void TestConstructorWhenNoGamesThenNewIEnumerable() - { - // Arrange - GameRunner gameRunner = new(new PlayerManager(), new DieManager()); - IEnumerable expected; - IEnumerable actual; - - // Act - expected = new List().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 expected; - IEnumerable 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 expected = new List() { game1, game2 }.AsEnumerable(); - IEnumerable actual = new List() - { - 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(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(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(action); - } - - [Fact] - public void TestRemoveWhenGiveenNonExistentThenFailsSilently() - { - // Arrange - GameRunner gameRunner = stubGameRunner; - Game notGame = new("blargh", new PlayerManager(), gameRunner.GetAll().First().Dice); - IEnumerable expected = gameRunner.GetAll(); - - // Act - gameRunner.Remove(notGame); - IEnumerable 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(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(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(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(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()); - } - } -} +using Model; +using Model.Dice; +using Model.Dice.Faces; +using Model.Games; +using Model.Players; +using System; +using System.Collections.Generic; +using System.Linq; +using Xunit; +using Data; + +namespace Tests.Model_UTs.Games +{ + public class GameRunnerTest + { + private readonly GameRunner stubGameRunner = new Stub().LoadApp(); + + [Fact] + public void TestConstructorWhenNoGamesThenNewIEnumerable() + { + // Arrange + GameRunner gameRunner = new(new PlayerManager(), new DieManager()); + IEnumerable expected; + IEnumerable actual; + + // Act + expected = new List().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 expected; + IEnumerable 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 expected = new List() { game1, game2 }.AsEnumerable(); + IEnumerable actual = new List() + { + 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(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(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(action); + } + + [Fact] + public void TestRemoveWhenGiveenNonExistentThenFailsSilently() + { + // Arrange + GameRunner gameRunner = stubGameRunner; + Game notGame = new("blargh", new PlayerManager(), gameRunner.GetAll().First().Dice); + IEnumerable expected = gameRunner.GetAll(); + + // Act + gameRunner.Remove(notGame); + IEnumerable 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(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(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(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(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()); + } + } +} diff --git a/Sources/Tests/Model_UTs/GameTest.cs b/Sources/Tests/Model_UTs/Games/GameTest.cs similarity index 99% rename from Sources/Tests/Model_UTs/GameTest.cs rename to Sources/Tests/Model_UTs/Games/GameTest.cs index 7a9f979..bd498a5 100644 --- a/Sources/Tests/Model_UTs/GameTest.cs +++ b/Sources/Tests/Model_UTs/Games/GameTest.cs @@ -8,7 +8,7 @@ using System.Diagnostics; using System.Linq; using Xunit; -namespace Tests.Model_UTs +namespace Tests.Model_UTs.Games { public class GameTest { diff --git a/Sources/Tests/Model_UTs/TurnTest.cs b/Sources/Tests/Model_UTs/Games/TurnTest.cs similarity index 95% rename from Sources/Tests/Model_UTs/TurnTest.cs rename to Sources/Tests/Model_UTs/Games/TurnTest.cs index cdfbfea..a0975ea 100644 --- a/Sources/Tests/Model_UTs/TurnTest.cs +++ b/Sources/Tests/Model_UTs/Games/TurnTest.cs @@ -1,322 +1,322 @@ -using Model.Dice; -using Model.Dice.Faces; -using Model.Games; -using Model.Players; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using Xunit; - -namespace Tests.Model_UTs -{ - public class TurnTest - - { - private readonly Dictionary, AbstractDieFace> DICE_N_FACES_1; - private readonly Dictionary, AbstractDieFace> DICE_N_FACES_2; - - private static readonly AbstractDieFace FACE_ONE = new NumberDieFace(1); - private static readonly AbstractDieFace FACE_TWO = new NumberDieFace(12); - private static readonly AbstractDieFace FACE_THREE = new ImageDieFace(54); - private static readonly AbstractDieFace FACE_FOUR = new ColorDieFace(16548); - - private readonly static NumberDieFace[] FACES1 = new NumberDieFace[] - { - FACE_ONE as NumberDieFace, - new NumberDieFace(2), - new NumberDieFace(3), - new NumberDieFace(4) - }; - - private readonly static NumberDieFace[] FACES2 = new NumberDieFace[] { - new NumberDieFace(9), - new NumberDieFace(10), - new NumberDieFace(11), - FACE_TWO as NumberDieFace, - new NumberDieFace(13), - new NumberDieFace(14) - }; - - private readonly static ImageDieFace[] FACES3 = new ImageDieFace[] { - new ImageDieFace(13), - new ImageDieFace(27), - new ImageDieFace(38), - FACE_THREE as ImageDieFace - }; - - private readonly static ColorDieFace[] FACES4 = new ColorDieFace[] { - new(11651), - new(24651), - FACE_FOUR as ColorDieFace, - new(412) - }; - - private readonly AbstractDie NUM1 = new NumberDie(FACES1); - private readonly AbstractDie NUM2 = new NumberDie(FACES2); - private readonly AbstractDie IMG1 = new ImageDie(FACES3); - private readonly AbstractDie CLR1 = new ColorDie(FACES4); - - public TurnTest() - { - DICE_N_FACES_1 = new() - { - { NUM1, FACE_ONE }, - { NUM2, FACE_TWO }, - { IMG1, FACE_THREE }, - { CLR1, FACE_FOUR } - }; - DICE_N_FACES_2 = new() - { - { NUM1, FACE_TWO }, - { IMG1, FACE_THREE }, - { CLR1, FACE_FOUR } - }; - } - - - - [Fact] - public void TestCreateWithSpecifiedTimeNotUTCThenValid() - { - // Arrange - DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Local); - Player player = new("Alice"); - Assert.NotEqual(DateTimeKind.Utc, dateTime.Kind); - - // Act - Turn turn = Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1); - - // Assert - Assert.Equal(DateTimeKind.Utc, turn.When.Kind); - Assert.Equal(dateTime.ToUniversalTime(), turn.When); - } - - - - [Fact] - public void TestCreateWithSpecifiedTimeUTCThenValid() - { - // Arrange - DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc); - Player player = new("Bobby"); - Assert.Equal(DateTimeKind.Utc, dateTime.Kind); - - // Act - Turn turn = Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1); - - // Assert - Assert.Equal(DateTimeKind.Utc, turn.When.Kind); - Assert.Equal(dateTime.ToUniversalTime(), turn.When); - } - - - [Fact] - public void TestCreateWithSpecifiedTimeNullPlayerThenException() - { - // Arrange - DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc); - - // Act - void action() => Turn.CreateWithSpecifiedTime(dateTime, null, DICE_N_FACES_1); - - // Assert - Assert.Throws(action); - } - - [Fact] - public void TestCreateWithSpecifiedTimeNullFacesThenException() - { - // Arrange - DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc); - Player player = new("Chucky"); - - // Act - void action() => Turn.CreateWithSpecifiedTime(dateTime, player, null); - - // Assert - Assert.Throws(action); - } - - - [Fact] - public void TestCreateWithSpecifiedTimeEmptyFacesThenException() - { - // Arrange - DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc); - Player player = new("Chucky"); - DICE_N_FACES_1.Clear(); - - // Act - void action() => Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1); - - // Assert - Assert.Throws(action); - } - - - - [Fact] - public void TestCreateWithDefaultTimeThenValid() - { - // Arrange - Player player = new("Chloe"); - - // Act - Turn turn = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1); - - // Assert - Assert.Equal(DateTimeKind.Utc, turn.When.Kind); - Assert.Equal(DateTime.Now.ToUniversalTime().Date, turn.When.Date); - // N.B.: might fail between 11:59:59PM and 00:00:00AM - } - - - - [Fact] - public void TestToStringValidIfAllNormal() - { - // Arrange - DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc); - string name = "Bobby"; - Player player = new(name); - string expected = $"2018-06-15 16:30:00 -- {name} rolled: " - + FACE_ONE.ToString() + " " - + FACE_TWO.ToString() + " " - + FACE_THREE.ToString() + " " - + FACE_FOUR.ToString(); - - Turn turn = Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1); - - // Act - string actual = turn.ToString(); - Debug.WriteLine(actual); - - // Assert - Assert.Equal(expected, actual); - } - - [Fact] - public void TestDiceNFacesProperty() - { - // Arrange - Player player = new("Erika"); - - // Act - Turn turn = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1); - IEnumerable, AbstractDieFace>> expected = DICE_N_FACES_1.AsEnumerable(); - - // Assert - Assert.Equal(expected, turn.DiceNFaces); - } - - [Fact] - public void TestEqualsFalseIfNotTurn() - { - // Arrange - Point point; - Turn turn; - Player player = new("Freddie"); - - // Act - point = new(1, 2); - turn = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1); - - // Assert - Assert.False(point.Equals(turn)); - Assert.False(point.GetHashCode().Equals(turn.GetHashCode())); - Assert.False(turn.Equals(point)); - Assert.False(turn.GetHashCode().Equals(point.GetHashCode())); - } - - [Fact] - public void TestGoesThruToSecondMethodIfObjIsTypeTurn() - { - // Arrange - Object t1; - Turn t2; - Player player1 = new Player("Marvin"); - Player player2 = new Player("Noah"); - - // Act - t1 = Turn.CreateWithDefaultTime(player1, DICE_N_FACES_1); - t2 = Turn.CreateWithDefaultTime(player2, DICE_N_FACES_2); - - // Assert - Assert.False(t1.Equals(t2)); - Assert.False(t1.GetHashCode().Equals(t2.GetHashCode())); - Assert.False(t2.Equals(t1)); - Assert.False(t2.GetHashCode().Equals(t1.GetHashCode())); - } - - - [Fact] - public void TestEqualsFalseIfNotSamePlayer() - { - // Arrange - Player player1= new("Panama"); - Player player2= new("Clyde"); - - // Act - Turn t1 = Turn.CreateWithDefaultTime(player1, DICE_N_FACES_2); - Turn t2 = Turn.CreateWithDefaultTime(player2, DICE_N_FACES_2); - - // Assert - Assert.False(t1.Equals(t2)); - Assert.False(t1.GetHashCode().Equals(t2.GetHashCode())); - Assert.False(t2.Equals(t1)); - Assert.False(t2.GetHashCode().Equals(t1.GetHashCode())); - } - - [Fact] - public void TestEqualsFalseIfNotSameTime() - { - // Arrange - Player player = new("Oscar"); - - // Act - Turn t1 = Turn.CreateWithSpecifiedTime(new DateTime(1994, 07, 10), player, DICE_N_FACES_1); - Turn t2 = Turn.CreateWithSpecifiedTime(new DateTime(1991, 08, 20), player, DICE_N_FACES_1); - - // Assert - Assert.False(t1.Equals(t2)); - Assert.False(t1.GetHashCode().Equals(t2.GetHashCode())); - Assert.False(t2.Equals(t1)); - Assert.False(t2.GetHashCode().Equals(t1.GetHashCode())); - } - - [Fact] - public void TestEqualsFalseIfNotSameDiceNFaces() - { - // Arrange - Player player = new("Django"); - - // Act - Turn t1 = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1); - Turn t2 = Turn.CreateWithDefaultTime(player, DICE_N_FACES_2); - - // Assert - Assert.False(t1.Equals(t2)); - Assert.False(t1.GetHashCode().Equals(t2.GetHashCode())); - Assert.False(t2.Equals(t1)); - Assert.False(t2.GetHashCode().Equals(t1.GetHashCode())); - } - - [Fact] - public void TestEqualsTrueIfExactlySameProperties() - { - // Arrange - Player player = new("Elyse"); - - // Act - Turn t1 = Turn.CreateWithSpecifiedTime(new DateTime(1990, 04, 29), player, DICE_N_FACES_1); - Turn t2 = Turn.CreateWithSpecifiedTime(new DateTime(1990, 04, 29), player, DICE_N_FACES_1); - - // Assert - Assert.True(t1.Equals(t2)); - Assert.True(t1.GetHashCode().Equals(t2.GetHashCode())); - Assert.True(t2.Equals(t1)); - Assert.True(t2.GetHashCode().Equals(t1.GetHashCode())); - } - } -} +using Model.Dice; +using Model.Dice.Faces; +using Model.Games; +using Model.Players; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using Xunit; + +namespace Tests.Model_UTs.Games +{ + public class TurnTest + + { + private readonly Dictionary, AbstractDieFace> DICE_N_FACES_1; + private readonly Dictionary, AbstractDieFace> DICE_N_FACES_2; + + private static readonly AbstractDieFace FACE_ONE = new NumberDieFace(1); + private static readonly AbstractDieFace FACE_TWO = new NumberDieFace(12); + private static readonly AbstractDieFace FACE_THREE = new ImageDieFace(54); + private static readonly AbstractDieFace FACE_FOUR = new ColorDieFace(16548); + + private readonly static NumberDieFace[] FACES1 = new NumberDieFace[] + { + FACE_ONE as NumberDieFace, + new NumberDieFace(2), + new NumberDieFace(3), + new NumberDieFace(4) + }; + + private readonly static NumberDieFace[] FACES2 = new NumberDieFace[] { + new NumberDieFace(9), + new NumberDieFace(10), + new NumberDieFace(11), + FACE_TWO as NumberDieFace, + new NumberDieFace(13), + new NumberDieFace(14) + }; + + private readonly static ImageDieFace[] FACES3 = new ImageDieFace[] { + new ImageDieFace(13), + new ImageDieFace(27), + new ImageDieFace(38), + FACE_THREE as ImageDieFace + }; + + private readonly static ColorDieFace[] FACES4 = new ColorDieFace[] { + new(11651), + new(24651), + FACE_FOUR as ColorDieFace, + new(412) + }; + + private readonly AbstractDie NUM1 = new NumberDie(FACES1); + private readonly AbstractDie NUM2 = new NumberDie(FACES2); + private readonly AbstractDie IMG1 = new ImageDie(FACES3); + private readonly AbstractDie CLR1 = new ColorDie(FACES4); + + public TurnTest() + { + DICE_N_FACES_1 = new() + { + { NUM1, FACE_ONE }, + { NUM2, FACE_TWO }, + { IMG1, FACE_THREE }, + { CLR1, FACE_FOUR } + }; + DICE_N_FACES_2 = new() + { + { NUM1, FACE_TWO }, + { IMG1, FACE_THREE }, + { CLR1, FACE_FOUR } + }; + } + + + + [Fact] + public void TestCreateWithSpecifiedTimeNotUTCThenValid() + { + // Arrange + DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Local); + Player player = new("Alice"); + Assert.NotEqual(DateTimeKind.Utc, dateTime.Kind); + + // Act + Turn turn = Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1); + + // Assert + Assert.Equal(DateTimeKind.Utc, turn.When.Kind); + Assert.Equal(dateTime.ToUniversalTime(), turn.When); + } + + + + [Fact] + public void TestCreateWithSpecifiedTimeUTCThenValid() + { + // Arrange + DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc); + Player player = new("Bobby"); + Assert.Equal(DateTimeKind.Utc, dateTime.Kind); + + // Act + Turn turn = Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1); + + // Assert + Assert.Equal(DateTimeKind.Utc, turn.When.Kind); + Assert.Equal(dateTime.ToUniversalTime(), turn.When); + } + + + [Fact] + public void TestCreateWithSpecifiedTimeNullPlayerThenException() + { + // Arrange + DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc); + + // Act + void action() => Turn.CreateWithSpecifiedTime(dateTime, null, DICE_N_FACES_1); + + // Assert + Assert.Throws(action); + } + + [Fact] + public void TestCreateWithSpecifiedTimeNullFacesThenException() + { + // Arrange + DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc); + Player player = new("Chucky"); + + // Act + void action() => Turn.CreateWithSpecifiedTime(dateTime, player, null); + + // Assert + Assert.Throws(action); + } + + + [Fact] + public void TestCreateWithSpecifiedTimeEmptyFacesThenException() + { + // Arrange + DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc); + Player player = new("Chucky"); + DICE_N_FACES_1.Clear(); + + // Act + void action() => Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1); + + // Assert + Assert.Throws(action); + } + + + + [Fact] + public void TestCreateWithDefaultTimeThenValid() + { + // Arrange + Player player = new("Chloe"); + + // Act + Turn turn = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1); + + // Assert + Assert.Equal(DateTimeKind.Utc, turn.When.Kind); + Assert.Equal(DateTime.Now.ToUniversalTime().Date, turn.When.Date); + // N.B.: might fail between 11:59:59PM and 00:00:00AM + } + + + + [Fact] + public void TestToStringValidIfAllNormal() + { + // Arrange + DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc); + string name = "Bobby"; + Player player = new(name); + string expected = $"2018-06-15 16:30:00 -- {name} rolled: " + + FACE_ONE.ToString() + " " + + FACE_TWO.ToString() + " " + + FACE_THREE.ToString() + " " + + FACE_FOUR.ToString(); + + Turn turn = Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1); + + // Act + string actual = turn.ToString(); + Debug.WriteLine(actual); + + // Assert + Assert.Equal(expected, actual); + } + + [Fact] + public void TestDiceNFacesProperty() + { + // Arrange + Player player = new("Erika"); + + // Act + Turn turn = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1); + IEnumerable, AbstractDieFace>> expected = DICE_N_FACES_1.AsEnumerable(); + + // Assert + Assert.Equal(expected, turn.DiceNFaces); + } + + [Fact] + public void TestEqualsFalseIfNotTurn() + { + // Arrange + Point point; + Turn turn; + Player player = new("Freddie"); + + // Act + point = new(1, 2); + turn = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1); + + // Assert + Assert.False(point.Equals(turn)); + Assert.False(point.GetHashCode().Equals(turn.GetHashCode())); + Assert.False(turn.Equals(point)); + Assert.False(turn.GetHashCode().Equals(point.GetHashCode())); + } + + [Fact] + public void TestGoesThruToSecondMethodIfObjIsTypeTurn() + { + // Arrange + object t1; + Turn t2; + Player player1 = new Player("Marvin"); + Player player2 = new Player("Noah"); + + // Act + t1 = Turn.CreateWithDefaultTime(player1, DICE_N_FACES_1); + t2 = Turn.CreateWithDefaultTime(player2, DICE_N_FACES_2); + + // Assert + Assert.False(t1.Equals(t2)); + Assert.False(t1.GetHashCode().Equals(t2.GetHashCode())); + Assert.False(t2.Equals(t1)); + Assert.False(t2.GetHashCode().Equals(t1.GetHashCode())); + } + + + [Fact] + public void TestEqualsFalseIfNotSamePlayer() + { + // Arrange + Player player1 = new("Panama"); + Player player2 = new("Clyde"); + + // Act + Turn t1 = Turn.CreateWithDefaultTime(player1, DICE_N_FACES_2); + Turn t2 = Turn.CreateWithDefaultTime(player2, DICE_N_FACES_2); + + // Assert + Assert.False(t1.Equals(t2)); + Assert.False(t1.GetHashCode().Equals(t2.GetHashCode())); + Assert.False(t2.Equals(t1)); + Assert.False(t2.GetHashCode().Equals(t1.GetHashCode())); + } + + [Fact] + public void TestEqualsFalseIfNotSameTime() + { + // Arrange + Player player = new("Oscar"); + + // Act + Turn t1 = Turn.CreateWithSpecifiedTime(new DateTime(1994, 07, 10), player, DICE_N_FACES_1); + Turn t2 = Turn.CreateWithSpecifiedTime(new DateTime(1991, 08, 20), player, DICE_N_FACES_1); + + // Assert + Assert.False(t1.Equals(t2)); + Assert.False(t1.GetHashCode().Equals(t2.GetHashCode())); + Assert.False(t2.Equals(t1)); + Assert.False(t2.GetHashCode().Equals(t1.GetHashCode())); + } + + [Fact] + public void TestEqualsFalseIfNotSameDiceNFaces() + { + // Arrange + Player player = new("Django"); + + // Act + Turn t1 = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1); + Turn t2 = Turn.CreateWithDefaultTime(player, DICE_N_FACES_2); + + // Assert + Assert.False(t1.Equals(t2)); + Assert.False(t1.GetHashCode().Equals(t2.GetHashCode())); + Assert.False(t2.Equals(t1)); + Assert.False(t2.GetHashCode().Equals(t1.GetHashCode())); + } + + [Fact] + public void TestEqualsTrueIfExactlySameProperties() + { + // Arrange + Player player = new("Elyse"); + + // Act + Turn t1 = Turn.CreateWithSpecifiedTime(new DateTime(1990, 04, 29), player, DICE_N_FACES_1); + Turn t2 = Turn.CreateWithSpecifiedTime(new DateTime(1990, 04, 29), player, DICE_N_FACES_1); + + // Assert + Assert.True(t1.Equals(t2)); + Assert.True(t1.GetHashCode().Equals(t2.GetHashCode())); + Assert.True(t2.Equals(t1)); + Assert.True(t2.GetHashCode().Equals(t1.GetHashCode())); + } + } +} diff --git a/Sources/Tests/Model_UTs/PlayerManagerTest.cs b/Sources/Tests/Model_UTs/Players/PlayerManagerTest.cs similarity index 99% rename from Sources/Tests/Model_UTs/PlayerManagerTest.cs rename to Sources/Tests/Model_UTs/Players/PlayerManagerTest.cs index 5d8e1b1..2cdb994 100644 --- a/Sources/Tests/Model_UTs/PlayerManagerTest.cs +++ b/Sources/Tests/Model_UTs/Players/PlayerManagerTest.cs @@ -5,7 +5,7 @@ using System.Collections.ObjectModel; using System.Linq; using Xunit; -namespace Tests.Model_UTs +namespace Tests.Model_UTs.Players { public class PlayerManagerTest { diff --git a/Sources/Tests/Model_UTs/PlayerTest.cs b/Sources/Tests/Model_UTs/Players/PlayerTest.cs similarity index 99% rename from Sources/Tests/Model_UTs/PlayerTest.cs rename to Sources/Tests/Model_UTs/Players/PlayerTest.cs index d800d5d..ca244d0 100644 --- a/Sources/Tests/Model_UTs/PlayerTest.cs +++ b/Sources/Tests/Model_UTs/Players/PlayerTest.cs @@ -2,7 +2,7 @@ using Model.Players; using System; using Xunit; -namespace Tests.Model_UTs +namespace Tests.Model_UTs.Players { public class PlayerTest { @@ -99,7 +99,7 @@ namespace Tests.Model_UTs public void TestGoesThruToSecondMethodIfObjIsTypePlayer() { // Arrange - Object p1; + object p1; Player p2; // Act