diff --git a/Sources/App/Program.cs b/Sources/App/Program.cs index d0bc48b..bd66be8 100644 --- a/Sources/App/Program.cs +++ b/Sources/App/Program.cs @@ -40,7 +40,9 @@ namespace App // Later, we'll use the DiceAppDbContext to get a GameDbRunner // get all the players from the DB - IEnumerable entities = db.Players; + PlayerDbManager playerDbManager = new(db); + IEnumerable entities = await playerDbManager.GetAll(); + Debug.WriteLine("Loading players"); diff --git a/Sources/Data/Data.csproj b/Sources/Data/Data.csproj index 1aa3210..a96003f 100644 --- a/Sources/Data/Data.csproj +++ b/Sources/Data/Data.csproj @@ -17,6 +17,7 @@ + diff --git a/Sources/Data/EF/Dice/ColorDieEntity.cs b/Sources/Data/EF/Dice/ColorDieEntity.cs index 877914a..450cb68 100644 --- a/Sources/Data/EF/Dice/ColorDieEntity.cs +++ b/Sources/Data/EF/Dice/ColorDieEntity.cs @@ -1,16 +1,9 @@ using Data.EF.Dice.Faces; -using Model.Dice.Faces; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Data.EF.Dice { - public class ColorDieEntity + public class ColorDieEntity : DieEntity { - public Guid Id { get; set; } - public ICollection Faces { get; set; } + public new ICollection Faces { get; set; } = new List(); } } diff --git a/Sources/Data/EF/Dice/ColorDieExtensions.cs b/Sources/Data/EF/Dice/ColorDieExtensions.cs index e3860d6..03e4dd1 100644 --- a/Sources/Data/EF/Dice/ColorDieExtensions.cs +++ b/Sources/Data/EF/Dice/ColorDieExtensions.cs @@ -6,27 +6,22 @@ namespace Data.EF.Dice { public static class ColorDieExtensions { - public static ColorDie ToModel(this ColorDieEntity clrDieEntity) + public static ColorDie ToModel(this ColorDieEntity dieEntity) { /* * creating an array of faces model */ - ColorFace[] faces = new ColorFace[clrDieEntity.Faces.Count - 1]; - List clrFacesList = clrDieEntity.Faces.ToModels().ToList(); - clrFacesList.CopyTo(faces, 1); + ColorFace[] faces = dieEntity.Faces.ToModels().ToArray(); /* * creating the die */ - ColorDie die = new(clrDieEntity.Faces.ElementAt(0).ToModel(), faces); + ColorDie die = new(faces[0], faces[1..]); return die; } - public static IEnumerable ToModels(this IEnumerable entities) - { - return entities.Select(entity => entity.ToModel()); - } + public static IEnumerable ToModels(this IEnumerable entities) => entities.Select(entity => entity.ToModel()); public static ColorDieEntity ToEntity(this ColorDie model) { @@ -35,10 +30,6 @@ namespace Data.EF.Dice return entity; } - public static IEnumerable ToEntities(this IEnumerable models) - { - return models.Select(model => model.ToEntity()); - } - + public static IEnumerable ToEntities(this IEnumerable models) => models.Select(model => model.ToEntity()); } } diff --git a/Sources/Data/EF/Dice/DieEntity.cs b/Sources/Data/EF/Dice/DieEntity.cs new file mode 100644 index 0000000..19d0976 --- /dev/null +++ b/Sources/Data/EF/Dice/DieEntity.cs @@ -0,0 +1,32 @@ +using Data.EF.Dice.Faces; +using Data.EF.Games; +using Data.EF.Joins; +using System.Diagnostics.CodeAnalysis; + +namespace Data.EF.Dice +{ + /// + /// not designed to be instantiated, but not abstract in order to allow extensions + /// + /// + public class DieEntity : IEqualityComparer + { + public Guid ID { get; set; } + public ICollection Faces { get; set; } = new List(); // one to many + public ICollection Turns { get; set; } = new List(); // many to many + public List DieTurns { get; set; } = new(); + + public bool Equals(DieEntity x, DieEntity y) + { + return x is not null + && y is not null + && x.ID.Equals(y.ID) + && x.Faces.Equals(y.Faces); + } + + public int GetHashCode([DisallowNull] DieEntity obj) + { + return HashCode.Combine(ID, Faces); + } + } +} diff --git a/Sources/Data/EF/Dice/Faces/ColorFaceEntity.cs b/Sources/Data/EF/Dice/Faces/ColorFaceEntity.cs index 550ae64..d28e6d0 100644 --- a/Sources/Data/EF/Dice/Faces/ColorFaceEntity.cs +++ b/Sources/Data/EF/Dice/Faces/ColorFaceEntity.cs @@ -1,20 +1,15 @@ -using Model.Dice; -using System; -using System.ComponentModel.DataAnnotations.Schema; -using System.Drawing; +using System.Drawing; namespace Data.EF.Dice.Faces { - public class ColorFaceEntity + public class ColorFaceEntity : FaceEntity { - public Guid ID { get; set; } - public byte A { get; set; } public byte R { get; set; } public byte G { get; set; } public byte B { get; set; } - [ForeignKey("ColorDieFK")] + public Guid ColorDieEntityID { get; set; } public ColorDieEntity ColorDieEntity { get; set; } public void SetValue(Color c) diff --git a/Sources/Data/EF/Dice/Faces/ColorFaceExtensions.cs b/Sources/Data/EF/Dice/Faces/ColorFaceExtensions.cs index 7b789f4..2a36150 100644 --- a/Sources/Data/EF/Dice/Faces/ColorFaceExtensions.cs +++ b/Sources/Data/EF/Dice/Faces/ColorFaceExtensions.cs @@ -10,27 +10,12 @@ namespace Data.EF.Dice.Faces { public static class ColorFaceExtensions { - public static ColorFace ToModel(this ColorFaceEntity clrFaceEntity) - { - ColorFace colorFace = new(Color.FromArgb(clrFaceEntity.A, clrFaceEntity.R, clrFaceEntity.G, clrFaceEntity.B)); - return colorFace; - } + public static ColorFace ToModel(this ColorFaceEntity clrFaceEntity) => new(Color.FromArgb(clrFaceEntity.A, clrFaceEntity.R, clrFaceEntity.G, clrFaceEntity.B)); - public static IEnumerable ToModels(this IEnumerable entities) - { - return entities.Select(entity => entity.ToModel()); - } + public static IEnumerable ToModels(this IEnumerable entities) => entities.Select(entity => entity.ToModel()); - public static ColorFaceEntity ToEntity(this ColorFace model) - { - return new ColorFaceEntity() { A = model.Value.A, R = model.Value.R, G = model.Value.G, B = model.Value.B }; - } + public static ColorFaceEntity ToEntity(this ColorFace model) => new() { A = model.Value.A, R = model.Value.R, G = model.Value.G, B = model.Value.B }; - public static IEnumerable ToEntities(this IEnumerable models) - { - return models.Select(model => model.ToEntity()); - } - - + public static IEnumerable ToEntities(this IEnumerable models) => models.Select(model => model.ToEntity()); } } diff --git a/Sources/Data/EF/Dice/Faces/FaceEntity.cs b/Sources/Data/EF/Dice/Faces/FaceEntity.cs new file mode 100644 index 0000000..bdb7899 --- /dev/null +++ b/Sources/Data/EF/Dice/Faces/FaceEntity.cs @@ -0,0 +1,28 @@ +using Data.EF.Games; +using Data.EF.Joins; +using System.Diagnostics.CodeAnalysis; + +namespace Data.EF.Dice.Faces +{ + /// + /// not designed to be instantiated, but not abstract in order to allow extensions + /// + public class FaceEntity : IEqualityComparer + { + public Guid ID { get; set; } + public ICollection Turns { get; set; } // many to many + public List FaceTurns { get; set; } + + public bool Equals(FaceEntity x, FaceEntity y) + { + return x is not null + && y is not null + && x.ID.Equals(y.ID); + } + + public int GetHashCode([DisallowNull] FaceEntity obj) + { + return ID.GetHashCode(); + } + } +} diff --git a/Sources/Data/EF/Dice/Faces/ImageFaceEntity.cs b/Sources/Data/EF/Dice/Faces/ImageFaceEntity.cs index 3d29656..7227868 100644 --- a/Sources/Data/EF/Dice/Faces/ImageFaceEntity.cs +++ b/Sources/Data/EF/Dice/Faces/ImageFaceEntity.cs @@ -1,19 +1,9 @@ -using Model.Dice; -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Data.EF.Dice.Faces +namespace Data.EF.Dice.Faces { - public class ImageFaceEntity + public class ImageFaceEntity : FaceEntity { - public Guid ID { get; set; } public string Value { get; set; } - - [ForeignKey("ImgDieFK")] + public Guid ImageDieEntityID { get; set; } public ImageDieEntity ImageDieEntity { get; set; } } } diff --git a/Sources/Data/EF/Dice/Faces/ImageFaceExtensions.cs b/Sources/Data/EF/Dice/Faces/ImageFaceExtensions.cs index 4eb9d53..19597fc 100644 --- a/Sources/Data/EF/Dice/Faces/ImageFaceExtensions.cs +++ b/Sources/Data/EF/Dice/Faces/ImageFaceExtensions.cs @@ -11,24 +11,12 @@ namespace Data.EF.Dice.Faces { public static class ImageFaceExtensions { - public static ImageFace ToModel(this ImageFaceEntity entity) - { - return new ImageFace(new Uri(entity.Value)); - } + public static ImageFace ToModel(this ImageFaceEntity entity) => new(new Uri(entity.Value)); - public static IEnumerable ToModels(this IEnumerable entities) - { - return entities.Select(entity => entity.ToModel()); - } + public static IEnumerable ToModels(this IEnumerable entities) => entities.Select(entity => entity.ToModel()); - public static ImageFaceEntity ToEntity(this ImageFace model) - { - return new ImageFaceEntity() { Value = model.StringValue }; - } + public static ImageFaceEntity ToEntity(this ImageFace model) => new() { Value = model.StringValue }; - public static IEnumerable ToEntities(this IEnumerable models) - { - return models.Select(model => model.ToEntity()); - } + public static IEnumerable ToEntities(this IEnumerable models) => models.Select(model => model.ToEntity()); } } diff --git a/Sources/Data/EF/Dice/Faces/NumberFaceEntity.cs b/Sources/Data/EF/Dice/Faces/NumberFaceEntity.cs index 2895633..862f333 100644 --- a/Sources/Data/EF/Dice/Faces/NumberFaceEntity.cs +++ b/Sources/Data/EF/Dice/Faces/NumberFaceEntity.cs @@ -1,19 +1,9 @@ -using Model.Dice; -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Data.EF.Dice.Faces +namespace Data.EF.Dice.Faces { - public class NumberFaceEntity + public class NumberFaceEntity : FaceEntity { - public Guid Id { get; set; } public int Value { get; set; } - - [ForeignKey("NumDieFK")] + public Guid NumberDieEntityID { get; set; } public NumberDieEntity NumberDieEntity { get; set; } } } diff --git a/Sources/Data/EF/Dice/Faces/NumberFaceExtensions.cs b/Sources/Data/EF/Dice/Faces/NumberFaceExtensions.cs index f6c3d9e..448b03f 100644 --- a/Sources/Data/EF/Dice/Faces/NumberFaceExtensions.cs +++ b/Sources/Data/EF/Dice/Faces/NumberFaceExtensions.cs @@ -9,24 +9,12 @@ namespace Data.EF.Dice.Faces { public static class NumberFaceExtensions { - public static NumberFace ToModel(this NumberFaceEntity entity) - { - return new NumberFace(entity.Value); - } + public static NumberFace ToModel(this NumberFaceEntity entity) => new(entity.Value); - public static IEnumerable ToModels(this IEnumerable entities) - { - return entities.Select(entity => entity.ToModel()); - } + public static IEnumerable ToModels(this IEnumerable entities) => entities.Select(entity => entity.ToModel()); - public static NumberFaceEntity ToEntity(this NumberFace model) - { - return new NumberFaceEntity() { Value = model.Value }; - } + public static NumberFaceEntity ToEntity(this NumberFace model) => new() { Value = model.Value }; - public static IEnumerable ToEntities(this IEnumerable models) - { - return models.Select(model => model.ToEntity()); - } + public static IEnumerable ToEntities(this IEnumerable models) => models.Select(model => model.ToEntity()); } } diff --git a/Sources/Data/EF/Dice/ImageDieEntity.cs b/Sources/Data/EF/Dice/ImageDieEntity.cs index 2b379ef..67516d0 100644 --- a/Sources/Data/EF/Dice/ImageDieEntity.cs +++ b/Sources/Data/EF/Dice/ImageDieEntity.cs @@ -1,16 +1,9 @@ using Data.EF.Dice.Faces; -using Model.Dice.Faces; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Data.EF.Dice { - public class ImageDieEntity + public class ImageDieEntity : DieEntity { - public Guid Id { get; set; } - public ICollection Faces { get; set; } + public new ICollection Faces { get; set; } = new List(); } } diff --git a/Sources/Data/EF/Dice/ImageDieExtensions.cs b/Sources/Data/EF/Dice/ImageDieExtensions.cs index 772470e..be7be00 100644 --- a/Sources/Data/EF/Dice/ImageDieExtensions.cs +++ b/Sources/Data/EF/Dice/ImageDieExtensions.cs @@ -1,33 +1,27 @@ using Data.EF.Dice.Faces; -using Model.Dice.Faces; using Model.Dice; +using Model.Dice.Faces; namespace Data.EF.Dice { public static class ImageDieExtensions { - public static ImageDie ToModel(this ImageDieEntity clrDieEntity) + public static ImageDie ToModel(this ImageDieEntity dieEntity) { /* * creating an array of faces model */ - ImageFace[] faces = new ImageFace[clrDieEntity.Faces.Count - 1]; - List clrFacesList = clrDieEntity.Faces.ToModels().ToList(); - clrFacesList.CopyTo(faces, 1); - + ImageFace[] faces = dieEntity.Faces.ToModels().ToArray(); /* * creating the die */ - ImageDie die = new(clrDieEntity.Faces.ElementAt(0).ToModel(), faces); + ImageDie die = new(faces[0], faces[1..]); return die; } - public static IEnumerable ToModels(this IEnumerable entities) - { - return entities.Select(entity => entity.ToModel()); - } + public static IEnumerable ToModels(this IEnumerable entities) => entities.Select(entity => entity.ToModel()); public static ImageDieEntity ToEntity(this ImageDie model) { @@ -36,9 +30,6 @@ namespace Data.EF.Dice return entity; } - public static IEnumerable ToEntities(this IEnumerable models) - { - return models.Select(model => model.ToEntity()); - } + public static IEnumerable ToEntities(this IEnumerable models) => models.Select(model => model.ToEntity()); } } diff --git a/Sources/Data/EF/Dice/NumberDieEntity.cs b/Sources/Data/EF/Dice/NumberDieEntity.cs index 27b1d21..77afa69 100644 --- a/Sources/Data/EF/Dice/NumberDieEntity.cs +++ b/Sources/Data/EF/Dice/NumberDieEntity.cs @@ -1,16 +1,9 @@ using Data.EF.Dice.Faces; -using Model.Dice.Faces; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Data.EF.Dice { - public class NumberDieEntity + public class NumberDieEntity : DieEntity { - public Guid Id { get; set; } - public ICollection Faces { get; set; } + public new ICollection Faces { get; set; } = new List(); } } diff --git a/Sources/Data/EF/Dice/NumberDieExtensions.cs b/Sources/Data/EF/Dice/NumberDieExtensions.cs index a2fa363..7e2e4ac 100644 --- a/Sources/Data/EF/Dice/NumberDieExtensions.cs +++ b/Sources/Data/EF/Dice/NumberDieExtensions.cs @@ -1,37 +1,27 @@ using Data.EF.Dice.Faces; -using Model.Dice.Faces; using Model.Dice; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using Model.Dice.Faces; namespace Data.EF.Dice { public static class NumberDieExtensions { - public static NumberDie ToModel(this NumberDieEntity clrDieEntity) + public static NumberDie ToModel(this NumberDieEntity dieEntity) { /* * creating an array of faces model */ - NumberFace[] faces = new NumberFace[clrDieEntity.Faces.Count - 1]; - List clrFacesList = clrDieEntity.Faces.ToModels().ToList(); - clrFacesList.CopyTo(faces, 1); + NumberFace[] faces = dieEntity.Faces.ToModels().ToArray(); /* * creating the die */ - NumberDie die = new(clrDieEntity.Faces.ElementAt(0).ToModel(), faces); + NumberDie die = new(faces[0], faces[1..]); return die; } - public static IEnumerable ToModels(this IEnumerable entities) - { - return entities.Select(entity => ToModel(entity)); - } + public static IEnumerable ToModels(this IEnumerable entities) => entities.Select(entity => ToModel(entity)); public static NumberDieEntity ToEntity(this NumberDie model) { @@ -40,9 +30,6 @@ namespace Data.EF.Dice return entity; } - public static IEnumerable ToEntities(this IEnumerable models) - { - return models.Select(model => model.ToEntity()); - } + public static IEnumerable ToEntities(this IEnumerable models) => models.Select(model => model.ToEntity()); } } diff --git a/Sources/Data/EF/DiceAppDbContext.cs b/Sources/Data/EF/DiceAppDbContext.cs index ffddbe5..61f48c2 100644 --- a/Sources/Data/EF/DiceAppDbContext.cs +++ b/Sources/Data/EF/DiceAppDbContext.cs @@ -1,5 +1,7 @@ using Data.EF.Dice; using Data.EF.Dice.Faces; +using Data.EF.Games; +using Data.EF.Joins; using Data.EF.Players; using Microsoft.EntityFrameworkCore; using Model.Games; @@ -11,13 +13,14 @@ namespace Data.EF // will be async! public virtual Task LoadApp() { throw new NotImplementedException(); } - public DbSet Players { get; set; } - public DbSet NumberDice { get; set; } - public DbSet NumberFaces { get; set; } - public DbSet ImageDice { get; set; } - public DbSet ImageFaces { get; set; } - public DbSet ColorDice { get; set; } - public DbSet ColorFaces { get; set; } + public DbSet PlayerEntity { get; set; } + public DbSet TurnEntity { get; set; } + public DbSet NumberDieEntity { get; set; } + public DbSet NumberFaceEntity { get; set; } + public DbSet ImageDieEntity { get; set; } + public DbSet ImageFaceEntity { get; set; } + public DbSet ColorDieEntity { get; set; } + public DbSet ColorFaceEntity { get; set; } public DiceAppDbContext() { } @@ -28,5 +31,52 @@ namespace Data.EF { if (!optionsBuilder.IsConfigured) optionsBuilder.UseSqlite("Data Source=EFDice.DiceApp.db").EnableSensitiveDataLogging(); } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + // thanks to https://learn.microsoft.com/en-us/ef/core/modeling/relationships?tabs=fluent-api%2Cfluent-api-simple-key%2Csimple-key#join-entity-type-configuration + + // many to many TurnEntity <-> FaceEntity + modelBuilder.Entity() + .HasMany(face => face.Turns) + .WithMany(turn => turn.Faces) + .UsingEntity( + + join => join + // FaceTurn --> TurnEntity + .HasOne(faceturn => faceturn.TurnEntity) + .WithMany(turn => turn.FaceTurns) + .HasForeignKey(faceturn => faceturn.TurnEntityID), + join => join + // FaceTurn --> FaceEntity + .HasOne(faceturn => faceturn.FaceEntity) + .WithMany(face => face.FaceTurns) + .HasForeignKey(faceturn => faceturn.FaceEntityID), + // FaceTurn.PK = (ID1, ID2) + join => join.HasKey(faceturn => new { faceturn.FaceEntityID, faceturn.TurnEntityID }) + + ); + + // many to many TurnEntity <-> DieEntity + modelBuilder.Entity() + .HasMany(die => die.Turns) + .WithMany(turn => turn.Dice) + .UsingEntity( + + join => join + // DieTurn --> TurnEntity + .HasOne(dieturn => dieturn.TurnEntity) + .WithMany(turn => turn.DieTurns) + .HasForeignKey(dieturn => dieturn.TurnEntityID), + join => join + // DieTurn --> DieEntity + .HasOne(dieturn => dieturn.DieEntity) + .WithMany(die => die.DieTurns) + .HasForeignKey(dieturn => dieturn.DieEntityID), + // DieTurn.PK = (ID1, ID2) + join => join.HasKey(dieturn => new { dieturn.DieEntityID, dieturn.TurnEntityID }) + + ); + } } } diff --git a/Sources/Data/EF/DiceAppDbContextWithStub.cs b/Sources/Data/EF/DiceAppDbContextWithStub.cs index 4ba9983..852d7fb 100644 --- a/Sources/Data/EF/DiceAppDbContextWithStub.cs +++ b/Sources/Data/EF/DiceAppDbContextWithStub.cs @@ -1,4 +1,8 @@ -using Data.EF.Players; +using Data.EF.Dice; +using Data.EF.Dice.Faces; +using Data.EF.Games; +using Data.EF.Joins; +using Data.EF.Players; using Microsoft.EntityFrameworkCore; using Model.Games; using System.Linq.Expressions; @@ -20,12 +24,182 @@ namespace Data.EF { base.OnModelCreating(modelBuilder); - modelBuilder.Entity().HasData( - new PlayerEntity { ID = Guid.NewGuid(), Name = "Alice" }, // some tests depend on this name - new PlayerEntity { ID = new("6e856818-92f1-4d7d-b35c-f9c6687ef8e1"), Name = "Bob" }, // some tests depend on this name and this ID - new PlayerEntity { ID = Guid.NewGuid(), Name = "Clyde" }, // some tests depend on this name - new PlayerEntity { ID = Guid.NewGuid(), Name = "Dahlia" } // some tests depend on this name - ); + Guid playerID_1 = Guid.NewGuid(); + Guid playerID_2 = new("6e856818-92f1-4d7d-b35c-f9c6687ef8e1"); + Guid playerID_3 = Guid.NewGuid(); + Guid playerID_4 = Guid.NewGuid(); + + PlayerEntity player_1 = new() { ID = playerID_1, Name = "Alice" }; + PlayerEntity player_2 = new() { ID = playerID_2, Name = "Bob" }; + PlayerEntity player_3 = new() { ID = playerID_3, Name = "Clyde" }; + PlayerEntity player_4 = new() { ID = playerID_4, Name = "Dahlia" }; + + Guid turnID_1 = Guid.NewGuid(); + Guid turnID_2 = Guid.NewGuid(); + + TurnEntity turn_1 = new() + { + ID = turnID_1, + When = new DateTime(2017, 1, 6, 17, 30, 0, DateTimeKind.Utc), + PlayerEntityID = playerID_1 + }; + + TurnEntity turn_2 = new() + { + ID = turnID_2, + When = DateTime.UtcNow, + PlayerEntityID = playerID_2 + }; + + Guid dieID_1 = Guid.NewGuid(); + Guid dieID_2 = Guid.NewGuid(); + Guid dieID_3 = Guid.NewGuid(); + + NumberDieEntity die_1 = new() { ID = dieID_1 }; + ImageDieEntity die_2 = new() { ID = dieID_2 }; + ColorDieEntity die_3 = new() { ID = dieID_3 }; + + Guid faceID_1 = Guid.NewGuid(); + Guid faceID_2 = Guid.NewGuid(); + Guid faceID_3 = Guid.NewGuid(); + Guid faceID_4 = Guid.NewGuid(); + Guid faceID_5 = Guid.NewGuid(); + Guid faceID_6 = Guid.NewGuid(); + + NumberFaceEntity face_1 = new() + { + ID = faceID_1, + Value = 1, + NumberDieEntityID = dieID_1 + }; + NumberFaceEntity face_2 = new() + { + ID = faceID_2, + Value = 2, + NumberDieEntityID = dieID_1 + }; + + ImageFaceEntity face_3 = new() + { + ID = faceID_3, + Value = "https://1", + ImageDieEntityID = dieID_2 + }; + ImageFaceEntity face_4 = new() + { + ID = faceID_4, + Value = "https://2", + ImageDieEntityID = dieID_2 + }; + + ColorFaceEntity face_5 = new() + { + ID = faceID_5, + A = 255, + R = 255, + G = 0, + B = 0, + ColorDieEntityID = dieID_3 + }; + ColorFaceEntity face_6 = new() + { + ID = faceID_6, + A = 255, + R = 0, + G = 255, + B = 0, + ColorDieEntityID = dieID_3 + }; + + modelBuilder.Entity().HasData(player_1, player_2, player_3, player_4); + + modelBuilder.Entity().HasData(turn_1, turn_2); + + modelBuilder.Entity().HasData(die_1); + + modelBuilder.Entity().HasData(face_1, face_2); + + modelBuilder.Entity().HasData(die_2); + + modelBuilder.Entity().HasData(face_3, face_4); + + modelBuilder.Entity().HasData(die_3); + + modelBuilder.Entity().HasData(face_5, face_6); + + // die 1 die 2 die 3 + // turn 1 : num->2, img->https://2, clr->red + // turn 2 : num->1, clr->green + + modelBuilder + .Entity() + .HasMany(turn => turn.Faces) + .WithMany(face => face.Turns) + .UsingEntity( + join => join.HasData( + new + { + TurnEntityID = turnID_1, + FaceEntityID = faceID_2 + }, + new + { + TurnEntityID = turnID_1, + FaceEntityID = faceID_4 + }, + new + { + TurnEntityID = turnID_1, + FaceEntityID = faceID_5 + }, + + new + { + TurnEntityID = turnID_2, + FaceEntityID = faceID_1 + }, + new + { + TurnEntityID = turnID_2, + FaceEntityID = faceID_6 + } + ) + ); + + modelBuilder + .Entity() + .HasMany(turn => turn.Dice) + .WithMany(die => die.Turns) + .UsingEntity( + join => join.HasData( + new + { + TurnEntityID = turnID_1, + DieEntityID = dieID_1 + }, + new + { + TurnEntityID = turnID_1, + DieEntityID = dieID_2 + }, + new + { + TurnEntityID = turnID_1, + DieEntityID = dieID_3 + }, + + new + { + TurnEntityID = turnID_2, + DieEntityID = dieID_1 + }, + new + { + TurnEntityID = turnID_2, + DieEntityID = dieID_3 + } + ) + ); } } } diff --git a/Sources/Data/EF/Games/TurnEntity.cs b/Sources/Data/EF/Games/TurnEntity.cs index d2e0ba7..21ff016 100644 --- a/Sources/Data/EF/Games/TurnEntity.cs +++ b/Sources/Data/EF/Games/TurnEntity.cs @@ -1,12 +1,58 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using Data.EF.Dice; +using Data.EF.Dice.Faces; +using Data.EF.Joins; +using Data.EF.Players; namespace Data.EF.Games { - public class TurnEntity + public sealed class TurnEntity: IEquatable { + public Guid ID { get; set; } + public DateTime When { get; set; } + public PlayerEntity PlayerEntity { get; set; } + public Guid PlayerEntityID { get; set; } + public ICollection Dice { get; set; } = new List(); // many to many + public List DieTurns { get; set; } = new(); + public ICollection Faces { get; set; } = new List(); // many to many + public List FaceTurns { get; set; } = new(); + + public override bool Equals(object obj) + { + if (obj is not TurnEntity) + { + return false; + } + return Equals(obj as TurnEntity); + } + + public bool Equals(TurnEntity other) + { + return other is not null + && this.ID.Equals(other.ID) + && this.When.Equals(other.When) + && this.PlayerEntity.Equals(other.PlayerEntity) + && this.Dice.SequenceEqual(other.Dice) + && this.Faces.SequenceEqual(other.Faces); + } + + public override int GetHashCode() + { + int result = HashCode.Combine( + ID, + When, + PlayerEntity); + + foreach (DieEntity die in Dice) + { + result += die.GetHashCode(); + } + + foreach (FaceEntity face in Faces) + { + result += face.GetHashCode(); + } + + return result; + } } -} +} \ No newline at end of file diff --git a/Sources/Data/EF/Games/TurnExtensions.cs b/Sources/Data/EF/Games/TurnExtensions.cs index f6cd483..469fd64 100644 --- a/Sources/Data/EF/Games/TurnExtensions.cs +++ b/Sources/Data/EF/Games/TurnExtensions.cs @@ -1,12 +1,68 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using Data.EF.Dice; +using Data.EF.Dice.Faces; +using Data.EF.Players; +using Model.Dice; +using Model.Dice.Faces; +using Model.Games; namespace Data.EF.Games { public static class TurnExtensions { + + private static (List, List) ToModels(ICollection diceEntities, ICollection faceEntities) + { + List dice = new(); + List faces = new(); + + foreach (DieEntity dieEntity in diceEntities) + { + if (dieEntity.GetType() == typeof(NumberDieEntity)) { dice.Add((dieEntity as NumberDieEntity).ToModel()); } + if (dieEntity.GetType() == typeof(ColorDieEntity)) { dice.Add((dieEntity as ColorDieEntity).ToModel()); } + if (dieEntity.GetType() == typeof(ImageDieEntity)) { dice.Add((dieEntity as ImageDieEntity).ToModel()); } + } + foreach (FaceEntity faceEntity in faceEntities) + { + if (faceEntity.GetType() == typeof(NumberFaceEntity)) { faces.Add((faceEntity as NumberFaceEntity).ToModel()); } + if (faceEntity.GetType() == typeof(ColorFaceEntity)) { faces.Add((faceEntity as ColorFaceEntity).ToModel()); } + if (faceEntity.GetType() == typeof(ImageFaceEntity)) { faces.Add((faceEntity as ImageFaceEntity).ToModel()); } + } + + return (dice, faces); + } + + public static Turn ToModel(this TurnEntity entity) + { + Dictionary DiceNFaces = new(); + + List keysList; + List valuesList; + + (keysList, valuesList) = ToModels(entity.Dice, entity.Faces); + + DiceNFaces = Utils.Enumerables.FeedListsToDict(DiceNFaces, keysList, valuesList); + + return Turn.CreateWithSpecifiedTime(when: entity.When, player: entity.PlayerEntity.ToModel(), diceNFaces: DiceNFaces); + } + + public static IEnumerable ToModels(this IEnumerable entities) => entities.Select(entity => entity.ToModel()); + + public static TurnEntity ToEntity(this Turn model) + { + + List DiceEntities = new(); + List FaceEntities = new(); + + foreach (KeyValuePair kvp in model.DiceNFaces) + { + if (kvp.Key.GetType() == typeof(NumberDie)) { DiceEntities.Add((kvp.Key as NumberDie).ToEntity()); FaceEntities.Add((kvp.Value as NumberFace).ToEntity()); } + if (kvp.Key.GetType() == typeof(ImageDie)) { DiceEntities.Add((kvp.Key as ImageDie).ToEntity()); FaceEntities.Add((kvp.Value as ImageFace).ToEntity()); } + if (kvp.Key.GetType() == typeof(ColorDie)) { DiceEntities.Add((kvp.Key as ColorDie).ToEntity()); FaceEntities.Add((kvp.Value as ColorFace).ToEntity()); } + } + + return new TurnEntity() { When = model.When, PlayerEntity = model.Player.ToEntity(), Dice = DiceEntities, Faces = FaceEntities }; + } + + public static IEnumerable ToEntities(this IEnumerable models) => models.Select(model => model.ToEntity()); } -} +} \ No newline at end of file diff --git a/Sources/Data/EF/Joins/DieTurn.cs b/Sources/Data/EF/Joins/DieTurn.cs new file mode 100644 index 0000000..d811deb --- /dev/null +++ b/Sources/Data/EF/Joins/DieTurn.cs @@ -0,0 +1,15 @@ +using Data.EF.Dice; +using Data.EF.Dice.Faces; +using Data.EF.Games; + +namespace Data.EF.Joins +{ + public class DieTurn + { + public Guid DieEntityID { get; set; } + public DieEntity DieEntity { get; set; } + + public Guid TurnEntityID { get; set; } + public TurnEntity TurnEntity { get; set; } + } +} diff --git a/Sources/Data/EF/Joins/FaceTurn.cs b/Sources/Data/EF/Joins/FaceTurn.cs new file mode 100644 index 0000000..3c86203 --- /dev/null +++ b/Sources/Data/EF/Joins/FaceTurn.cs @@ -0,0 +1,19 @@ +using Data.EF.Dice.Faces; +using Data.EF.Games; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Data.EF.Joins +{ + public class FaceTurn + { + public Guid FaceEntityID { get; set; } + public FaceEntity FaceEntity { get; set; } + + public Guid TurnEntityID { get; set; } + public TurnEntity TurnEntity { get; set; } + } +} diff --git a/Sources/Data/EF/Players/PlayerDBManager.cs b/Sources/Data/EF/Players/PlayerDBManager.cs index 3eb17db..99b9ab8 100644 --- a/Sources/Data/EF/Players/PlayerDBManager.cs +++ b/Sources/Data/EF/Players/PlayerDBManager.cs @@ -47,7 +47,7 @@ namespace Data.EF.Players { CleanPlayerEntity(toAdd); - if (db.Players.Where(entity => entity.Name == toAdd.Name).Any()) + if (db.PlayerEntity.Where(entity => entity.Name == toAdd.Name).Any()) { throw new ArgumentException("this username is already taken", nameof(toAdd)); } @@ -57,7 +57,7 @@ namespace Data.EF.Players private async Task InternalAdd(PlayerEntity toAdd) { - EntityEntry ee = await db.Players.AddAsync(toAdd); + EntityEntry ee = await db.PlayerEntity.AddAsync(toAdd); await db.SaveChangesAsync(); return (PlayerEntity)ee.Entity; } @@ -65,7 +65,7 @@ namespace Data.EF.Players public async Task> GetAll() { List players = new(); - await Task.Run(() => players.AddRange(db.Players)); + await Task.Run(() => players.AddRange(db.PlayerEntity)); return players.AsEnumerable(); } @@ -90,7 +90,7 @@ namespace Data.EF.Players private async Task InternalGetOneByName(string name) { - return await db.Players.Where(p => p.Name == name).FirstAsync(); + return await db.PlayerEntity.Where(p => p.Name == name).FirstAsync(); } public async Task IsPresentByName(string name) @@ -100,7 +100,7 @@ namespace Data.EF.Players return false; } name = name.Trim(); - return await db.Players.Where(p => p.Name == name).FirstOrDefaultAsync() is not null; + return await db.PlayerEntity.Where(p => p.Name == name).FirstOrDefaultAsync() is not null; } /// @@ -115,7 +115,7 @@ namespace Data.EF.Players bool isPresent = IsPresentByID(toRemove.ID).Result; if (isPresent) { - db.Players.Remove(toRemove); + db.PlayerEntity.Remove(toRemove); db.SaveChanges(); } } @@ -161,12 +161,12 @@ namespace Data.EF.Players /// public async Task GetOneByID(Guid ID) { - return await db.Players.FirstAsync(p => p.ID == ID); + return await db.PlayerEntity.FirstAsync(p => p.ID == ID); } public async Task IsPresentByID(Guid ID) { - return await db.Players.FirstOrDefaultAsync(p => p.ID == ID) is not null; + return await db.PlayerEntity.FirstOrDefaultAsync(p => p.ID == ID) is not null; } } } diff --git a/Sources/Data/EF/Players/PlayerDbManager.cs b/Sources/Data/EF/Players/PlayerDbManager.cs index 3eb17db..99b9ab8 100644 --- a/Sources/Data/EF/Players/PlayerDbManager.cs +++ b/Sources/Data/EF/Players/PlayerDbManager.cs @@ -47,7 +47,7 @@ namespace Data.EF.Players { CleanPlayerEntity(toAdd); - if (db.Players.Where(entity => entity.Name == toAdd.Name).Any()) + if (db.PlayerEntity.Where(entity => entity.Name == toAdd.Name).Any()) { throw new ArgumentException("this username is already taken", nameof(toAdd)); } @@ -57,7 +57,7 @@ namespace Data.EF.Players private async Task InternalAdd(PlayerEntity toAdd) { - EntityEntry ee = await db.Players.AddAsync(toAdd); + EntityEntry ee = await db.PlayerEntity.AddAsync(toAdd); await db.SaveChangesAsync(); return (PlayerEntity)ee.Entity; } @@ -65,7 +65,7 @@ namespace Data.EF.Players public async Task> GetAll() { List players = new(); - await Task.Run(() => players.AddRange(db.Players)); + await Task.Run(() => players.AddRange(db.PlayerEntity)); return players.AsEnumerable(); } @@ -90,7 +90,7 @@ namespace Data.EF.Players private async Task InternalGetOneByName(string name) { - return await db.Players.Where(p => p.Name == name).FirstAsync(); + return await db.PlayerEntity.Where(p => p.Name == name).FirstAsync(); } public async Task IsPresentByName(string name) @@ -100,7 +100,7 @@ namespace Data.EF.Players return false; } name = name.Trim(); - return await db.Players.Where(p => p.Name == name).FirstOrDefaultAsync() is not null; + return await db.PlayerEntity.Where(p => p.Name == name).FirstOrDefaultAsync() is not null; } /// @@ -115,7 +115,7 @@ namespace Data.EF.Players bool isPresent = IsPresentByID(toRemove.ID).Result; if (isPresent) { - db.Players.Remove(toRemove); + db.PlayerEntity.Remove(toRemove); db.SaveChanges(); } } @@ -161,12 +161,12 @@ namespace Data.EF.Players /// public async Task GetOneByID(Guid ID) { - return await db.Players.FirstAsync(p => p.ID == ID); + return await db.PlayerEntity.FirstAsync(p => p.ID == ID); } public async Task IsPresentByID(Guid ID) { - return await db.Players.FirstOrDefaultAsync(p => p.ID == ID) is not null; + return await db.PlayerEntity.FirstOrDefaultAsync(p => p.ID == ID) is not null; } } } diff --git a/Sources/Data/EF/Players/PlayerEntity.cs b/Sources/Data/EF/Players/PlayerEntity.cs index b7f1714..e0b904b 100644 --- a/Sources/Data/EF/Players/PlayerEntity.cs +++ b/Sources/Data/EF/Players/PlayerEntity.cs @@ -1,4 +1,5 @@ -using Microsoft.EntityFrameworkCore; +using Data.EF.Games; +using Microsoft.EntityFrameworkCore; namespace Data.EF.Players { @@ -9,6 +10,8 @@ namespace Data.EF.Players public string Name { get; set; } + public ICollection Turns { get; set; } = new List(); + public override bool Equals(object obj) { if (obj is not PlayerEntity) @@ -20,7 +23,7 @@ namespace Data.EF.Players public bool Equals(PlayerEntity other) { - return other is not null && this.ID == other.ID && this.Name == other.Name; + return other is not null && this.ID.Equals(other.ID) && this.Name.Equals(other.Name); } public override int GetHashCode() diff --git a/Sources/Data/EF/Players/PlayerExtensions.cs b/Sources/Data/EF/Players/PlayerExtensions.cs index 3aa188d..a487010 100644 --- a/Sources/Data/EF/Players/PlayerExtensions.cs +++ b/Sources/Data/EF/Players/PlayerExtensions.cs @@ -4,24 +4,12 @@ namespace Data.EF.Players { public static class PlayerExtensions { - public static Player ToModel(this PlayerEntity entity) - { - return new Player(name: entity.Name); - } + public static Player ToModel(this PlayerEntity entity) => new Player(name: entity.Name); - public static IEnumerable ToModels(this IEnumerable entities) - { - return entities.Select(entity => entity.ToModel()); - } + public static IEnumerable ToModels(this IEnumerable entities) => entities.Select(entity => entity.ToModel()); - public static PlayerEntity ToEntity(this Player model) - { - return new PlayerEntity() { Name = model.Name }; - } + public static PlayerEntity ToEntity(this Player model) => new PlayerEntity() { Name = model.Name }; - public static IEnumerable ToEntities(this IEnumerable models) - { - return models.Select(model => model.ToEntity()); - } + public static IEnumerable ToEntities(this IEnumerable models) => models.Select(model => model.ToEntity()); } } diff --git a/Sources/DiceApp.sln b/Sources/DiceApp.sln index 7041b1a..e9e8a18 100644 --- a/Sources/DiceApp.sln +++ b/Sources/DiceApp.sln @@ -9,7 +9,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Tests\Tests.csproj EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{953D2D67-BCE7-412C-B7BB-7C63B5592359}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Data", "Data\Data.csproj", "{E9683741-E603-4ED3-8088-4099D67FCA6D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Data", "Data\Data.csproj", "{E9683741-E603-4ED3-8088-4099D67FCA6D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utils", "Utils\Utils\Utils.csproj", "{9300910D-9D32-4C79-8868-67D0ED56E2F3}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -29,6 +31,10 @@ Global {E9683741-E603-4ED3-8088-4099D67FCA6D}.Debug|Any CPU.Build.0 = Debug|Any CPU {E9683741-E603-4ED3-8088-4099D67FCA6D}.Release|Any CPU.ActiveCfg = Release|Any CPU {E9683741-E603-4ED3-8088-4099D67FCA6D}.Release|Any CPU.Build.0 = Release|Any CPU + {9300910D-9D32-4C79-8868-67D0ED56E2F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9300910D-9D32-4C79-8868-67D0ED56E2F3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9300910D-9D32-4C79-8868-67D0ED56E2F3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9300910D-9D32-4C79-8868-67D0ED56E2F3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Sources/DiceAppConsole.sln b/Sources/DiceAppConsole.sln index b7e99f6..b9d9678 100644 --- a/Sources/DiceAppConsole.sln +++ b/Sources/DiceAppConsole.sln @@ -14,7 +14,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Tests\Tests.csproj EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{953D2D67-BCE7-412C-B7BB-7C63B5592359}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Data", "Data\Data.csproj", "{E9683741-E603-4ED3-8088-4099D67FCA6D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Data", "Data\Data.csproj", "{E9683741-E603-4ED3-8088-4099D67FCA6D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utils", "Utils\Utils\Utils.csproj", "{9300910D-9D32-4C79-8868-67D0ED56E2F3}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -38,6 +40,10 @@ Global {E9683741-E603-4ED3-8088-4099D67FCA6D}.Debug|Any CPU.Build.0 = Debug|Any CPU {E9683741-E603-4ED3-8088-4099D67FCA6D}.Release|Any CPU.ActiveCfg = Release|Any CPU {E9683741-E603-4ED3-8088-4099D67FCA6D}.Release|Any CPU.Build.0 = Release|Any CPU + {9300910D-9D32-4C79-8868-67D0ED56E2F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9300910D-9D32-4C79-8868-67D0ED56E2F3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9300910D-9D32-4C79-8868-67D0ED56E2F3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9300910D-9D32-4C79-8868-67D0ED56E2F3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Sources/Tests/Data_UTs/DiceAppDbContextWithStubTest.cs b/Sources/Tests/Data_UTs/DiceAppDbContextWithStubTest.cs index 76ae758..9d7cb40 100644 --- a/Sources/Tests/Data_UTs/DiceAppDbContextWithStubTest.cs +++ b/Sources/Tests/Data_UTs/DiceAppDbContextWithStubTest.cs @@ -41,7 +41,7 @@ namespace Tests.Data_UTs // Assert - Assert.True(db.Players.Where(p => p.Name.Equals(name)).Any()); + Assert.True(db.PlayerEntity.Where(p => p.Name.Equals(name)).Any()); } } diff --git a/Sources/Tests/Data_UTs/Games/TurnEntityTest.cs b/Sources/Tests/Data_UTs/Games/TurnEntityTest.cs index 7b91117..0afb061 100644 --- a/Sources/Tests/Data_UTs/Games/TurnEntityTest.cs +++ b/Sources/Tests/Data_UTs/Games/TurnEntityTest.cs @@ -1,12 +1,409 @@ -using System; +using Data.EF.Dice; +using Data.EF.Dice.Faces; +using Data.EF.Games; +using Data.EF.Joins; +using Data.EF.Players; +using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Drawing; +using Xunit; namespace Tests.Data_UTs.Games { public class TurnEntityTest { + + private readonly DieEntity numDie; + private readonly FaceEntity numFace1 = new NumberFaceEntity() { ID = Guid.NewGuid(), Value = 7 }; + private readonly FaceEntity numFace2 = new NumberFaceEntity() { ID = Guid.NewGuid(), Value = 8 }; + + private readonly DieEntity clrDie; + private readonly FaceEntity clrFace1 = new ColorFaceEntity() { ID = Guid.NewGuid(), A = 255, R = 255, G = 255, B = 255 }; + private readonly FaceEntity clrFace2 = new ColorFaceEntity() { ID = Guid.NewGuid() }; + + private readonly DieEntity imgDie; + private readonly FaceEntity imgFace1 = new ImageFaceEntity() { ID = Guid.NewGuid(), Value = "https://a" }; + private readonly FaceEntity imgFace2 = new ImageFaceEntity() { ID = Guid.NewGuid(), Value = "https://b" }; + + private readonly DieTurn dieTurn1; + private readonly DieTurn dieTurn2; + private readonly DieTurn dieTurn3; + private readonly DieTurn dieTurn4; + private readonly DieTurn dieTurn5; + + private readonly FaceTurn faceTurn1; + private readonly FaceTurn faceTurn2; + private readonly FaceTurn faceTurn3; + private readonly FaceTurn faceTurn4; + private readonly FaceTurn faceTurn5; + + private readonly TurnEntity turn1; + private readonly TurnEntity turn2; + private readonly TurnEntity turn3; + + public TurnEntityTest() + { + numDie = new NumberDieEntity() { ID = Guid.NewGuid(), Faces = new List() { numFace1 as NumberFaceEntity, numFace2 as NumberFaceEntity } }; + (numFace1 as NumberFaceEntity).NumberDieEntity = (NumberDieEntity)numDie; + (numFace2 as NumberFaceEntity).NumberDieEntity = (NumberDieEntity)numDie; + + (clrFace2 as ColorFaceEntity).SetValue(Color.FromName("blue")); + + clrDie = new ColorDieEntity() { ID = Guid.NewGuid(), Faces = new List() { clrFace1 as ColorFaceEntity, clrFace2 as ColorFaceEntity } }; + (clrFace1 as ColorFaceEntity).ColorDieEntity = (ColorDieEntity)clrDie; + (clrFace2 as ColorFaceEntity).ColorDieEntity = (ColorDieEntity)clrDie; + + imgDie = new ImageDieEntity() { ID = Guid.NewGuid(), Faces = new List() { imgFace1 as ImageFaceEntity, imgFace2 as ImageFaceEntity } }; + (imgFace1 as ImageFaceEntity).ImageDieEntity = (ImageDieEntity)imgDie; + (imgFace2 as ImageFaceEntity).ImageDieEntity = (ImageDieEntity)imgDie; + + turn1 = new() + { + ID = Guid.NewGuid(), + When = datetime1, + PlayerEntity = player1, + PlayerEntityID = player1.ID, + Dice = new List + { + numDie, + clrDie, + imgDie + }, + Faces = new List + { + numFace1, + clrFace2, + imgFace2 + }, + + }; + + dieTurn1 = new() { DieEntityID = numDie.ID, DieEntity = numDie, TurnEntityID = turn1.ID, TurnEntity = turn1 }; + dieTurn2 = new() { DieEntityID = clrDie.ID, DieEntity = clrDie, TurnEntityID = turn1.ID, TurnEntity = turn1 }; + dieTurn3 = new() { DieEntityID = imgDie.ID, DieEntity = imgDie, TurnEntityID = turn1.ID, TurnEntity = turn1 }; + turn1.DieTurns = new() { dieTurn1, dieTurn2, dieTurn3 }; + numDie.DieTurns = new() { dieTurn1 }; + clrDie.DieTurns = new() { dieTurn2 }; + imgDie.DieTurns = new() { dieTurn3 }; + + faceTurn1 = new() { FaceEntityID = numFace1.ID, FaceEntity = numFace1, TurnEntityID = turn1.ID, TurnEntity = turn1 }; + faceTurn2 = new() { FaceEntityID = clrFace2.ID, FaceEntity = clrFace2, TurnEntityID = turn1.ID, TurnEntity = turn1 }; + faceTurn3 = new() { FaceEntityID = imgFace2.ID, FaceEntity = imgFace2, TurnEntityID = turn1.ID, TurnEntity = turn1 }; + turn1.FaceTurns = new() { faceTurn1, faceTurn2, faceTurn3 }; + numFace1.FaceTurns = new() { faceTurn1 }; + clrFace2.FaceTurns = new() { faceTurn2 }; + imgFace2.FaceTurns = new() { faceTurn3 }; + + Guid turn2ID = Guid.NewGuid(); + + turn2 = new() + { + ID = turn2ID, + When = datetime2, + PlayerEntity = player2, + PlayerEntityID = player2.ID, + Dice = new List + { + numDie, + clrDie + }, + Faces = new List + { + numFace2, + clrFace2 + }, + + }; + + dieTurn4 = new() { DieEntityID = numDie.ID, DieEntity = numDie, TurnEntityID = turn2.ID, TurnEntity = turn2 }; + dieTurn5 = new() { DieEntityID = clrDie.ID, DieEntity = clrDie, TurnEntityID = turn2.ID, TurnEntity = turn2 }; + turn2.DieTurns = new() { dieTurn4, dieTurn5 }; + numDie.DieTurns = new() { dieTurn4 }; + clrDie.DieTurns = new() { dieTurn5 }; + + faceTurn4 = new() { FaceEntityID = numFace2.ID, FaceEntity = numFace2, TurnEntityID = turn2.ID, TurnEntity = turn2 }; + faceTurn5 = new() { FaceEntityID = clrFace2.ID, FaceEntity = clrFace2, TurnEntityID = turn2.ID, TurnEntity = turn2 }; + turn2.FaceTurns = new() { faceTurn4, faceTurn5 }; + numFace2.FaceTurns = new() { faceTurn4 }; + clrFace2.FaceTurns = new() { faceTurn5 }; + + turn3 = new() + { + ID = turn2ID, + When = datetime2, + PlayerEntity = player2, + PlayerEntityID = player2.ID, + Dice = new List + { + numDie, + clrDie + }, + Faces = new List + { + numFace2, + clrFace2 + }, + + }; + } + + + + private readonly PlayerEntity player1 = new() { ID = Guid.NewGuid(), Name = "Marvin" }; + private readonly PlayerEntity player2 = new() { ID = Guid.NewGuid(), Name = "Barbara" }; + + private readonly DateTime datetime1 = new(2020, 6, 15, 12, 15, 3, DateTimeKind.Utc); + private readonly DateTime datetime2 = new(2016, 12, 13, 14, 15, 16, DateTimeKind.Utc); + + [Fact] + public void TestGetSetID() + { + // Arrange + TurnEntity turn = new(); + Guid expected = Guid.NewGuid(); + + // Act + turn.ID = expected; + Guid actual = turn.ID; + + // Assert + Assert.Equal(expected, actual); + } + + [Fact] + public void TestGetSetWhen() + { + // Arrange + TurnEntity turn = new(); + DateTime expected = datetime1; + + + // Act + turn.When = expected; + DateTime actual = turn.When; + + // Assert + Assert.Equal(expected, actual); + } + + [Fact] + public void TestGetSetPlayer() + { + // Arrange + TurnEntity turn = new(); + PlayerEntity expected = player1; + + + // Act + turn.PlayerEntity = expected; + PlayerEntity actual = turn.PlayerEntity; + + // Assert + Assert.Equal(expected, actual); + } + + [Fact] + public void TestGetSetPlayerID() + { + // Arrange + TurnEntity turn = new(); + Guid expected = player1.ID; + + // Act + turn.PlayerEntityID = expected; + Guid actual = turn.PlayerEntityID; + + // Assert + Assert.Equal(expected, actual); + } + + [Fact] + public void TestGetSetDice() + { + // Arrange + TurnEntity turn = new(); + + + ICollection expected = new List + { + numDie, + clrDie, + imgDie + }; + + // Act + turn.Dice = expected; + ICollection actual = turn.Dice; + + // Assert + Assert.Equal(expected, actual); + } + + [Fact] + public void TestGetSetDieTurns() + { + // Arrange + TurnEntity turn = new(); + List expected = new() { dieTurn1, dieTurn2, dieTurn3 }; + + + // Act + turn.DieTurns = expected; + List actual = turn.DieTurns; + + // Assert + Assert.Equal(expected, actual); + } + + [Fact] + public void TestGetSetFaces() + { + // Arrange + TurnEntity turn = new(); + + + ICollection expected = new List + { + numFace1, + clrFace1, + imgFace1 + }; + + // Act + turn.Faces = expected; + ICollection actual = turn.Faces; + + // Assert + Assert.Equal(expected, actual); + } + + [Fact] + public void TestGetSetFaceTurns() + { + // Arrange + TurnEntity turn = new(); + List expected = new() { faceTurn1, faceTurn2 }; + + + // Act + turn.FaceTurns = expected; + List actual = turn.FaceTurns; + + // Assert + Assert.Equal(expected, actual); + } + + [Fact] + public void TestEqualsWhenNotTurnEntityThenFalse() + { + // Arrange + Point point; + TurnEntity entity; + + // Act + point = new(1, 2); + entity = turn1; + + // Assert + Assert.False(point.Equals(entity)); + Assert.False(entity.Equals(point)); + } + + [Fact] + public void TestEqualsWhenNullThenFalse() + { + // Arrange + TurnEntity entity; + + // Act + entity = turn2; + + // Assert + Assert.False(entity.Equals(null)); + } + + [Fact] + public void TestGoesThruToSecondMethodIfObjIsTypeTurnEntity() + { + // Arrange + object t1; + TurnEntity t2; + + // Act + t1 = turn1; + t2 = turn2; + + // Assert + Assert.False(t1.Equals(t2)); + Assert.False(t2.Equals(t1)); + } + + [Fact] + public void TestEqualsFalseIfNotSame() + { + // Arrange + TurnEntity t1; + TurnEntity t2; + + // Act + + t1 = turn1; + t2 = turn2; + + // Assert + Assert.False(t1.Equals(t2)); + Assert.False(t2.Equals(t1)); + } + + [Fact] + public void TestEqualsTrueIfSame() + { + // Arrange + TurnEntity t1; + TurnEntity t2; + + // Act + + t1 = turn2; + t2 = turn3; // turns 2 and 3 should be same as far as Equals is concerned + + // Assert + Assert.True(t1.Equals(t2)); + Assert.True(t2.Equals(t1)); + } + + [Fact] + public void TestSameHashFalseIfNotSame() + { + // Arrange + TurnEntity t1; + TurnEntity t2; + + // Act + + t1 = turn1; + t2 = turn2; + + // Assert + Assert.False(t1.GetHashCode().Equals(t2.GetHashCode())); + Assert.False(t2.GetHashCode().Equals(t1.GetHashCode())); + } + + [Fact] + public void TestSameHashTrueIfSame() + { + // Arrange + TurnEntity t1; + TurnEntity t2; + + // Act + + t1 = turn2; + t2 = turn3; + + // Assert + Assert.True(t1.GetHashCode().Equals(t2.GetHashCode())); + Assert.True(t2.GetHashCode().Equals(t1.GetHashCode())); + } } } diff --git a/Sources/Tests/Data_UTs/Players/PlayerDbManagerTest.cs b/Sources/Tests/Data_UTs/Players/PlayerDbManagerTest.cs index 6978a6b..78d43d8 100644 --- a/Sources/Tests/Data_UTs/Players/PlayerDbManagerTest.cs +++ b/Sources/Tests/Data_UTs/Players/PlayerDbManagerTest.cs @@ -368,7 +368,7 @@ namespace Tests.Data_UTs.Players { db.Database.EnsureCreated(); - Assert.DoesNotContain(toRemove, db.Players); + Assert.DoesNotContain(toRemove, db.PlayerEntity); } } @@ -656,11 +656,9 @@ namespace Tests.Data_UTs.Players PlayerDbManager mgr; Guid id = Guid.NewGuid(); - - Guid otherId = Guid.NewGuid(); + Guid otherId; PlayerEntity presentEntity; - PlayerEntity absentEntity; // Act @@ -670,9 +668,10 @@ namespace Tests.Data_UTs.Players mgr = new(db); presentEntity = new() { ID = id, Name = "Victor" }; - await mgr.Add(presentEntity); - - absentEntity = new() { ID = otherId, Name = "Victor" }; + await mgr.Add(presentEntity); + + otherId = Guid.NewGuid(); + // not added } // Assert @@ -682,7 +681,7 @@ namespace Tests.Data_UTs.Players db.Database.EnsureCreated(); mgr = new(db); - Assert.DoesNotContain(absentEntity, db.Players); + Assert.False(await mgr.IsPresentByID(otherId)); } } } diff --git a/Sources/Tests/Data_UTs/Players/PlayerEntityTest.cs b/Sources/Tests/Data_UTs/Players/PlayerEntityTest.cs index db482cc..56f1dba 100644 --- a/Sources/Tests/Data_UTs/Players/PlayerEntityTest.cs +++ b/Sources/Tests/Data_UTs/Players/PlayerEntityTest.cs @@ -1,6 +1,5 @@ using Data.EF.Players; using System; -using Tests.Model_UTs; using Xunit; namespace Tests.Data_UTs.Players diff --git a/Sources/Tests/Model_UTs/Point.cs b/Sources/Tests/Point.cs similarity index 83% rename from Sources/Tests/Model_UTs/Point.cs rename to Sources/Tests/Point.cs index e5b6b5e..15559f7 100644 --- a/Sources/Tests/Model_UTs/Point.cs +++ b/Sources/Tests/Point.cs @@ -1,13 +1,13 @@ -namespace Tests.Model_UTs -{ - public class Point - { - public int X { get; private set; } - public int Y { get; private set; } - public Point(int x, int y) - { - X = x; Y = y; - } - - } -} +namespace Tests +{ + public class Point + { + public int X { get; private set; } + public int Y { get; private set; } + public Point(int x, int y) + { + X = x; Y = y; + } + + } +} diff --git a/Sources/Tests/Utils_UTs/EnumerablesTest.cs b/Sources/Tests/Utils_UTs/EnumerablesTest.cs new file mode 100644 index 0000000..cb86388 --- /dev/null +++ b/Sources/Tests/Utils_UTs/EnumerablesTest.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Utils; +using Xunit; + +namespace Tests.Utils_UTs +{ + public class EnumerablesTest + { + [Fact] + public void TestFeedListsToDict() + { + // Arrange + string str1 = "blah"; + string str2 = "blahblah"; + string str3 = "azfyoaz"; + + int int1 = 5; + int int2 = 12; + int int3 = 3; + + Dictionary expected = new() + { + { str1, int1 }, + { str2, int2 }, + { str3, int3 } + }; + + List strings = new() { str2, str3 }; + List ints = new() { int2, int3 }; + + Dictionary actual = new() + { + {str1, int1 } + }; // we will add on top of this + + // Act + + actual = Enumerables.FeedListsToDict(actual, strings, ints); + // Assert + + Assert.Equal(expected, actual); + } + + [Fact] + public void TestGetDictFromLists() + { + // Arrange + string str1 = "blah"; + string str2 = "blahblah"; + + int int1 = 5; + int int2 = 12; + + Dictionary expected = new() + { + { str1, int1 }, + { str2, int2 } + }; + + List strings = new() { str1, str2 }; + List ints = new() { int1, int2 }; + + // Act + + Dictionary actual = Enumerables.GetDictFromLists(strings, ints); + // Assert + + Assert.Equal(expected, actual); + } + } +} diff --git a/Sources/Utils/Utils/Enumerables.cs b/Sources/Utils/Utils/Enumerables.cs new file mode 100644 index 0000000..614e013 --- /dev/null +++ b/Sources/Utils/Utils/Enumerables.cs @@ -0,0 +1,21 @@ +namespace Utils +{ + public static class Enumerables + { + + public static Dictionary GetDictFromLists(List keys, List values) + { + return keys.Zip(values, (k, v) => new { k, v }) + .ToDictionary(x => x.k, x => x.v); + } + + public static Dictionary FeedListsToDict(Dictionary kvps, List keys, List values) + { + foreach (var kv in GetDictFromLists(keys, values)) + { + kvps.Add(kv.Key, kv.Value); + } + return kvps; + } + } +} \ No newline at end of file diff --git a/Sources/Utils/Utils/Utils.csproj b/Sources/Utils/Utils/Utils.csproj new file mode 100644 index 0000000..d215c71 --- /dev/null +++ b/Sources/Utils/Utils/Utils.csproj @@ -0,0 +1,8 @@ + + + + net6.0 + enable + + +