diff --git a/.gitignore b/.gitignore
index 4d9e991..26b926c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
local.appsettings.config
# User-specific files
+.idea/
*.suo
*.user
*.userosscache
diff --git a/Order.Management.Test/Approvals/ProgramTest.TestMainOutputs.approved.txt b/Order.Management.Test/Approvals/ProgramTest.TestMainOutputs.approved.txt
new file mode 100644
index 0000000..535bf93
--- /dev/null
+++ b/Order.Management.Test/Approvals/ProgramTest.TestMainOutputs.approved.txt
@@ -0,0 +1,41 @@
+Please input your Name: Please input your Address: Please input your Due Date:
+Please input the number of Red Squares: Please input the number of Blue Squares: Please input the number of Yellow Squares:
+Please input the number of Red Triangles: Please input the number of Blue Triangles: Please input the number of Yellow Triangles:
+Please input the number of Red Circle: Please input the number of Blue Circle: Please input the number of Yellow Circle:
+Your invoice report has been generated:
+
+Name: David Wei Address: 26A Croydon Street, Sydenham, Christchurch 8024 Due Date: 29-09-2021 Order #: 0
+-------------------------------------------------------------------------
+| | Red | Blue | Yellow |
+-------------------------------------------------------------------------
+| Square | 1 | 2 | 3 |
+| Triangle | 4 | 7 | 2 |
+| Circle | 5 | 8 | 1 |
+-------------------------------------------------------------------------
+
+Squares 6 @ $1 ppi = $6
+Triangles 13 @ $2 ppi = $26
+Circles 14 @ $3 ppi = $42
+Red Color Surcharge 10 @ $1 ppi = $10
+
+Your cutting list has been generated:
+
+Name: David Wei Address: 26A Croydon Street, Sydenham, Christchurch 8024 Due Date: 29-09-2021 Order #: 0
+--------------------
+| | Qty |
+--------------------
+| Square | 6 |
+|Triangle | 13 |
+| Circle | 14 |
+--------------------
+
+Your painting report has been generated:
+
+Name: David Wei Address: 26A Croydon Street, Sydenham, Christchurch 8024 Due Date: 29-09-2021 Order #: 0
+-------------------------------------------------------------------------
+| | Red | Blue | Yellow |
+-------------------------------------------------------------------------
+| Square | 1 | 2 | 3 |
+| Triangle | 4 | 7 | 2 |
+| Circle | 5 | 8 | 1 |
+-------------------------------------------------------------------------
diff --git a/Order.Management.Test/Approvals/input.txt b/Order.Management.Test/Approvals/input.txt
new file mode 100644
index 0000000..95b6feb
--- /dev/null
+++ b/Order.Management.Test/Approvals/input.txt
@@ -0,0 +1,12 @@
+David Wei
+26A Croydon Street, Sydenham, Christchurch 8024
+29-09-2021
+1
+2
+3
+4
+7
+2
+5
+8
+1
\ No newline at end of file
diff --git a/Order.Management.Test/Order.Management.Test.csproj b/Order.Management.Test/Order.Management.Test.csproj
new file mode 100644
index 0000000..9ab0d69
--- /dev/null
+++ b/Order.Management.Test/Order.Management.Test.csproj
@@ -0,0 +1,31 @@
+
+
+
+ netcoreapp3.1
+
+ false
+
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+ Always
+
+
+
+
+
+
+
diff --git a/Order.Management.Test/ProgramTest.cs b/Order.Management.Test/ProgramTest.cs
new file mode 100644
index 0000000..bb1112a
--- /dev/null
+++ b/Order.Management.Test/ProgramTest.cs
@@ -0,0 +1,30 @@
+using System;
+using System.IO;
+using System.Reflection;
+using ApprovalTests;
+using ApprovalTests.Namers;
+using ApprovalTests.Reporters;
+using Xunit;
+
+namespace Order.Management.Test
+{
+ [UseReporter(typeof(DiffReporter))]
+ [UseApprovalSubdirectory("Approvals")]
+ public class ProgramTest
+ {
+ [Fact]
+ public void TestMainOutputs()
+ {
+ using var fakeStdout = new StringWriter();
+ Console.SetOut(fakeStdout);
+
+ var currentDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
+ using var inputNames = new StreamReader($@"{currentDir}/Approvals/input.txt");
+ // Tell console to get its input from the file, not from the keyboard
+ Console.SetIn(inputNames);
+
+ Program.Main(new string[] { });
+ Approvals.Verify(fakeStdout.ToString());
+ }
+ }
+}
\ No newline at end of file
diff --git a/Order.Management.sln b/Order.Management.sln
index 400236d..f34bcd4 100644
--- a/Order.Management.sln
+++ b/Order.Management.sln
@@ -5,6 +5,8 @@ VisualStudioVersion = 16.0.29519.87
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Order.Management", "Order.Management\Order.Management.csproj", "{1DAC7794-3F0E-4083-95A9-2E6FF9512C0C}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Order.Management.Test", "Order.Management.Test\Order.Management.Test.csproj", "{AEA22CA0-3BCB-4793-994C-F81440CD8C99}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -15,6 +17,10 @@ Global
{1DAC7794-3F0E-4083-95A9-2E6FF9512C0C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1DAC7794-3F0E-4083-95A9-2E6FF9512C0C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1DAC7794-3F0E-4083-95A9-2E6FF9512C0C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AEA22CA0-3BCB-4793-994C-F81440CD8C99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AEA22CA0-3BCB-4793-994C-F81440CD8C99}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AEA22CA0-3BCB-4793-994C-F81440CD8C99}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AEA22CA0-3BCB-4793-994C-F81440CD8C99}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Order.Management/Circle.cs b/Order.Management/Circle.cs
index 9824ecc..9d164a9 100644
--- a/Order.Management/Circle.cs
+++ b/Order.Management/Circle.cs
@@ -1,4 +1,5 @@
-using System;
+// 0. Remove no longer required code conveniently could make code cleaner
+using System;
using System.Collections.Generic;
using System.Text;
@@ -6,25 +7,31 @@ namespace Order.Management
{
class Circle : Shape
{
+ // 1. magic number
public int circlePrice = 3;
public Circle(int red, int blue, int yellow)
{
+ // 2. hard-coded string
Name = "Circle";
base.Price = circlePrice;
AdditionalCharge = 1;
+ // 3. we could use a better way: 'base(red, blue, yellow)' assigning values to the fields that defined in base class
base.NumberOfRedShape = red;
base.NumberOfBlueShape = blue;
base.NumberOfYellowShape = yellow;
}
+ // 4. bad method name: you cannot know the exact meaning of `total`, a better name could be PriceTotal
public override int Total()
{
return RedCirclesTotal() + BlueCirclesTotal() + YellowCirclesTotal();
}
+ // 5. if I were the author, I would like use properties for the following methods
public int RedCirclesTotal()
{
return (base.NumberOfRedShape * Price);
}
+
public int BlueCirclesTotal()
{
return (base.NumberOfBlueShape * Price);
diff --git a/Order.Management/CuttingListReport.cs b/Order.Management/CuttingListReport.cs
index 125d45f..aecaf0e 100644
--- a/Order.Management/CuttingListReport.cs
+++ b/Order.Management/CuttingListReport.cs
@@ -6,9 +6,12 @@ namespace Order.Management
{
class CuttingListReport : Order
{
+ // 1. Inconsistent name convention: it should change to TableWidth
+ // 2. This property could be readonly.
public int tableWidth = 20;
public CuttingListReport(string customerName, string customerAddress, string dueDate, List shapes)
{
+ // use base(parameters) instead of the `base.FieldName` way
base.CustomerName = customerName;
base.Address = customerAddress;
base.DueDate = dueDate;
@@ -21,6 +24,7 @@ public override void GenerateReport()
Console.WriteLine(base.ToString());
generateTable();
}
+ // 1. Inconsistent name convention: it should change to GenerateTable
public void generateTable()
{
PrintLine();
@@ -31,11 +35,13 @@ public void generateTable()
PrintRow("Circle", base.OrderedBlocks[2].TotalQuantityOfShape().ToString());
PrintLine();
}
+ // 3. If a method could be private, make it private
public void PrintLine()
{
Console.WriteLine(new string('-', tableWidth));
}
+ // 3. If a method could be private, make it private
public void PrintRow(params string[] columns)
{
int width = (tableWidth - columns.Length) / columns.Length;
@@ -49,10 +55,12 @@ public void PrintRow(params string[] columns)
Console.WriteLine(row);
}
+ // 3. If a method could be private, make it private
public string AlignCentre(string text, int width)
{
text = text.Length > width ? text.Substring(0, width - 3) + "..." : text;
+ // 4. this check should be the very first check
if (string.IsNullOrEmpty(text))
{
return new string(' ', width);
@@ -62,7 +70,5 @@ public string AlignCentre(string text, int width)
return text.PadRight(width - (width - text.Length) / 2).PadLeft(width);
}
}
-
-
}
}
diff --git a/Order.Management/InvoiceReport.cs b/Order.Management/InvoiceReport.cs
index 78443c3..349a1fc 100644
--- a/Order.Management/InvoiceReport.cs
+++ b/Order.Management/InvoiceReport.cs
@@ -68,6 +68,7 @@ public void PrintLine()
Console.WriteLine(new string('-', tableWidth));
}
+ // Duplicate Code, should move to a base Report Class
public void PrintRow(params string[] columns)
{
int width = (tableWidth - columns.Length) / columns.Length;
@@ -81,8 +82,10 @@ public void PrintRow(params string[] columns)
Console.WriteLine(row);
}
+ // Duplicate code
public string AlignCentre(string text, int width)
{
+ // Should extract into a getTrimmedText method
text = text.Length > width ? text.Substring(0, width - 3) + "..." : text;
if (string.IsNullOrEmpty(text))
diff --git a/Order.Management/Order.cs b/Order.Management/Order.cs
index 235c789..9d72b18 100644
--- a/Order.Management/Order.cs
+++ b/Order.Management/Order.cs
@@ -6,6 +6,7 @@ namespace Order.Management
{
abstract class Order
{
+ // 1. the following two fields could save into a Customer class
public string CustomerName { get; set; }
public string Address { get; set; }
public string DueDate { get; set; }
diff --git a/Order.Management/PaintingReport.cs b/Order.Management/PaintingReport.cs
index 9b61c83..da65b5b 100644
--- a/Order.Management/PaintingReport.cs
+++ b/Order.Management/PaintingReport.cs
@@ -4,6 +4,7 @@
namespace Order.Management
{
+ // 1. Reports should have its own base class instead of inheriting from Order though they have some common information
class PaintingReport : Order
{
public int tableWidth = 73;
@@ -26,12 +27,13 @@ public void generateTable()
PrintLine();
PrintRow(" ", " Red ", " Blue ", " Yellow ");
PrintLine();
+ // 2. Please don't use [index] way unless you have no other choice
PrintRow("Square", base.OrderedBlocks[0].NumberOfRedShape.ToString(), base.OrderedBlocks[0].NumberOfBlueShape.ToString(), base.OrderedBlocks[0].NumberOfYellowShape.ToString());
PrintRow("Triangle", base.OrderedBlocks[1].NumberOfRedShape.ToString(), base.OrderedBlocks[1].NumberOfBlueShape.ToString(), base.OrderedBlocks[1].NumberOfYellowShape.ToString());
PrintRow("Circle", base.OrderedBlocks[2].NumberOfRedShape.ToString(), base.OrderedBlocks[2].NumberOfBlueShape.ToString(), base.OrderedBlocks[2].NumberOfYellowShape.ToString());
PrintLine();
}
-
+
public void PrintLine()
{
Console.WriteLine(new string('-', tableWidth));
diff --git a/Order.Management/Program.cs b/Order.Management/Program.cs
index 1422f85..d996c06 100644
--- a/Order.Management/Program.cs
+++ b/Order.Management/Program.cs
@@ -3,10 +3,11 @@
namespace Order.Management
{
- class Program
+
+ public static class Program
{
// Main entry
- static void Main(string[] args)
+ public static void Main(string[] args)
{
var (customerName, address, dueDate) = CustomerInfoInput();
@@ -18,9 +19,9 @@ static void Main(string[] args)
PaintingReport(customerName, address, dueDate, orderedShapes);
}
-
+
// Order Circle Input
- public static Circle OrderCirclesInput()
+ private static Circle OrderCirclesInput()
{
Console.Write("\nPlease input the number of Red Circle: ");
int redCircle = Convert.ToInt32(userInput());
@@ -32,9 +33,9 @@ public static Circle OrderCirclesInput()
Circle circle = new Circle(redCircle, blueCircle, yellowCircle);
return circle;
}
-
+
// Order Squares Input
- public static Square OrderSquaresInput()
+ private static Square OrderSquaresInput()
{
Console.Write("\nPlease input the number of Red Squares: ");
int redSquare = Convert.ToInt32(userInput());
@@ -48,7 +49,7 @@ public static Square OrderSquaresInput()
}
// Order Triangles Input
- public static Triangle OrderTrianglesInput()
+ private static Triangle OrderTrianglesInput()
{
Console.Write("\nPlease input the number of Red Triangles: ");
int redTriangle = Convert.ToInt32(userInput());
@@ -74,21 +75,21 @@ public static string userInput()
return input;
}
- // Generate Painting Report
+ // Generate Painting Report
private static void PaintingReport(string customerName, string address, string dueDate, List orderedShapes)
{
PaintingReport paintingReport = new PaintingReport(customerName, address, dueDate, orderedShapes);
paintingReport.GenerateReport();
}
- // Generate Painting Report
+ // Generate Painting Report
private static void CuttingListReport(string customerName, string address, string dueDate, List orderedShapes)
{
CuttingListReport cuttingListReport = new CuttingListReport(customerName, address, dueDate, orderedShapes);
cuttingListReport.GenerateReport();
}
- // Generate Invoice Report
+ // Generate Invoice Report
private static void InvoiceReport(string customerName, string address, string dueDate, List orderedShapes)
{
InvoiceReport invoiceReport = new InvoiceReport(customerName, address, dueDate, orderedShapes);
diff --git a/Order.Management/Shape.cs b/Order.Management/Shape.cs
index 7f5c61c..50f9492 100644
--- a/Order.Management/Shape.cs
+++ b/Order.Management/Shape.cs
@@ -8,10 +8,12 @@ abstract class Shape
{
public string Name { get; set; }
public int Price { get; set; }
+ // 1. the following four fields are actually not attribute of a shape, it should belong to Order Information
public int AdditionalCharge { get; set; }
public int NumberOfRedShape { get; set; }
public int NumberOfBlueShape { get; set; }
public int NumberOfYellowShape { get; set; }
+ // 2. the following methods are similar to the fields above, it should move into the order class
public int TotalQuantityOfShape()
{
return NumberOfRedShape + NumberOfBlueShape + NumberOfYellowShape;
@@ -21,6 +23,7 @@ public int AdditionalChargeTotal()
{
return NumberOfRedShape * AdditionalCharge;
}
+ // 3. bad method name, PriceTotal could be a better candidate
public abstract int Total();
}