diff --git a/Refactoring.sln b/Refactoring.sln index e744380..10ce691 100644 --- a/Refactoring.sln +++ b/Refactoring.sln @@ -1,8 +1,6 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.40629.0 -MinimumVisualStudioVersion = 10.0.40219.1 +# Visual Studio 2012 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Refactoring", "Refactoring\Refactoring.csproj", "{2D3F5D0E-4A6B-44C0-8F63-8E95243AC028}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTestProject", "UnitTestProject\UnitTestProject.csproj", "{1FAF99A1-CCBF-435D-B599-4DAE1DAD5105}" @@ -10,17 +8,27 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {2D3F5D0E-4A6B-44C0-8F63-8E95243AC028}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2D3F5D0E-4A6B-44C0-8F63-8E95243AC028}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2D3F5D0E-4A6B-44C0-8F63-8E95243AC028}.Debug|x64.ActiveCfg = Debug|x64 + {2D3F5D0E-4A6B-44C0-8F63-8E95243AC028}.Debug|x64.Build.0 = Debug|x64 {2D3F5D0E-4A6B-44C0-8F63-8E95243AC028}.Release|Any CPU.ActiveCfg = Release|Any CPU {2D3F5D0E-4A6B-44C0-8F63-8E95243AC028}.Release|Any CPU.Build.0 = Release|Any CPU + {2D3F5D0E-4A6B-44C0-8F63-8E95243AC028}.Release|x64.ActiveCfg = Release|x64 + {2D3F5D0E-4A6B-44C0-8F63-8E95243AC028}.Release|x64.Build.0 = Release|x64 {1FAF99A1-CCBF-435D-B599-4DAE1DAD5105}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1FAF99A1-CCBF-435D-B599-4DAE1DAD5105}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1FAF99A1-CCBF-435D-B599-4DAE1DAD5105}.Debug|x64.ActiveCfg = Debug|x64 + {1FAF99A1-CCBF-435D-B599-4DAE1DAD5105}.Debug|x64.Build.0 = Debug|x64 {1FAF99A1-CCBF-435D-B599-4DAE1DAD5105}.Release|Any CPU.ActiveCfg = Release|Any CPU {1FAF99A1-CCBF-435D-B599-4DAE1DAD5105}.Release|Any CPU.Build.0 = Release|Any CPU + {1FAF99A1-CCBF-435D-B599-4DAE1DAD5105}.Release|x64.ActiveCfg = Release|x64 + {1FAF99A1-CCBF-435D-B599-4DAE1DAD5105}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Refactoring/ConsoleUserInterface.cs b/Refactoring/ConsoleUserInterface.cs new file mode 100644 index 0000000..e9dc269 --- /dev/null +++ b/Refactoring/ConsoleUserInterface.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Refactoring +{ + public class ConsoleUserInterface : UserInterface + { + public void displayBanner(string bannerText) + { + Console.WriteLine(bannerText); + Console.WriteLine(new string('-', bannerText.Length)); + } + + public string getStringInputFromUser(string labelText) + { + Console.WriteLine(); + Console.WriteLine(labelText); + return Console.ReadLine(); + } + + public void promptUserToExit() + { + Console.WriteLine(); + Console.WriteLine("Press Enter key to exit"); + Console.ReadLine(); + } + + public void displayErrors(params string[] errorText) + { + displayMessageWithColor(ConsoleColor.Red, errorText); + } + + public void displayWarnings(params string[] warningText) + { + displayMessageWithColor(ConsoleColor.Yellow, warningText); + } + + public void displayNotices(params string[] noticeText) + { + displayMessageWithColor(ConsoleColor.Green, noticeText); + } + + private void displayMessageWithColor(ConsoleColor color, params string[] messages) + { + Console.Clear(); + Console.ForegroundColor = color; + Console.WriteLine(); + foreach (string message in messages) + Console.WriteLine(message); + Console.ResetColor(); + } + } +} diff --git a/Refactoring/LoginManager.cs b/Refactoring/LoginManager.cs new file mode 100644 index 0000000..44d377b --- /dev/null +++ b/Refactoring/LoginManager.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Refactoring +{ + public class LoginManager + { + private UserInterface ui; + private IEnumerable users; + + public LoginManager(IEnumerable users, UserInterface ui) + { + if (users == null) + throw new ArgumentException(); + + if (ui == null) + throw new ArgumentException(); + + this.users = users; + this.ui = ui; + } + + private bool isUserNameValid(string userName) + { + return users.Any(user => user.Name == userName); + } + + private User getUserByUserNameAndPassword(string userName, string password) + { + return users.FirstOrDefault(user => user.Name == userName && user.Password == password); + } + + public User login() + { + while (true) // RFUTODO: Temporary! + { + string userName = ui.getStringInputFromUser(Environment.NewLine + "Enter Username:"); // TODO: Deal with the extra line we need to add here + + if (string.IsNullOrEmpty(userName)) + return null; + + if (isUserNameValid(userName)) + { + string password = ui.getStringInputFromUser("Enter Password:"); + + User matchingUser = getUserByUserNameAndPassword(userName, password); + + if (matchingUser != null) + return matchingUser; + + ui.displayErrors("You entered an invalid password."); + } + else + { + ui.displayErrors("You entered an invalid user."); + } + } + } + } +} diff --git a/Refactoring/Product.cs b/Refactoring/Product.cs index c9ceee5..2e42aa5 100644 --- a/Refactoring/Product.cs +++ b/Refactoring/Product.cs @@ -15,6 +15,6 @@ public class Product [JsonProperty("Price")] public double Price; [JsonProperty("Quantity")] - public int Qty; + public int Quantity; } } diff --git a/Refactoring/Program.cs b/Refactoring/Program.cs index f0509aa..c780cfa 100644 --- a/Refactoring/Program.cs +++ b/Refactoring/Program.cs @@ -9,15 +9,20 @@ namespace Refactoring { public class Program { + private static string USERS_FILE = @"Data/Users.json"; + private static string PRODUCTS_FILE = @"Data/Products.json"; + public static void Main(string[] args) { - // Load users from data file - List users = JsonConvert.DeserializeObject>(File.ReadAllText(@"Data/Users.json")); + List users = JsonConvert.DeserializeObject>(File.ReadAllText(USERS_FILE)); + List products = JsonConvert.DeserializeObject>(File.ReadAllText(PRODUCTS_FILE)); + + UserInterface ui = new ConsoleUserInterface(); - // Load products from data file - List products = JsonConvert.DeserializeObject>(File.ReadAllText(@"Data/Products.json")); + Tusc.Start(users, products, ui); - Tusc.Start(users, products); + File.WriteAllText(USERS_FILE, JsonConvert.SerializeObject(users, Formatting.Indented)); + File.WriteAllText(PRODUCTS_FILE, JsonConvert.SerializeObject(products, Formatting.Indented)); } } } diff --git a/Refactoring/Refactoring.csproj b/Refactoring/Refactoring.csproj index 6696ba9..07e50c6 100644 --- a/Refactoring/Refactoring.csproj +++ b/Refactoring/Refactoring.csproj @@ -11,6 +11,8 @@ Refactoring v4.5 512 + ..\ + true AnyCPU @@ -31,6 +33,26 @@ prompt 4 + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + prompt + MinimumRecommendedRules.ruleset + true + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + true + ..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll @@ -45,11 +67,15 @@ + + + + diff --git a/Refactoring/Store.cs b/Refactoring/Store.cs new file mode 100644 index 0000000..1fc7d2f --- /dev/null +++ b/Refactoring/Store.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Refactoring +{ + public class Store + { + public Store(List products, UserInterface ui) + { + if (products == null) + throw new ArgumentException(); + + if (ui == null) + throw new ArgumentException(); + } + } +} diff --git a/Refactoring/Tusc.cs b/Refactoring/Tusc.cs index bd07dce..45fd1aa 100644 --- a/Refactoring/Tusc.cs +++ b/Refactoring/Tusc.cs @@ -10,221 +10,92 @@ namespace Refactoring { public class Tusc { - public static void Start(List usrs, List prods) + public static void Start(List users, List products, UserInterface ui) { // Write welcome message - Console.WriteLine("Welcome to TUSC"); - Console.WriteLine("---------------"); + ui.displayBanner("Welcome to TUSC"); - // Login - Login: - bool loggedIn = false; // Is logged in? + LoginManager loginManager = new LoginManager(users, ui); + User loggedInUser = loginManager.login(); - // Prompt for user input + if (loggedInUser == null) + { + ui.promptUserToExit(); + return; + } + + // Show welcome message + ui.displayNotices("Login successful! Welcome " + loggedInUser.Name + "!"); + + // Show balance Console.WriteLine(); - Console.WriteLine("Enter Username:"); - string name = Console.ReadLine(); + Console.WriteLine("Your balance is " + loggedInUser.Balance.ToString("C")); - // Validate Username - bool valUsr = false; // Is valid user? - if (!string.IsNullOrEmpty(name)) + // Show product list + while (true) { - for (int i = 0; i < 5; i++) + // Prompt for user input + Console.WriteLine(); + Console.WriteLine("What would you like to buy?"); + for (int i = 0; i < 7; i++) { - User user = usrs[i]; - // Check that name matches - if (user.Name == name) - { - valUsr = true; - } + Product product = products[i]; + Console.WriteLine(i + 1 + ": " + product.Name + " (" + product.Price.ToString("C") + ")"); } + Console.WriteLine(products.Count + 1 + ": Exit"); + + // Prompt for user input + string answer = ui.getStringInputFromUser("Enter a number:"); + int selectedProductIndex = Convert.ToInt32(answer); + selectedProductIndex = selectedProductIndex - 1; - // if valid user - if (valUsr) + // Check if user entered number that equals product count + if (selectedProductIndex == products.Count) + { + ui.promptUserToExit(); + return; + } + else { + Product selectedProduct = products[selectedProductIndex]; + Console.WriteLine(); + Console.WriteLine("You want to buy: " + selectedProduct.Name); + Console.WriteLine("Your balance is " + loggedInUser.Balance.ToString("C")); + // Prompt for user input - Console.WriteLine("Enter Password:"); - string pwd = Console.ReadLine(); + answer = ui.getStringInputFromUser("Enter amount to purchase:"); + int quantityToPurchase = Convert.ToInt32(answer); - // Validate Password - bool valPwd = false; // Is valid password? - for (int i = 0; i < 5; i++) + // Check if balance - quantity * price is less than 0 + if (loggedInUser.Balance - selectedProduct.Price * quantityToPurchase < 0) { - User user = usrs[i]; - - // Check that name and password match - if (user.Name == name && user.Pwd == pwd) - { - valPwd = true; - } + ui.displayErrors("You do not have enough money to buy that."); + continue; } - // if valid password - if (valPwd == true) + // Check if quantity is less than quantity + if (selectedProduct.Quantity <= quantityToPurchase) { - loggedIn = true; - - // Show welcome message - Console.Clear(); - Console.ForegroundColor = ConsoleColor.Green; - Console.WriteLine(); - Console.WriteLine("Login successful! Welcome " + name + "!"); - Console.ResetColor(); - - // Show remaining balance - double bal = 0; - for (int i = 0; i < 5; i++) - { - User usr = usrs[i]; - - // Check that name and password match - if (usr.Name == name && usr.Pwd == pwd) - { - bal = usr.Bal; - - // Show balance - Console.WriteLine(); - Console.WriteLine("Your balance is " + usr.Bal.ToString("C")); - } - } - - // Show product list - while (true) - { - // Prompt for user input - Console.WriteLine(); - Console.WriteLine("What would you like to buy?"); - for (int i = 0; i < 7; i++) - { - Product prod = prods[i]; - Console.WriteLine(i + 1 + ": " + prod.Name + " (" + prod.Price.ToString("C") + ")"); - } - Console.WriteLine(prods.Count + 1 + ": Exit"); - - // Prompt for user input - Console.WriteLine("Enter a number:"); - string answer = Console.ReadLine(); - int num = Convert.ToInt32(answer); - num = num - 1; /* Subtract 1 from number - num = num + 1 // Add 1 to number */ - - // Check if user entered number that equals product count - if (num == 7) - { - // Update balance - foreach (var usr in usrs) - { - // Check that name and password match - if (usr.Name == name && usr.Pwd == pwd) - { - usr.Bal = bal; - } - } - - // Write out new balance - string json = JsonConvert.SerializeObject(usrs, Formatting.Indented); - File.WriteAllText(@"Data/Users.json", json); - - // Write out new quantities - string json2 = JsonConvert.SerializeObject(prods, Formatting.Indented); - File.WriteAllText(@"Data/Products.json", json2); - - - // Prevent console from closing - Console.WriteLine(); - Console.WriteLine("Press Enter key to exit"); - Console.ReadLine(); - return; - } - else - { - Console.WriteLine(); - Console.WriteLine("You want to buy: " + prods[num].Name); - Console.WriteLine("Your balance is " + bal.ToString("C")); - - // Prompt for user input - Console.WriteLine("Enter amount to purchase:"); - answer = Console.ReadLine(); - int qty = Convert.ToInt32(answer); - - // Check if balance - quantity * price is less than 0 - if (bal - prods[num].Price * qty < 0) - { - Console.Clear(); - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine(); - Console.WriteLine("You do not have enough money to buy that."); - Console.ResetColor(); - continue; - } - - // Check if quantity is less than quantity - if (prods[num].Qty <= qty) - { - Console.Clear(); - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine(); - Console.WriteLine("Sorry, " + prods[num].Name + " is out of stock"); - Console.ResetColor(); - continue; - } + ui.displayErrors("Sorry, " + selectedProduct.Name + " is out of stock"); + continue; + } - // Check if quantity is greater than zero - if (qty > 0) - { - // Balance = Balance - Price * Quantity - bal = bal - prods[num].Price * qty; + if (quantityToPurchase > 0) + { + // Balance = Balance - Price * Quantity + loggedInUser.Balance = loggedInUser.Balance - selectedProduct.Price * quantityToPurchase; - // Quanity = Quantity - Quantity - prods[num].Qty = prods[num].Qty - qty; + // Quanity = Quantity - Quantity + selectedProduct.Quantity = selectedProduct.Quantity - quantityToPurchase; - Console.Clear(); - Console.ForegroundColor = ConsoleColor.Green; - Console.WriteLine("You bought " + qty + " " + prods[num].Name); - Console.WriteLine("Your new balance is " + bal.ToString("C")); - Console.ResetColor(); - } - else - { - // Quantity is less than zero - Console.Clear(); - Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine(); - Console.WriteLine("Purchase cancelled"); - Console.ResetColor(); - } - } - } + ui.displayNotices("You bought " + quantityToPurchase + " " + selectedProduct.Name, "Your new balance is " + loggedInUser.Balance.ToString("C")); } else { - // Invalid Password - Console.Clear(); - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine(); - Console.WriteLine("You entered an invalid password."); - Console.ResetColor(); - - goto Login; + ui.displayWarnings("Purchase cancelled"); } } - else - { - // Invalid User - Console.Clear(); - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine(); - Console.WriteLine("You entered an invalid user."); - Console.ResetColor(); - - goto Login; - } } - - // Prevent console from closing - Console.WriteLine(); - Console.WriteLine("Press Enter key to exit"); - Console.ReadLine(); } } } diff --git a/Refactoring/User.cs b/Refactoring/User.cs index fdc34e8..0192ed1 100644 --- a/Refactoring/User.cs +++ b/Refactoring/User.cs @@ -13,8 +13,8 @@ public class User [JsonProperty("Username")] public string Name; [JsonProperty("Password")] - public string Pwd; + public string Password; [JsonProperty("Balance")] - public double Bal; + public double Balance; } } diff --git a/Refactoring/UserInterface.cs b/Refactoring/UserInterface.cs new file mode 100644 index 0000000..2ce8165 --- /dev/null +++ b/Refactoring/UserInterface.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Refactoring +{ + public interface UserInterface + { + void displayBanner(string bannerText); + string getStringInputFromUser(string labelText); + void promptUserToExit(); + void displayErrors(params string[] errorText); + void displayWarnings(params string[] warningText); + void displayNotices(params string[] noticeText); + } +} diff --git a/UnitTestProject/FakeUserInterface.cs b/UnitTestProject/FakeUserInterface.cs new file mode 100644 index 0000000..95ba696 --- /dev/null +++ b/UnitTestProject/FakeUserInterface.cs @@ -0,0 +1,54 @@ +using Refactoring; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace UnitTestProject +{ + public class FakeUserInterface : UserInterface + { + private List stringInputLabels = new List(); + private Queue stringResponses = new Queue(); + private string errorText; + + public void displayBanner(string bannerText) + { + } + + public string getStringInputFromUser(string labelText) + { + stringInputLabels.Add(labelText); + return stringResponses.Any() ? stringResponses.Dequeue() : null; + } + + public void promptUserToExit() + { + } + + public ICollection getStringInputLabels() + { + return stringInputLabels; + } + + public void queueStringResponse(string response) + { + stringResponses.Enqueue(response); + } + + public void displayErrors(params string[] errorText) + { + this.errorText = errorText[0]; + } + + public void displayWarnings(params string[] warningText) { } + + public void displayNotices(params string[] noticeText) { } + + public string getErrorText() + { + return errorText; + } + } +} diff --git a/UnitTestProject/TestConsoleUserInterface.cs b/UnitTestProject/TestConsoleUserInterface.cs new file mode 100644 index 0000000..9b33125 --- /dev/null +++ b/UnitTestProject/TestConsoleUserInterface.cs @@ -0,0 +1,130 @@ +using NUnit.Framework; +using Refactoring; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace UnitTestProject +{ + [TestFixture] + public class TestConsoleUserInterface + { + [Test] + public void testPrintBannerSendsBannerText() + { + using (var writer = new StringWriter()) + { + Console.SetOut(writer); + UserInterface ui = new ConsoleUserInterface(); + ui.displayBanner("This is my banner!"); + Assert.IsTrue(writer.ToString().Contains("This is my banner!")); + } + } + + [Test] + public void testPrintBannerSendsUnderline() + { + using (var writer = new StringWriter()) + { + Console.SetOut(writer); + UserInterface ui = new ConsoleUserInterface(); + ui.displayBanner("This is my banner!"); + Assert.IsTrue(writer.ToString().Contains("------------------")); + } + } + + [Test] + public void testGetStringInputFromUserSendsLabelText() + { + using (var writer = new StringWriter()) + { + Console.SetOut(writer); + + using (var reader = new StringReader("Test" + Environment.NewLine)) + { + Console.SetIn(reader); + UserInterface ui = new ConsoleUserInterface(); + string userInput = ui.getStringInputFromUser("This is my label: "); + Assert.IsTrue(writer.ToString().Contains("This is my label: ")); + } + } + } + + [Test] + public void testGetStringInputFromUserReturnsTheUserInput() + { + using (var writer = new StringWriter()) + { + Console.SetOut(writer); + + using (var reader = new StringReader("Test" + Environment.NewLine)) + { + Console.SetIn(reader); + UserInterface ui = new ConsoleUserInterface(); + string userInput = ui.getStringInputFromUser("This is my label: "); + Assert.AreEqual("Test", userInput); + } + } + } + + [Test] + public void testPromptUserToExitIncludesText() + { + using (var writer = new StringWriter()) + { + Console.SetOut(writer); + + using (var reader = new StringReader(Environment.NewLine)) + { + Console.SetIn(reader); + UserInterface ui = new ConsoleUserInterface(); + ui.promptUserToExit(); + Assert.IsTrue(writer.ToString().Contains(Environment.NewLine + "Press Enter key to exit")); + } + } + } + + // RFUTODO: It would be nice to test that the colour gets set and reset as part of the error/warning/notice calls, too + // RFUTODO: We should also demonstrate that multi-string messages work + + [Test] + public void testDisplayErrorIncludesText() + { + using (var writer = new StringWriter()) + { + Console.SetOut(writer); + UserInterface ui = new ConsoleUserInterface(); + ui.displayErrors("ERRORERROR"); + Assert.IsTrue(writer.ToString().Contains("ERRORERROR")); + } + } + + [Test] + public void testDisplayWarningIncludesText() + { + using (var writer = new StringWriter()) + { + Console.SetOut(writer); + UserInterface ui = new ConsoleUserInterface(); + ui.displayWarnings("WARNINGWARNING"); + Assert.IsTrue(writer.ToString().Contains("WARNINGWARNING")); + } + } + + [Test] + public void testDisplayNoticeIncludesText() + { + using (var writer = new StringWriter()) + { + Console.SetOut(writer); + UserInterface ui = new ConsoleUserInterface(); + ui.displayNotices("NOTICENOTICE"); + Assert.IsTrue(writer.ToString().Contains("NOTICENOTICE")); + } + } + + } +} diff --git a/UnitTestProject/TestLoginManager.cs b/UnitTestProject/TestLoginManager.cs new file mode 100644 index 0000000..19d6d52 --- /dev/null +++ b/UnitTestProject/TestLoginManager.cs @@ -0,0 +1,173 @@ +using NUnit.Framework; +using Refactoring; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace UnitTestProject +{ + [TestFixture] + public class TestLoginManager + { + List sampleUsers; + FakeUserInterface ui; + + [SetUp] + public void setUp() + { + sampleUsers = new List(); + sampleUsers.Add(new User {Name = "Al", Balance = 1.0, Password = "lA"}); + sampleUsers.Add(new User {Name = "Beth", Balance = 2.0, Password = "hteB"}); + sampleUsers.Add(new User {Name = "Carl", Balance = 3.0, Password = "lraC"}); + sampleUsers.Add(new User {Name = "Dana", Balance = 4.0, Password = "anaD"}); + sampleUsers.Add(new User {Name = "Ed", Balance = 5.0, Password = "dE"}); + sampleUsers.Add(new User {Name = "Fara", Balance = 6.0, Password = "araF"}); + sampleUsers.Add(new User {Name = "Carl", Balance = 3.0, Password = "IAmAlsoCarl"}); + sampleUsers.Add(new User { Name = "Beth", Balance = 2.0, Password = "hteB" }); + + ui = new FakeUserInterface(); + } + + [Test] + [ExpectedException("System.ArgumentException")] + public void testCannotBeCreatedWithoutUserList() + { + LoginManager loginManager = new LoginManager(null, ui); + } + + [Test] + [ExpectedException("System.ArgumentException")] + public void testCannotBeCreatedWithoutUi() + { + LoginManager loginManager = new LoginManager(sampleUsers, null); + } + + [Test] + public void testLoginAsksForAUserName() + { + LoginManager loginManager = new LoginManager(sampleUsers, ui); + ui.queueStringResponse(null); + loginManager.login(); + Assert.That(ui.getStringInputLabels(), Contains.Item(Environment.NewLine + "Enter Username:")); + } + + [Test] + public void testIfUserProvidesNullUserNameReturnNull() + { + LoginManager loginmanager = new LoginManager(sampleUsers, ui); + ui.queueStringResponse(null); + User user = loginmanager.login(); + Assert.Null(user); + } + + [Test] + public void testIfUserProvidesBlankUserNameReturnNull() + { + LoginManager loginmanager = new LoginManager(sampleUsers, ui); + ui.queueStringResponse(""); + User user = loginmanager.login(); + Assert.Null(user); + } + + [Test] + public void testIfUserProvidesBadUserNameTheyGetAnError() + { + LoginManager loginmanager = new LoginManager(sampleUsers, ui); + ui.queueStringResponse("NotARealUserName"); + User user = loginmanager.login(); + Assert.AreEqual("You entered an invalid user.", ui.getErrorText()); + } + + [Test] + public void testIfUserProvidesBadUserNameTheyAreAskedAgain() + { + LoginManager loginManager = new LoginManager(sampleUsers, ui); + ui.queueStringResponse("NotARealUserName"); + loginManager.login(); + ICollection inputLabels = ui.getStringInputLabels(); + Assert.AreEqual(2, inputLabels.Count); + foreach (string inputLabel in inputLabels) + Assert.AreEqual(Environment.NewLine + "Enter Username:", inputLabel); + } + + [Test] + public void testIfUserProvidesGoodUserNameTheyAreAskedForAPassword() + { + LoginManager loginManager = new LoginManager(sampleUsers, ui); + ui.queueStringResponse("Al"); + loginManager.login(); + Assert.That(ui.getStringInputLabels(), Contains.Item("Enter Password:")); + } + + [Test] + public void testIfUserProvidesGoodUserNameAndBadPasswordTheyGetAnError() + { + LoginManager loginManager = new LoginManager(sampleUsers, ui); + ui.queueStringResponse("Al"); + ui.queueStringResponse("FakePassword"); + loginManager.login(); + Assert.AreEqual("You entered an invalid password.", ui.getErrorText()); + } + + [Test] + public void testIfUserProvidesBadUserNameTheyAreAskedToLoginAgain() + { + LoginManager loginManager = new LoginManager(sampleUsers, ui); + ui.queueStringResponse("Al"); + ui.queueStringResponse("FakePassword"); + loginManager.login(); + ICollection inputLabels = ui.getStringInputLabels(); + Assert.AreEqual(3, inputLabels.Count); + Assert.AreEqual(Environment.NewLine + "Enter Username:", inputLabels.ElementAt(0)); + Assert.AreEqual("Enter Password:", inputLabels.ElementAt(1)); + Assert.AreEqual(Environment.NewLine + "Enter Username:", inputLabels.ElementAt(2)); + } + + [Test] + public void testIfUserProvidesGoodUserNameAndPasswordTheyGetThatUserBack() + { + LoginManager loginManager = new LoginManager(sampleUsers, ui); + ui.queueStringResponse("Carl"); + ui.queueStringResponse("lraC"); + User user = loginManager.login(); + Assert.AreSame(sampleUsers[2], user); + } + + [Test] + public void testBugfixCanLoginAsTheSixthUser() + { + LoginManager loginManager = new LoginManager(sampleUsers, ui); + ui.queueStringResponse("Fara"); + ui.queueStringResponse("araF"); + User user = loginManager.login(); + Assert.AreSame(sampleUsers[5], user); + } + + [Test] + public void testCanLoginAsTwoDifferentUsersWithSameNameButDifferentPassword() + { + LoginManager loginManager = new LoginManager(sampleUsers, ui); + ui.queueStringResponse("Carl"); + ui.queueStringResponse("lraC"); + User user = loginManager.login(); + Assert.AreSame(sampleUsers[2], user); + + ui.queueStringResponse("Carl"); + ui.queueStringResponse("IAmAlsoCarl"); + user = loginManager.login(); + Assert.AreSame(sampleUsers[6], user); + } + + [Test] + public void testBugfixIfTwoUsersHaveTheSameNameAndPasswordTheFirstOneIsRetrieved() + { + LoginManager loginManager = new LoginManager(sampleUsers, ui); + ui.queueStringResponse("Beth"); + ui.queueStringResponse("hteB"); + User user = loginManager.login(); + Assert.AreSame(sampleUsers[1], user); + } + } +} diff --git a/UnitTestProject/TestStore.cs b/UnitTestProject/TestStore.cs new file mode 100644 index 0000000..530dfdd --- /dev/null +++ b/UnitTestProject/TestStore.cs @@ -0,0 +1,48 @@ +using NUnit.Framework; +using Refactoring; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace UnitTestProject +{ + [TestFixture] + public class TestStore + { + List sampleProducts; + FakeUserInterface ui; + + [SetUp] + public void setUp() + { + sampleProducts = new List(); + sampleProducts.Add(new Product { Name = "Apple", Price = 1.0, Quantity = 1 }); + sampleProducts.Add(new Product { Name = "Banana", Price = 2.0, Quantity = 2 }); + sampleProducts.Add(new Product { Name = "Cookies", Price = 3.0, Quantity = 3 }); + sampleProducts.Add(new Product { Name = "Donut", Price = 4.0, Quantity = 4 }); + sampleProducts.Add(new Product { Name = "Eclair", Price = 5.0, Quantity = 5 }); + sampleProducts.Add(new Product { Name = "Frozen Yogurt", Price = 6.0, Quantity = 6 }); + sampleProducts.Add(new Product { Name = "Gelato", Price = 7.0, Quantity = 7 }); + sampleProducts.Add(new Product { Name = "Ham", Price = 8.0, Quantity = 8 }); + sampleProducts.Add(new Product { Name = "Icing", Price = 9.0, Quantity = 9 }); + + ui = new FakeUserInterface(); + } + + [Test] + [ExpectedException("System.ArgumentException")] + public void testCannotBeCreatedWithoutProductList() + { + Store store = new Store(null, ui); + } + + [Test] + [ExpectedException("System.ArgumentException")] + public void testCannotBeCreatedWithoutUi() + { + Store store = new Store(sampleProducts, null); + } + } +} diff --git a/UnitTestProject/UnitTestProject.csproj b/UnitTestProject/UnitTestProject.csproj index d2245a3..b7ec381 100644 --- a/UnitTestProject/UnitTestProject.csproj +++ b/UnitTestProject/UnitTestProject.csproj @@ -16,6 +16,8 @@ $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages False UnitTest + ..\ + true true @@ -34,28 +36,46 @@ prompt 4 + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + prompt + MinimumRecommendedRules.ruleset + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + + False ..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll - True - + ..\packages\NUnitTestAdapter.WithFramework.2.0.0\lib\nunit.core.dll False - + ..\packages\NUnitTestAdapter.WithFramework.2.0.0\lib\nunit.core.interfaces.dll False + False ..\packages\NUnitTestAdapter.WithFramework.2.0.0\lib\nunit.framework.dll - True - + ..\packages\NUnitTestAdapter.WithFramework.2.0.0\lib\nunit.util.dll False - + ..\packages\NUnitTestAdapter.WithFramework.2.0.0\lib\NUnit.VisualStudio.TestAdapter.dll False @@ -70,6 +90,10 @@ + + + + @@ -80,9 +104,7 @@ - - Designer - + diff --git a/UnitTestProject/UnitTests.cs b/UnitTestProject/UnitTests.cs index 51a30ad..c3fbc1f 100644 --- a/UnitTestProject/UnitTests.cs +++ b/UnitTestProject/UnitTests.cs @@ -13,34 +13,16 @@ namespace UnitTestProject public class UnitTests { private List users; - private List originalUsers; private List products; - private List originalProducts; + private UserInterface ui; [SetUp] public void Test_Initialize() { - // Load users from data file - originalUsers = JsonConvert.DeserializeObject>(File.ReadAllText(@"Data/Users.json")); - users = DeepCopy>(originalUsers); + users = JsonConvert.DeserializeObject>(File.ReadAllText(@"Data/Users.json")); + products = JsonConvert.DeserializeObject>(File.ReadAllText(@"Data/Products.json")); - // Load products from data file - originalProducts = JsonConvert.DeserializeObject>(File.ReadAllText(@"Data/Products.json")); - products = DeepCopy>(originalProducts); - } - - [TearDown] - public void Test_Cleanup() - { - // Restore users - string json = JsonConvert.SerializeObject(originalUsers, Formatting.Indented); - File.WriteAllText(@"Data/Users.json", json); - users = DeepCopy>(originalUsers); - - // Restore products - string json2 = JsonConvert.SerializeObject(originalProducts, Formatting.Indented); - File.WriteAllText(@"Data/Products.json", json2); - products = DeepCopy>(originalProducts); + ui = new ConsoleUserInterface(); } [Test] @@ -70,7 +52,7 @@ public void Test_TuscDoesNotThrowAnException() { Console.SetIn(reader); - Tusc.Start(users, products); + Tusc.Start(users, products, ui); } } } @@ -86,7 +68,7 @@ public void Test_InvalidUserIsNotAccepted() { Console.SetIn(reader); - Tusc.Start(users, products); + Tusc.Start(users, products, ui); } Assert.IsTrue(writer.ToString().Contains("You entered an invalid user")); @@ -104,7 +86,7 @@ public void Test_EmptyUserDoesNotThrowAnException() { Console.SetIn(reader); - Tusc.Start(users, products); + Tusc.Start(users, products, ui); } } } @@ -120,7 +102,7 @@ public void Test_InvalidPasswordIsNotAccepted() { Console.SetIn(reader); - Tusc.Start(users, products); + Tusc.Start(users, products, ui); } Assert.IsTrue(writer.ToString().Contains("You entered an invalid password")); @@ -138,7 +120,7 @@ public void Test_UserCanCancelPurchase() { Console.SetIn(reader); - Tusc.Start(users, products); + Tusc.Start(users, products, ui); } Assert.IsTrue(writer.ToString().Contains("Purchase cancelled")); @@ -150,8 +132,7 @@ public void Test_UserCanCancelPurchase() public void Test_ErrorOccursWhenBalanceLessThanPrice() { // Update data file - List tempUsers = DeepCopy>(originalUsers); - tempUsers.Where(u => u.Name == "Jason").Single().Bal = 0.0; + users.Where(u => u.Name == "Jason").Single().Balance = 0.0; using (var writer = new StringWriter()) { @@ -161,7 +142,7 @@ public void Test_ErrorOccursWhenBalanceLessThanPrice() { Console.SetIn(reader); - Tusc.Start(tempUsers, products); + Tusc.Start(users, products, ui); } Assert.IsTrue(writer.ToString().Contains("You do not have enough money to buy that")); @@ -172,8 +153,7 @@ public void Test_ErrorOccursWhenBalanceLessThanPrice() public void Test_ErrorOccursWhenProductOutOfStock() { // Update data file - List tempProducts = DeepCopy>(originalProducts); - tempProducts.Where(u => u.Name == "Chips").Single().Qty = 0; + products.Where(u => u.Name == "Chips").Single().Quantity = 0; using (var writer = new StringWriter()) { @@ -183,23 +163,11 @@ public void Test_ErrorOccursWhenProductOutOfStock() { Console.SetIn(reader); - Tusc.Start(users, tempProducts); + Tusc.Start(users, products, ui); } Assert.IsTrue(writer.ToString().Contains("is out of stock")); } } - - private static T DeepCopy(T obj) - { - using (MemoryStream stream = new MemoryStream()) - { - BinaryFormatter formatter = new BinaryFormatter(); - formatter.Serialize(stream, obj); - stream.Position = 0; - - return (T)formatter.Deserialize(stream); - } - } } }