diff --git a/.gitignore b/.gitignore
index 4a3a6d3..6c1ac87 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,9 @@
##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
+# User-spacific editor config
+.editorconfig
+
# User-specific files
*.rsuser
*.suo
diff --git a/MCTG/MCTGApp/MCTGApp.csproj b/MCTG/ConsoleApp/ConsoleApp.csproj
similarity index 73%
rename from MCTG/MCTGApp/MCTGApp.csproj
rename to MCTG/ConsoleApp/ConsoleApp.csproj
index f02677b..c7f3ecd 100644
--- a/MCTG/MCTGApp/MCTGApp.csproj
+++ b/MCTG/ConsoleApp/ConsoleApp.csproj
@@ -7,4 +7,8 @@
enable
+
+
+
+
diff --git a/MCTG/ConsoleApp/Program.cs b/MCTG/ConsoleApp/Program.cs
new file mode 100644
index 0000000..773f61b
--- /dev/null
+++ b/MCTG/ConsoleApp/Program.cs
@@ -0,0 +1,21 @@
+// See https://aka.ms/new-console-template for more information
+
+using ConsoleApp;
+using Model;
+
+
+Console.WriteLine("Hello, World!\n\n");
+
+
+// TESTS:
+
+Stub stub = new Stub();
+
+List recipes = stub.LoadRecipes();
+List recipeCollections = stub.LoadRecipeCollection();
+
+foreach (Recipe r in recipes)
+ Console.WriteLine(r);
+
+foreach (RecipeCollection r in recipeCollections)
+ Console.WriteLine(r);
diff --git a/MCTG/ConsoleApp/Stub.cs b/MCTG/ConsoleApp/Stub.cs
new file mode 100644
index 0000000..a6fc02a
--- /dev/null
+++ b/MCTG/ConsoleApp/Stub.cs
@@ -0,0 +1,45 @@
+using Model;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ConsoleApp
+{
+ internal struct Stub
+ {
+ public List LoadRecipes()
+ {
+ List stub = new List();
+ stub.AddRange(new[]
+ {
+ new Recipe(),
+ new Recipe("Cookies"),
+ new Recipe("Cookies", 23),
+ new Recipe("Cookies", null),
+ new Recipe("", null),
+ new Recipe("", 24),
+ new Recipe("Cookies", 24,
+ new PreparationStep(1)),
+ new Recipe("Cookies", 26,
+ new PreparationStep(1),
+ new PreparationStep(2, "Faire cuire."))
+ });
+ return stub;
+ }
+
+ public List LoadRecipeCollection()
+ {
+ List stub = new List();
+ stub.AddRange(new[]
+ {
+ new RecipeCollection("All", LoadRecipes().ToArray()),
+ new RecipeCollection("Starters", LoadRecipes().FindAll(x => x.Id.Equals(23)).ToArray()),
+ new RecipeCollection("Dishies", LoadRecipes().FindAll(x => x.Id.Equals(24)).ToArray()),
+ new RecipeCollection("Desserts", LoadRecipes().FindAll(x => x.Id.Equals(26)).ToArray()),
+ });
+ return stub;
+ }
+ }
+}
diff --git a/MCTG/MCTGApp/Program.cs b/MCTG/MCTGApp/Program.cs
deleted file mode 100644
index 3751555..0000000
--- a/MCTG/MCTGApp/Program.cs
+++ /dev/null
@@ -1,2 +0,0 @@
-// See https://aka.ms/new-console-template for more information
-Console.WriteLine("Hello, World!");
diff --git a/MCTG/MCTGLib/Class1.cs b/MCTG/MCTGLib/Class1.cs
deleted file mode 100644
index 5b51184..0000000
--- a/MCTG/MCTGLib/Class1.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace MCTGLib
-{
- public class Class1
- {
-
- }
-}
\ No newline at end of file
diff --git a/MCTG/MCTGLib/MCTGLib.csproj b/MCTG/Model/Model.csproj
similarity index 100%
rename from MCTG/MCTGLib/MCTGLib.csproj
rename to MCTG/Model/Model.csproj
diff --git a/MCTG/Model/PreparationStep.cs b/MCTG/Model/PreparationStep.cs
new file mode 100644
index 0000000..95d15ca
--- /dev/null
+++ b/MCTG/Model/PreparationStep.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Model
+{
+ ///
+ /// Define a step of the preparation of a recipe.
+ ///
+ public class PreparationStep : IEquatable
+ {
+ #region Attributes
+ private string _description = "";
+ #endregion
+
+ #region Properties
+ ///
+ /// The order of this step in the preparation of the meal.
+ ///
+ public int Order { get; init; }
+
+ ///
+ /// The description of the task the user need to do for this step of the preparation.
+ /// Set to "No description." when the value passed is null, empty or contain white spaces.
+ ///
+ public string Description
+ {
+ get => _description;
+ private set
+ {
+ if (string.IsNullOrWhiteSpace(value))
+ _description = "No description.";
+ else
+ _description = value;
+ }
+ }
+ #endregion
+
+ #region Constructors
+ ///
+ /// Construct a new step of preparation.
+ ///
+ /// The number of the order in preparation
+ /// The description of the task
+ public PreparationStep(int order, string description = "")
+ {
+ Order = order;
+ Description = description;
+ }
+ #endregion
+
+ #region Methods
+ public virtual bool Equals(PreparationStep? other)
+ {
+ if (other == null) return false;
+ if (other == this) return true;
+ return Order.Equals(other.Order) && Description.Equals(other.Description);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ var item = obj as PreparationStep;
+ if (item == null) return false;
+ return Equals(obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return Order.GetHashCode() + Description.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return $"{Order}- {Description}";
+ }
+ #endregion
+ }
+}
diff --git a/MCTG/Model/Recipe.cs b/MCTG/Model/Recipe.cs
new file mode 100644
index 0000000..9d65bf9
--- /dev/null
+++ b/MCTG/Model/Recipe.cs
@@ -0,0 +1,101 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace Model
+{
+ ///
+ /// Define a Recipe for the preparation of a meal.
+ ///
+ public class Recipe : IEquatable
+ {
+ #region Attributes
+ private string _title = "";
+ #endregion
+
+ #region Properties
+ ///
+ /// The ID of the recipe - allows you to compare and/or get this item in an easier way.
+ ///
+ public int Id { get; init; }
+
+ ///
+ /// The Title of the recipe.
+ /// Set to "No title." when the value passed is null, empty or contain white spaces.
+ ///
+ public string Title
+ {
+ get => _title;
+ set
+ {
+ if (string.IsNullOrWhiteSpace(value))
+ _title = "No title.";
+ else
+ _title = value;
+ }
+ }
+
+ ///
+ /// The steps of the preparation. See: .
+ ///
+ public List PreparationSteps { get; set; }
+ #endregion
+
+ #region Constructors
+ ///
+ /// Construct a new recipe.
+ ///
+ /// The title of the recipe
+ /// The id of the recipe. If not given, get a new id.
+ /// The steps of the preparation of the meal
+ public Recipe(string title = "", int? id = null,
+ params PreparationStep[] preparationSteps)
+ {
+ Title = title;
+ PreparationSteps = new List(preparationSteps);
+
+ if (id == null)
+ {
+ var randomGenerator = RandomNumberGenerator.Create();
+ byte[] data = new byte[16];
+ randomGenerator.GetBytes(data);
+ Id = Math.Abs(BitConverter.ToInt16(data));
+ }
+ else Id = (int)id;
+ }
+ #endregion
+
+ #region Methods
+ public virtual bool Equals(Recipe? other)
+ {
+ if (other == null) return false;
+ if (other == this) return true;
+ return Title.Equals(other.Title) && PreparationSteps.Equals(other.PreparationSteps);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ var item = obj as Recipe;
+ if (item == null) return false;
+ return Equals(obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return Id.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder($"[Recipe n°{Id}] - {Title}\n");
+ foreach (PreparationStep ps in PreparationSteps)
+ {
+ sb.AppendFormat("\t* {0}\n", ps.ToString());
+ }
+ return sb.ToString();
+ }
+ #endregion
+ }
+}
diff --git a/MCTG/Model/RecipeCollection.cs b/MCTG/Model/RecipeCollection.cs
new file mode 100644
index 0000000..3592bb8
--- /dev/null
+++ b/MCTG/Model/RecipeCollection.cs
@@ -0,0 +1,154 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Text;
+
+namespace Model
+{
+ ///
+ /// Define a collection of .
+ ///
This class implement and .
+ ///
+ public class RecipeCollection : IList, IEquatable
+ {
+ #region Attributes
+ private readonly List _recipes;
+ private string _description = "";
+ #endregion
+
+ #region Properties
+ ///
+ /// A short description of what this collection contain.
+ /// Set to "No description." when the value passed is null, empty or contain white spaces.
+ ///
+ public string Description
+ {
+ get => _description;
+ set
+ {
+ if (string.IsNullOrWhiteSpace(value))
+ _description = "No description.";
+ else
+ _description = value;
+ }
+ }
+
+ #region IList Prperties
+ public int Count => _recipes.Count;
+ public bool IsReadOnly => false;
+ public Recipe this[int index] { get => _recipes[index]; set => _recipes[index] = value; }
+ #endregion
+ #endregion
+
+ #region Constructors
+ ///
+ /// Construct a new collection of _recipes.
+ ///
+ /// A short description of what this list will contain
+ /// Recipes to add in this new collection
+ public RecipeCollection(string description, params Recipe[] recipes)
+ {
+ _recipes = new List(recipes);
+ Description = description;
+ }
+ #endregion
+
+ #region Methods
+ ///
+ /// Find a recipe in this list by giving the id.
+ ///
+ /// The id of the list we are looking for
+ /// The recipe of the id given
+ ///
+ public Recipe? GetRecipeById(int id)
+ {
+ Recipe? recipe = _recipes.Find(r => r.Id == id);
+ if (recipe == null) throw new ArgumentException("No _recipes match the given id.");
+ return recipe;
+ }
+
+ #region IList Methods
+ public int IndexOf(Recipe item)
+ {
+ return _recipes.IndexOf(item);
+ }
+
+ public void Insert(int index, Recipe item)
+ {
+ _recipes.Insert(index, item);
+ }
+
+ public void RemoveAt(int index)
+ {
+ _recipes.RemoveAt(index);
+ }
+
+ public void Add(Recipe item)
+ {
+ _recipes.Add(item);
+ }
+
+ public void Clear()
+ {
+ _recipes.Clear();
+ }
+
+ public bool Contains(Recipe item)
+ {
+ return _recipes.Contains(item);
+ }
+
+ public void CopyTo(Recipe[] array, int arrayIndex)
+ {
+ _recipes.CopyTo(array, arrayIndex);
+ }
+
+ public bool Remove(Recipe item)
+ {
+ return _recipes.Remove(item);
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ return _recipes.GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return _recipes.GetEnumerator();
+ }
+ #endregion
+
+ public virtual bool Equals(RecipeCollection? other)
+ {
+
+ if (other == null) return false;
+ if (other == this) return true;
+ return _description.Equals(other.Description) && _recipes.Equals(other._recipes);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ var item = obj as RecipeCollection;
+ if (item == null) return false;
+ return Equals(obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return _recipes.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder($"[RecipeCollection] - {Description}:\n");
+ foreach (Recipe r in _recipes)
+ {
+ sb.AppendFormat("\t - {0}\n", r.ToString());
+ }
+ return sb.ToString();
+ }
+ #endregion
+ }
+}
diff --git a/MCTG/SAE-2.01.sln b/MCTG/SAE-2.01.sln
index ab7e910..81242a9 100644
--- a/MCTG/SAE-2.01.sln
+++ b/MCTG/SAE-2.01.sln
@@ -3,11 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.33516.290
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MCTGApp", "MCTGApp\MCTGApp.csproj", "{666C2211-8EBB-4FC8-9484-CB93BC854153}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleApp", "ConsoleApp\ConsoleApp.csproj", "{666C2211-8EBB-4FC8-9484-CB93BC854153}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MCTGLib", "MCTGLib\MCTGLib.csproj", "{42FF86BD-92F9-4A32-A938-68515905378F}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Model", "Model\Model.csproj", "{42FF86BD-92F9-4A32-A938-68515905378F}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MCTGLib_UnitTests", "Tests\MCTGLib_UnitTests\MCTGLib_UnitTests.csproj", "{45AB746A-194B-4E43-81EB-83B06F35AA33}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Model_UnitTests", "Tests\Model_UnitTests\Model_UnitTests.csproj", "{45AB746A-194B-4E43-81EB-83B06F35AA33}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{08B80CE8-A01D-4D86-8989-AF225D5DA48C}"
EndProject
diff --git a/MCTG/Tests/MCTGLib_UnitTests/UnitTest1.cs b/MCTG/Tests/MCTGLib_UnitTests/UnitTest1.cs
deleted file mode 100644
index 4d22b68..0000000
--- a/MCTG/Tests/MCTGLib_UnitTests/UnitTest1.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace MCTGLib_UnitTests
-{
- public class UnitTest1
- {
- [Fact]
- public void Test1()
- {
-
- }
- }
-}
\ No newline at end of file
diff --git a/MCTG/Tests/MCTGLib_UnitTests/MCTGLib_UnitTests.csproj b/MCTG/Tests/Model_UnitTests/Model_UnitTests.csproj
similarity index 91%
rename from MCTG/Tests/MCTGLib_UnitTests/MCTGLib_UnitTests.csproj
rename to MCTG/Tests/Model_UnitTests/Model_UnitTests.csproj
index 42ff44d..dc31a95 100644
--- a/MCTG/Tests/MCTGLib_UnitTests/MCTGLib_UnitTests.csproj
+++ b/MCTG/Tests/Model_UnitTests/Model_UnitTests.csproj
@@ -22,4 +22,8 @@
+
+
+
+
diff --git a/MCTG/Tests/Model_UnitTests/Recipe_UT.cs b/MCTG/Tests/Model_UnitTests/Recipe_UT.cs
new file mode 100644
index 0000000..e8593a5
--- /dev/null
+++ b/MCTG/Tests/Model_UnitTests/Recipe_UT.cs
@@ -0,0 +1,26 @@
+using Model;
+
+namespace Model_UnitTests
+{
+ public class Recipe_UT
+ {
+ [Fact]
+ public void TestVoidConstructor()
+ {
+ Recipe r = new Recipe(id: 999); // id is given to avoid tests errors with the static atrribute 'idCreator'.
+ Assert.NotNull(r.Title);
+ }
+
+ [Theory]
+ [InlineData("Cookies", 23, "Cookies", 23)]
+ [InlineData("Cookies", 1, "Cookies", 1)]
+ [InlineData("No title.", 1, "", 1)]
+ public void TestConstructor(string expectedTitle, int expectedId, string title, int? id)
+ {
+ Recipe r = new Recipe(title, id);
+ Assert.NotNull(r.Title);
+ Assert.Equal(expectedId, r.Id);
+ Assert.Equal(expectedTitle, r.Title);
+ }
+ }
+}
diff --git a/MCTG/Tests/MCTGLib_UnitTests/Usings.cs b/MCTG/Tests/Model_UnitTests/Usings.cs
similarity index 100%
rename from MCTG/Tests/MCTGLib_UnitTests/Usings.cs
rename to MCTG/Tests/Model_UnitTests/Usings.cs