├── .gitignore
├── AcmeApp
├── Acme.Biz
│ ├── Acme.Biz.csproj
│ ├── Product.cs
│ ├── Vendor.cs
│ └── VendorRepository.cs
├── Acme.Common
│ ├── Acme.Common.csproj
│ ├── EmailService.cs
│ ├── LoggingService.cs
│ └── OperationResult.cs
├── Acme.Win
│ ├── Acme.Win.csproj
│ ├── Program.cs
│ ├── VendorWin.Designer.cs
│ ├── VendorWin.cs
│ └── VendorWin.resx
├── Acme.Wpf
│ ├── Acme.Wpf.csproj
│ ├── App.xaml
│ ├── App.xaml.cs
│ ├── AssemblyInfo.cs
│ ├── Assets
│ │ └── StyleLibrary.xaml
│ ├── MainWindow.xaml
│ ├── MainWindow.xaml.cs
│ ├── ViewModels
│ │ └── VendorDetailViewModel.cs
│ └── Views
│ │ ├── VendorDetailView.xaml
│ │ └── VendorDetailView.xaml.cs
├── AcmeApp.sln
└── Tests
│ ├── Acme.BizTests
│ ├── Acme.BizTests.csproj
│ ├── ProductTests.cs
│ ├── Usings.cs
│ └── VendorTests.cs
│ └── Acme.CommonTests
│ ├── Acme.CommonTests.csproj
│ ├── EmailServiceTests.cs
│ ├── LoggingServiceTests.cs
│ └── Usings.cs
├── LICENSE
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | build/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studo 2015 cache/options directory
26 | .vs/
27 |
28 | # MSTest test Results
29 | [Tt]est[Rr]esult*/
30 | [Bb]uild[Ll]og.*
31 |
32 | # NUNIT
33 | *.VisualState.xml
34 | TestResult.xml
35 |
36 | # Build Results of an ATL Project
37 | [Dd]ebugPS/
38 | [Rr]eleasePS/
39 | dlldata.c
40 |
41 | *_i.c
42 | *_p.c
43 | *_i.h
44 | *.ilk
45 | *.meta
46 | *.obj
47 | *.pch
48 | *.pdb
49 | *.pgc
50 | *.pgd
51 | *.rsp
52 | *.sbr
53 | *.tlb
54 | *.tli
55 | *.tlh
56 | *.tmp
57 | *.tmp_proj
58 | *.log
59 | *.vspscc
60 | *.vssscc
61 | .builds
62 | *.pidb
63 | *.svclog
64 | *.scc
65 |
66 | # Chutzpah Test files
67 | _Chutzpah*
68 |
69 | # Visual C++ cache files
70 | ipch/
71 | *.aps
72 | *.ncb
73 | *.opensdf
74 | *.sdf
75 | *.cachefile
76 |
77 | # Visual Studio profiler
78 | *.psess
79 | *.vsp
80 | *.vspx
81 |
82 | # TFS 2012 Local Workspace
83 | $tf/
84 |
85 | # Guidance Automation Toolkit
86 | *.gpState
87 |
88 | # ReSharper is a .NET coding add-in
89 | _ReSharper*/
90 | *.[Rr]e[Ss]harper
91 | *.DotSettings.user
92 |
93 | # JustCode is a .NET coding addin-in
94 | .JustCode
95 |
96 | # TeamCity is a build add-in
97 | _TeamCity*
98 |
99 | # DotCover is a Code Coverage Tool
100 | *.dotCover
101 |
102 | # NCrunch
103 | _NCrunch_*
104 | .*crunch*.local.xml
105 |
106 | # MightyMoose
107 | *.mm.*
108 | AutoTest.Net/
109 |
110 | # Web workbench (sass)
111 | .sass-cache/
112 |
113 | # Installshield output folder
114 | [Ee]xpress/
115 |
116 | # DocProject is a documentation generator add-in
117 | DocProject/buildhelp/
118 | DocProject/Help/*.HxT
119 | DocProject/Help/*.HxC
120 | DocProject/Help/*.hhc
121 | DocProject/Help/*.hhk
122 | DocProject/Help/*.hhp
123 | DocProject/Help/Html2
124 | DocProject/Help/html
125 |
126 | # Click-Once directory
127 | publish/
128 |
129 | # Publish Web Output
130 | *.[Pp]ublish.xml
131 | *.azurePubxml
132 | # TODO: Comment the next line if you want to checkin your web deploy settings
133 | # but database connection strings (with potential passwords) will be unencrypted
134 | *.pubxml
135 | *.publishproj
136 |
137 | # NuGet Packages
138 | *.nupkg
139 | # The packages folder can be ignored because of Package Restore
140 | **/packages/*
141 | # except build/, which is used as an MSBuild target.
142 | !**/packages/build/
143 | # Uncomment if necessary however generally it will be regenerated when needed
144 | #!**/packages/repositories.config
145 |
146 | # Windows Azure Build Output
147 | csx/
148 | *.build.csdef
149 |
150 | # Windows Store app package directory
151 | AppPackages/
152 |
153 | # Others
154 | *.[Cc]ache
155 | ClientBin/
156 | [Ss]tyle[Cc]op.*
157 | ~$*
158 | *~
159 | *.dbmdl
160 | *.dbproj.schemaview
161 | *.pfx
162 | *.publishsettings
163 | node_modules/
164 | bower_components/
165 |
166 | # RIA/Silverlight projects
167 | Generated_Code/
168 |
169 | # Backup & report files from converting an old project file
170 | # to a newer Visual Studio version. Backup files are not needed,
171 | # because we have git ;-)
172 | _UpgradeReport_Files/
173 | Backup*/
174 | UpgradeLog*.XML
175 | UpgradeLog*.htm
176 |
177 | # SQL Server files
178 | *.mdf
179 | *.ldf
180 |
181 | # Business Intelligence projects
182 | *.rdl.data
183 | *.bim.layout
184 | *.bim_*.settings
185 |
186 | # Microsoft Fakes
187 | FakesAssemblies/
188 |
189 | # Node.js Tools for Visual Studio
190 | .ntvs_analysis.dat
191 |
192 | # Visual Studio 6 build log
193 | *.plg
194 |
195 | # Visual Studio 6 workspace options file
196 | *.opt
197 |
--------------------------------------------------------------------------------
/AcmeApp/Acme.Biz/Acme.Biz.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/AcmeApp/Acme.Biz/Product.cs:
--------------------------------------------------------------------------------
1 | using Acme.Common;
2 | using System.Numerics;
3 |
4 | namespace Acme.Biz;
5 |
6 | ///
7 | /// Manages products carried in inventory.
8 | ///
9 | public class Product
10 | {
11 | public const double pi = 3.14;
12 | public const int red = 0xFF0000;
13 | public const double inchesPerMeter = 39.37;
14 |
15 | public readonly decimal MinimumPrice;
16 |
17 | public Product()
18 | {
19 | Category = "Tools";
20 | MinimumPrice = .96m;
21 | InventoryCount = GetInventoryCount();
22 | ProductVendor = new Vendor();
23 | }
24 |
25 | public Product(int productId,
26 | string productName,
27 | string description) : this()
28 | {
29 | ProductId = productId;
30 | ProductName = productName;
31 | Description = description;
32 |
33 | if (ProductName.StartsWith("Bulk"))
34 | {
35 | MinimumPrice = 9.99m;
36 | }
37 | Console.WriteLine("Product instance has a name: " + ProductName);
38 | }
39 |
40 | #region Properties
41 | public decimal Cost { get; set; }
42 | internal string Category { get; set; }
43 | public int SequenceNumber { get; } = 1;
44 |
45 | public Vendor? CurrentVendor { get; set; }
46 |
47 | public int InventoryCount { get; }
48 |
49 | private static int GetInventoryCount()
50 | {
51 | return 25;
52 | }
53 |
54 | private string description = "";
55 |
56 | public string Description
57 | {
58 | get { return description; }
59 | set { description = value; }
60 | }
61 |
62 | private int productId;
63 |
64 | public int ProductId
65 | {
66 | get { return productId; }
67 | set { productId = value; }
68 | }
69 |
70 | private string productName = "";
71 | public string ProductName
72 | {
73 | get
74 | {
75 | var formattedValue = productName.Trim();
76 | return formattedValue;
77 | }
78 | set
79 | {
80 | if (value.Length < 3)
81 | {
82 | ValidationMessage = "Product Name must be at least 3 characters";
83 | }
84 | else if (value.Length > 20)
85 | {
86 | ValidationMessage = "Product Name cannot be more than 20 characters";
87 |
88 | }
89 | else
90 | {
91 | productName = value;
92 | }
93 | }
94 | }
95 |
96 | public Vendor ProductVendor { get; set; } = new Vendor();
97 |
98 | public string? ValidationMessage { get; private set; }
99 |
100 | #endregion
101 |
102 | ///
103 | /// Calculates the suggested retail price
104 | ///
105 | /// Percent used to mark up the cost.
106 | ///
107 | //public decimal CalculateSuggestedPrice(decimal markupPercent)
108 | //{
109 | // return this.Cost + (this.Cost * markupPercent / 100);
110 | //}
111 |
112 | public decimal CalculateSuggestedPrice(decimal markupPercent) =>
113 | this.Cost + (this.Cost * markupPercent / 100);
114 |
115 | public string SayHello()
116 | {
117 | var emailGreeting = $"Hello {ProductName} ({ProductId}): {Description}";
118 | LoggingService.LogAction(emailGreeting);
119 |
120 | return emailGreeting;
121 | }
122 |
123 | public string? LastName { get; set; }
124 | public string? FirstName { get; set; }
125 | public string? FullName => FirstName + " " + LastName;
126 |
127 | //public string FullName
128 | //{
129 | // get { return FirstName + " " + LastName; }
130 | //}
131 |
132 |
133 | public int Quantity { get; set; }
134 | public int Price { get; set; }
135 | public int ItemTotal => Quantity * Price;
136 |
137 | //public int ItemTotal
138 | //{
139 | // get { return Quantity * Price; }
140 | //}
141 |
142 |
143 |
144 | public string? VendorName => ProductVendor?.CompanyName;
145 |
146 | //public string VendorName
147 | //{
148 | // get { return ProductVendor?.CompanyName; }
149 | //}
150 |
151 | public override string ToString()
152 | {
153 | return this.ProductName + " (" + this.productId + ")";
154 | }
155 | }
--------------------------------------------------------------------------------
/AcmeApp/Acme.Biz/Vendor.cs:
--------------------------------------------------------------------------------
1 | using Acme.Common;
2 |
3 | namespace Acme.Biz;
4 |
5 | public class Vendor
6 | {
7 | public int VendorId { get; set; }
8 | public string? CompanyName { get; set; }
9 | public string? Email { get; set; }
10 |
11 | // Return a default vendor
12 | public Vendor() : this(1, "Acme Supply", "acmeSupply@gmail.com")
13 | { }
14 |
15 |
16 | public Vendor(int vendorId, string companyName, string email)
17 | {
18 | VendorId = vendorId;
19 | CompanyName = companyName;
20 | Email = email;
21 | }
22 |
23 | ///
24 | /// Sample method.
25 | ///
26 | ///
27 | public string SayHello()
28 | {
29 | return ($"Hello {this.CompanyName}").Trim();
30 | }
31 |
32 | /////
33 | ///// Sends a product order to the vendor.
34 | /////
35 | ///// Product to order.
36 | ///// Quantity of the product to order
37 | /////
38 | //public OperationResult PlaceOrder(Product product, int quantity)
39 | //{
40 | // return PlaceOrder(product, quantity, null, null);
41 | //}
42 |
43 | /////
44 | ///// Sends a product order to the vendor.
45 | /////
46 | ///// Product to order.
47 | ///// Quantity of the product to order
48 | ///// Requested delivery by date
49 | /////
50 | //public OperationResult PlaceOrder(Product product, int quantity, DateTimeOffset? deliverBy)
51 | //{
52 | // return PlaceOrder(product, quantity, deliverBy, null);
53 | //}
54 |
55 | ///
56 | /// Sends a product order to the vendor.
57 | ///
58 | /// Product to order.
59 | /// Quantity of the product to order
60 | /// Requested delivery by date
61 | /// Delivery instructions
62 | ///
63 | public OperationResult PlaceOrder(Product? product, int quantity,
64 | DateTimeOffset? deliverBy = null,
65 | string instructions = "standard delivery")
66 | {
67 | // Guard clauses to check the parameters
68 | if (product == null) throw new ArgumentNullException(nameof(product));
69 | if (quantity <= 0) throw new ArgumentOutOfRangeException(nameof(quantity));
70 | if (deliverBy <= DateTimeOffset.Now) throw new ArgumentOutOfRangeException(nameof(deliverBy));
71 |
72 | var productIdentifier = product.Category + "-" + product.SequenceNumber;
73 | var orderText = "Order from Acme, Inc" + System.Environment.NewLine +
74 | "Product: " + productIdentifier + System.Environment.NewLine +
75 | "Quantity: " + quantity;
76 | if (deliverBy.HasValue)
77 | {
78 | orderText += System.Environment.NewLine +
79 | "Deliver By: " + deliverBy.Value.ToString("d");
80 | }
81 | if (!string.IsNullOrWhiteSpace(instructions))
82 | {
83 | orderText += System.Environment.NewLine +
84 | "Instructions: " + instructions;
85 | }
86 |
87 | var success = false;
88 | if (this.Email != null)
89 | {
90 | var emailService = new EmailService();
91 | success = emailService.SendMessage("New Order", orderText, Email);
92 | }
93 |
94 | var operationResult = new OperationResult(success, orderText);
95 | return operationResult;
96 |
97 | }
98 |
99 | /////
100 | ///// Sends a product order to the vendor.
101 | /////
102 | ///// Product to order.
103 | ///// Quantity of the product to order.
104 | ///// True to include the shipping address in the order.
105 | ///// True to send a copy of the email to the current user.
106 | ///// Success flag and order text
107 | //public OperationResult PlaceOrder(Product product, int quantity,
108 | // bool includeAddress, bool sendCopy)
109 | //{
110 | // var orderText = "Test";
111 | // if (includeAddress) orderText += " With Address";
112 | // if (sendCopy) orderText += " With Copy";
113 |
114 | // var operationResult = new OperationResult(true, orderText);
115 | // return operationResult;
116 | //}
117 |
118 | public enum IncludeAddress { Yes, No };
119 | public enum SendCopy { Yes, No };
120 |
121 | ///
122 | /// Sends a product order to the vendor.
123 | ///
124 | /// Product to order.
125 | /// Quantity of the product to order.
126 | /// True to include the shipping address in the order.
127 | /// True to send a copy of the email to the current user.
128 | /// Success flag and order text
129 | public OperationResult PlaceOrder(Product product, int quantity,
130 | IncludeAddress includeAddress,
131 | SendCopy sendCopy)
132 | {
133 | var orderText = "Test";
134 | if (includeAddress == IncludeAddress.Yes) orderText += " With Address";
135 | if (sendCopy == SendCopy.Yes) orderText += " With Copy";
136 |
137 | var operationResult = new OperationResult(true, orderText);
138 | return operationResult;
139 | }
140 |
141 | public bool PlaceOrderRef(Product product, int quantity,
142 | ref string orderText)
143 | {
144 | var success = true;
145 | quantity = 42;
146 | orderText = "Order from Acme";
147 |
148 | return success;
149 | }
150 |
151 |
152 | public bool PlaceOrderOut(Product product, int quantity,
153 | out string orderText)
154 | {
155 | var success = true;
156 | quantity = 42;
157 | orderText = "Order from Acme";
158 |
159 | return success;
160 | }
161 |
162 | }
163 |
--------------------------------------------------------------------------------
/AcmeApp/Acme.Biz/VendorRepository.cs:
--------------------------------------------------------------------------------
1 | namespace Acme.Biz;
2 |
3 | public class VendorRepository
4 | {
5 | ///
6 | /// Retrieve one vendor.
7 | ///
8 | public Vendor Retrieve(int vendorId)
9 | {
10 | // Create the instance of the Vendor class
11 | Vendor vendor = new Vendor();
12 |
13 | // Code that retrieves the defined customer
14 |
15 | // Temporary hard coded values to return
16 | if (vendorId == 1)
17 | {
18 | vendor.VendorId = 1;
19 | vendor.CompanyName = "ABC Corp";
20 | vendor.Email = "abc@abc.com";
21 | }
22 | return vendor;
23 | }
24 |
25 | public bool Save(Vendor vendor)
26 | {
27 | var success = true;
28 |
29 | // Code that saves the vendor
30 |
31 | return success;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/AcmeApp/Acme.Common/Acme.Common.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/AcmeApp/Acme.Common/EmailService.cs:
--------------------------------------------------------------------------------
1 | namespace Acme.Common;
2 |
3 | ///
4 | /// Provides services to send email.
5 | ///
6 | public class EmailService
7 | {
8 | ///
9 | /// Sends email message
10 | ///
11 | /// Subject of the message.
12 | /// Message text
13 | /// Email address of the message recipient.
14 | ///
15 | public bool SendMessage(string subject, string message, string recipient)
16 | {
17 | // Code to send an email
18 | LoggingService.LogAction("Message sent " + DateTime.Now + ": " + message);
19 | return true;
20 | }
21 |
22 | }
--------------------------------------------------------------------------------
/AcmeApp/Acme.Common/LoggingService.cs:
--------------------------------------------------------------------------------
1 | namespace Acme.Common;
2 |
3 | ///
4 | /// Provides logging.
5 | ///
6 | public static class LoggingService
7 | {
8 | ///
9 | /// Logs actions.
10 | ///
11 | /// Action to log.
12 | public static string LogAction(string action)
13 | {
14 | var logText = "Action: " + action;
15 | Console.WriteLine(logText);
16 |
17 | return logText;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/AcmeApp/Acme.Common/OperationResult.cs:
--------------------------------------------------------------------------------
1 | namespace Acme.Common;
2 |
3 | ///
4 | /// Provides a success flag and message
5 | /// useful as a method return type.
6 | ///
7 | public class OperationResult
8 | {
9 | public bool Success { get; set; }
10 | public string? Message { get; set; }
11 |
12 | public OperationResult()
13 | {
14 | }
15 |
16 | public OperationResult(bool success, string message) : this()
17 | {
18 | Success = success;
19 | Message = message;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/AcmeApp/Acme.Win/Acme.Win.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WinExe
5 | net6.0-windows
6 | enable
7 | true
8 | enable
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/AcmeApp/Acme.Win/Program.cs:
--------------------------------------------------------------------------------
1 | namespace Acme.Win;
2 |
3 | internal static class Program
4 | {
5 | ///
6 | /// The main entry point for the application.
7 | ///
8 | [STAThread]
9 | static void Main()
10 | {
11 | // To customize application configuration such as set high DPI settings or default font,
12 | // see https://aka.ms/applicationconfiguration.
13 | ApplicationConfiguration.Initialize();
14 | Application.Run(new VendorWin());
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/AcmeApp/Acme.Win/VendorWin.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace Acme.Win;
2 |
3 | partial class VendorWin
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | label1 = new Label();
32 | CompanyNameTextBox = new TextBox();
33 | EmailTextBox = new TextBox();
34 | label2 = new Label();
35 | CancelChangesButton = new Button();
36 | SaveButton = new Button();
37 | SuspendLayout();
38 | //
39 | // label1
40 | //
41 | label1.AutoSize = true;
42 | label1.Location = new Point(13, 13);
43 | label1.Name = "label1";
44 | label1.Size = new Size(94, 15);
45 | label1.TabIndex = 0;
46 | label1.Text = "Company Name";
47 | //
48 | // CompanyNameTextBox
49 | //
50 | CompanyNameTextBox.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
51 | CompanyNameTextBox.Location = new Point(13, 30);
52 | CompanyNameTextBox.Name = "CompanyNameTextBox";
53 | CompanyNameTextBox.Size = new Size(275, 23);
54 | CompanyNameTextBox.TabIndex = 1;
55 | //
56 | // EmailTextBox
57 | //
58 | EmailTextBox.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
59 | EmailTextBox.Location = new Point(13, 72);
60 | EmailTextBox.Name = "EmailTextBox";
61 | EmailTextBox.Size = new Size(275, 23);
62 | EmailTextBox.TabIndex = 3;
63 | //
64 | // label2
65 | //
66 | label2.AutoSize = true;
67 | label2.Location = new Point(16, 54);
68 | label2.Name = "label2";
69 | label2.Size = new Size(84, 15);
70 | label2.TabIndex = 2;
71 | label2.Text = "Email Address:";
72 | //
73 | // CancelChangesButton
74 | //
75 | CancelChangesButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
76 | CancelChangesButton.CausesValidation = false;
77 | CancelChangesButton.DialogResult = DialogResult.Cancel;
78 | CancelChangesButton.Location = new Point(214, 143);
79 | CancelChangesButton.Name = "CancelChangesButton";
80 | CancelChangesButton.Size = new Size(75, 23);
81 | CancelChangesButton.TabIndex = 4;
82 | CancelChangesButton.Text = "Cancel";
83 | CancelChangesButton.UseVisualStyleBackColor = true;
84 | CancelChangesButton.Click += CancelChangesButton_Click;
85 | //
86 | // SaveButton
87 | //
88 | SaveButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
89 | SaveButton.DialogResult = DialogResult.OK;
90 | SaveButton.Location = new Point(133, 143);
91 | SaveButton.Name = "SaveButton";
92 | SaveButton.Size = new Size(75, 23);
93 | SaveButton.TabIndex = 5;
94 | SaveButton.Text = "Save";
95 | SaveButton.UseVisualStyleBackColor = true;
96 | SaveButton.Click += SaveButton_Click;
97 | //
98 | // VendorWin
99 | //
100 | AcceptButton = SaveButton;
101 | AutoScaleDimensions = new SizeF(7F, 15F);
102 | AutoScaleMode = AutoScaleMode.Font;
103 | ClientSize = new Size(301, 178);
104 | Controls.Add(SaveButton);
105 | Controls.Add(CancelChangesButton);
106 | Controls.Add(EmailTextBox);
107 | Controls.Add(label2);
108 | Controls.Add(CompanyNameTextBox);
109 | Controls.Add(label1);
110 | MinimumSize = new Size(301, 187);
111 | Name = "VendorWin";
112 | Text = "Vendor Detail";
113 | Load += VendorWin_Load;
114 | ResumeLayout(false);
115 | PerformLayout();
116 | }
117 |
118 | #endregion
119 |
120 | private System.Windows.Forms.Label label1;
121 | private System.Windows.Forms.TextBox CompanyNameTextBox;
122 | private System.Windows.Forms.TextBox EmailTextBox;
123 | private System.Windows.Forms.Label label2;
124 | private System.Windows.Forms.Button CancelChangesButton;
125 | private System.Windows.Forms.Button SaveButton;
126 | }
--------------------------------------------------------------------------------
/AcmeApp/Acme.Win/VendorWin.cs:
--------------------------------------------------------------------------------
1 | using Acme.Biz;
2 |
3 | namespace Acme.Win
4 | {
5 | public partial class VendorWin : Form
6 | {
7 | Vendor? currentVendor;
8 | VendorRepository? vendorRepository;
9 |
10 | public VendorWin()
11 | {
12 | InitializeComponent();
13 | }
14 |
15 | private void VendorWin_Load(object sender, EventArgs e)
16 | {
17 | LoadData();
18 | }
19 |
20 | private void SaveButton_Click(object sender, EventArgs e)
21 | {
22 | // Update the properties
23 | if (currentVendor != null && vendorRepository != null)
24 | {
25 | currentVendor.CompanyName = this.CompanyNameTextBox.Text;
26 | currentVendor.Email = this.EmailTextBox.Text;
27 | vendorRepository.Save(currentVendor);
28 | }
29 | }
30 |
31 | private void CancelChangesButton_Click(object sender, EventArgs e)
32 | {
33 | LoadData();
34 | }
35 |
36 | private void LoadData()
37 | {
38 | vendorRepository = new VendorRepository();
39 | currentVendor = vendorRepository.Retrieve(1);
40 |
41 | // Populate the form
42 | this.CompanyNameTextBox.Text = currentVendor.CompanyName;
43 | this.EmailTextBox.Text = currentVendor.Email;
44 | }
45 |
46 |
47 | }
48 | }
--------------------------------------------------------------------------------
/AcmeApp/Acme.Win/VendorWin.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | text/microsoft-resx
50 |
51 |
52 | 2.0
53 |
54 |
55 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
56 |
57 |
58 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
59 |
60 |
--------------------------------------------------------------------------------
/AcmeApp/Acme.Wpf/Acme.Wpf.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WinExe
5 | net6.0-windows
6 | enable
7 | true
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/AcmeApp/Acme.Wpf/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/AcmeApp/Acme.Wpf/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace Acme.Wpf;
4 |
5 | ///
6 | /// Interaction logic for App.xaml
7 | ///
8 | public partial class App : Application
9 | {
10 | }
11 |
--------------------------------------------------------------------------------
/AcmeApp/Acme.Wpf/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | [assembly: ThemeInfo(
4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
5 | //(used if a resource is not found in the page,
6 | // or application resource dictionaries)
7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
8 | //(used if a resource is not found in the page,
9 | // app, or any theme specific resource dictionaries)
10 | )]
11 |
--------------------------------------------------------------------------------
/AcmeApp/Acme.Wpf/Assets/StyleLibrary.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 | Verdana
6 |
7 | Orange
9 | White
11 | Gray
13 | Black
15 |
16 |
19 |
22 |
25 |
26 |
28 |
29 |
32 |
35 |
36 |
37 |
38 |
54 |
55 |
68 |
69 |
--------------------------------------------------------------------------------
/AcmeApp/Acme.Wpf/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
--------------------------------------------------------------------------------
/AcmeApp/Acme.Wpf/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Navigation;
2 |
3 | namespace Acme.Wpf;
4 |
5 | ///
6 | /// Interaction logic for MainWindow.xaml
7 | ///
8 | public partial class MainWindow : NavigationWindow
9 | {
10 | public MainWindow()
11 | {
12 | InitializeComponent();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/AcmeApp/Acme.Wpf/ViewModels/VendorDetailViewModel.cs:
--------------------------------------------------------------------------------
1 | using Acme.Biz;
2 |
3 | namespace Acme.Wpf.ViewModels;
4 |
5 | public class VendorDetailViewModel
6 | {
7 | public Vendor? CurrentVendor { get; set; }
8 |
9 | VendorRepository VendorRepository = new VendorRepository();
10 |
11 | public VendorDetailViewModel()
12 | {
13 | LoadData();
14 | }
15 |
16 | public void LoadData()
17 | {
18 | CurrentVendor = VendorRepository.Retrieve(1);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/AcmeApp/Acme.Wpf/Views/VendorDetailView.xaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
33 |
34 |
35 |
38 |
39 |
42 |
43 |
44 |
45 |
46 |
48 |
49 |
51 |
52 |
54 |
55 |
56 |
57 |
58 |
60 |
61 |
63 |
64 |
66 |
67 |
68 |
76 |
80 |
81 |
82 |
90 |
94 |
95 |
96 |
97 |
102 |
106 |
110 |
111 |
112 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/AcmeApp/Acme.Wpf/Views/VendorDetailView.xaml.cs:
--------------------------------------------------------------------------------
1 | using Acme.Biz;
2 | using Acme.Wpf.ViewModels;
3 | using System.Windows;
4 | using System.Windows.Controls;
5 |
6 | namespace Acme.Wpf.Views;
7 |
8 | ///
9 | /// Interaction logic for VendorDetailView.xaml
10 | ///
11 | public partial class VendorDetailView : Page
12 | {
13 | public VendorDetailView()
14 | {
15 | InitializeComponent();
16 | }
17 |
18 | private void SaveButton_Click(object sender, RoutedEventArgs e)
19 | {
20 | var vm = (VendorDetailViewModel)((Button)e.OriginalSource).DataContext;
21 | if (vm?.CurrentVendor != null)
22 | {
23 | var vendorRepository = new VendorRepository();
24 | vendorRepository.Save(vm.CurrentVendor);
25 | }
26 | }
27 |
28 | private void CancelButton_Click(object sender, RoutedEventArgs e)
29 | {
30 | this.NavigationService.Refresh();
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/AcmeApp/AcmeApp.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.5.33424.131
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.Biz", "Acme.Biz\Acme.Biz.csproj", "{A833967A-C6C4-4B3D-AC56-58E38896E908}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.Common", "Acme.Common\Acme.Common.csproj", "{EEFD740D-6B73-4EC5-82DB-1FCB6FD0747F}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.BizTests", "tests\Acme.BizTests\Acme.BizTests.csproj", "{D87F1B23-3B9B-467F-B828-7FE8F12DB15B}"
11 | EndProject
12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{C632A4F7-58A9-4FD4-9BEC-8E8611FB9817}"
13 | EndProject
14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.CommonTests", "tests\Acme.CommonTests\Acme.CommonTests.csproj", "{8C09F1C5-A536-406B-A439-702743779D03}"
15 | EndProject
16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Acme.Win", "Acme.Win\Acme.Win.csproj", "{9095DD64-3D7E-4DAF-9A46-BED72EE2998C}"
17 | EndProject
18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acme.Wpf", "Acme.Wpf\Acme.Wpf.csproj", "{3D464FBC-5924-4438-8626-C6DC437FC193}"
19 | EndProject
20 | Global
21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
22 | Debug|Any CPU = Debug|Any CPU
23 | Release|Any CPU = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
26 | {A833967A-C6C4-4B3D-AC56-58E38896E908}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {A833967A-C6C4-4B3D-AC56-58E38896E908}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {A833967A-C6C4-4B3D-AC56-58E38896E908}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {A833967A-C6C4-4B3D-AC56-58E38896E908}.Release|Any CPU.Build.0 = Release|Any CPU
30 | {EEFD740D-6B73-4EC5-82DB-1FCB6FD0747F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {EEFD740D-6B73-4EC5-82DB-1FCB6FD0747F}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {EEFD740D-6B73-4EC5-82DB-1FCB6FD0747F}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {EEFD740D-6B73-4EC5-82DB-1FCB6FD0747F}.Release|Any CPU.Build.0 = Release|Any CPU
34 | {D87F1B23-3B9B-467F-B828-7FE8F12DB15B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {D87F1B23-3B9B-467F-B828-7FE8F12DB15B}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {D87F1B23-3B9B-467F-B828-7FE8F12DB15B}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 | {D87F1B23-3B9B-467F-B828-7FE8F12DB15B}.Release|Any CPU.Build.0 = Release|Any CPU
38 | {8C09F1C5-A536-406B-A439-702743779D03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 | {8C09F1C5-A536-406B-A439-702743779D03}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 | {8C09F1C5-A536-406B-A439-702743779D03}.Release|Any CPU.ActiveCfg = Release|Any CPU
41 | {8C09F1C5-A536-406B-A439-702743779D03}.Release|Any CPU.Build.0 = Release|Any CPU
42 | {9095DD64-3D7E-4DAF-9A46-BED72EE2998C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
43 | {9095DD64-3D7E-4DAF-9A46-BED72EE2998C}.Debug|Any CPU.Build.0 = Debug|Any CPU
44 | {9095DD64-3D7E-4DAF-9A46-BED72EE2998C}.Release|Any CPU.ActiveCfg = Release|Any CPU
45 | {9095DD64-3D7E-4DAF-9A46-BED72EE2998C}.Release|Any CPU.Build.0 = Release|Any CPU
46 | {3D464FBC-5924-4438-8626-C6DC437FC193}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
47 | {3D464FBC-5924-4438-8626-C6DC437FC193}.Debug|Any CPU.Build.0 = Debug|Any CPU
48 | {3D464FBC-5924-4438-8626-C6DC437FC193}.Release|Any CPU.ActiveCfg = Release|Any CPU
49 | {3D464FBC-5924-4438-8626-C6DC437FC193}.Release|Any CPU.Build.0 = Release|Any CPU
50 | EndGlobalSection
51 | GlobalSection(SolutionProperties) = preSolution
52 | HideSolutionNode = FALSE
53 | EndGlobalSection
54 | GlobalSection(NestedProjects) = preSolution
55 | {D87F1B23-3B9B-467F-B828-7FE8F12DB15B} = {C632A4F7-58A9-4FD4-9BEC-8E8611FB9817}
56 | {8C09F1C5-A536-406B-A439-702743779D03} = {C632A4F7-58A9-4FD4-9BEC-8E8611FB9817}
57 | EndGlobalSection
58 | GlobalSection(ExtensibilityGlobals) = postSolution
59 | SolutionGuid = {14CA8F41-22DC-4A8F-A59D-C719D12D9DBC}
60 | EndGlobalSection
61 | EndGlobal
62 |
--------------------------------------------------------------------------------
/AcmeApp/Tests/Acme.BizTests/Acme.BizTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | enable
7 |
8 | false
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/AcmeApp/Tests/Acme.BizTests/ProductTests.cs:
--------------------------------------------------------------------------------
1 | namespace Acme.Biz.Tests
2 | {
3 | [TestClass()]
4 | public class ProductTests
5 | {
6 | [TestMethod()]
7 | public void Category_DefaultValue()
8 | {
9 | //Arrange
10 | var currentProduct = new Product();
11 |
12 | var expected = "Tools";
13 |
14 | //Act
15 | var actual = currentProduct.Category;
16 |
17 | //Assert
18 | Assert.AreEqual(expected, actual);
19 | }
20 |
21 | [TestMethod()]
22 | public void Category_NewValue()
23 | {
24 | //Arrange
25 | var currentProduct = new Product();
26 | currentProduct.Category = "Garden";
27 |
28 | var expected = "Garden";
29 |
30 | //Act
31 | var actual = currentProduct.Category;
32 |
33 | //Assert
34 | Assert.AreEqual(expected, actual);
35 | }
36 |
37 | [TestMethod()]
38 | public void Sequence_DefaultValue()
39 | {
40 | //Arrange
41 | var currentProduct = new Product();
42 |
43 | var expected = 1;
44 |
45 | //Act
46 | var actual = currentProduct.SequenceNumber;
47 |
48 | //Assert
49 | Assert.AreEqual(expected, actual);
50 | }
51 |
52 | //[TestMethod()]
53 | //public void Sequence_NewValue()
54 | //{
55 | // //Arrange
56 | // var currentProduct = new Product();
57 | // currentProduct.SequenceNumber = 5;
58 |
59 | // var expected = 1;
60 |
61 | // //Act
62 | // var actual = currentProduct.SequenceNumber;
63 |
64 | // //Assert
65 | // Assert.AreEqual(expected, actual);
66 | //}
67 |
68 | [TestMethod()]
69 | public void ProductName_Format()
70 | {
71 | //Arrange
72 | var currentProduct = new Product();
73 | currentProduct.ProductName = " Steel Hammer ";
74 |
75 | var expected = "Steel Hammer";
76 |
77 | //Act
78 | var actual = currentProduct.ProductName;
79 |
80 | //Assert
81 | Assert.AreEqual(expected, actual);
82 | }
83 |
84 | [TestMethod()]
85 | public void ProductName_TooShort()
86 | {
87 | //Arrange
88 | var currentProduct = new Product();
89 | currentProduct.ProductName = "aw";
90 |
91 | string expected = "";
92 | string expectedMessage = "Product Name must be at least 3 characters";
93 |
94 | //Act
95 | var actual = currentProduct.ProductName;
96 | var actualMessage = currentProduct.ValidationMessage;
97 |
98 | //Assert
99 | Assert.AreEqual(expected, actual);
100 | Assert.AreEqual(expectedMessage, actualMessage);
101 | }
102 |
103 | [TestMethod()]
104 | public void ProductName_TooLong()
105 | {
106 | //Arrange
107 | var currentProduct = new Product();
108 | currentProduct.ProductName = "Steel Bladed Hand Saw";
109 |
110 | string expected = "";
111 | string expectedMessage = "Product Name cannot be more than 20 characters";
112 |
113 | //Act
114 | var actual = currentProduct.ProductName;
115 | var actualMessage = currentProduct.ValidationMessage;
116 |
117 | //Assert
118 | Assert.AreEqual(expected, actual);
119 | Assert.AreEqual(expectedMessage, actualMessage);
120 | }
121 |
122 | [TestMethod()]
123 | public void ProductName_JustRight()
124 | {
125 | //Arrange
126 | var currentProduct = new Product();
127 | currentProduct.ProductName = "Saw";
128 |
129 | string expected = "Saw";
130 | string? expectedMessage = null;
131 |
132 | //Act
133 | var actual = currentProduct.ProductName;
134 | var actualMessage = currentProduct.ValidationMessage;
135 |
136 | //Assert
137 | Assert.AreEqual(expected, actual);
138 | Assert.AreEqual(expectedMessage, actualMessage);
139 | }
140 |
141 | [TestMethod()]
142 | public void SayHelloTest()
143 | {
144 | //Arrange
145 | var currentProduct = new Product();
146 | currentProduct.ProductName = "Saw";
147 | currentProduct.ProductId = 1;
148 | currentProduct.Description =
149 | "15-inch steel blade hand saw";
150 | currentProduct.ProductVendor.CompanyName = "ABC Corp";
151 |
152 | var expected = "Hello Saw (1): 15-inch steel blade hand saw";
153 |
154 | //Act
155 | var actual = currentProduct.SayHello();
156 |
157 | //Assert
158 | Assert.AreEqual(expected, actual);
159 | }
160 |
161 | [TestMethod()]
162 | public void SayHello_ParameterizedConstructor()
163 | {
164 | //Arrange
165 | var currentProduct = new Product(1, "Saw",
166 | "15-inch steel blade hand saw");
167 |
168 | var expected = "Hello Saw (1): 15-inch steel blade hand saw";
169 |
170 | //Act
171 | var actual = currentProduct.SayHello();
172 |
173 | //Assert
174 | Assert.AreEqual(expected, actual);
175 | }
176 |
177 | [TestMethod()]
178 | public void SayHello_ObjectInitializer()
179 | {
180 | //Arrange
181 | var currentProduct = new Product
182 | {
183 | ProductId = 1,
184 | ProductName = "Saw",
185 | Description = "15-inch steel blade hand saw"
186 | };
187 |
188 | var expected = "Hello Saw (1): 15-inch steel blade hand saw";
189 |
190 | //Act
191 | var actual = currentProduct.SayHello();
192 |
193 | //Assert
194 | Assert.AreEqual(expected, actual);
195 | }
196 |
197 | [TestMethod()]
198 | public void Product_Null()
199 | {
200 | //Arrange
201 | Product? currentProduct = null;
202 |
203 | var companyName = currentProduct?.ProductVendor?.CompanyName;
204 |
205 | string? expected = null;
206 |
207 | //Act
208 | var actual = companyName;
209 |
210 | //Assert
211 | Assert.AreEqual(expected, actual);
212 | }
213 |
214 | [TestMethod()]
215 | public void ConvertMetersToInchesTest()
216 | {
217 | // Arrange
218 | var expected = 78.74;
219 |
220 | // Act
221 | var actual = 2 * Product.inchesPerMeter;
222 |
223 | // Assert
224 | Assert.AreEqual(expected, actual);
225 | }
226 |
227 | [TestMethod()]
228 | public void MinimumPriceTest_Default()
229 | {
230 | // Arrange
231 | var currentProduct = new Product();
232 | var expected = .96m;
233 |
234 | // Act
235 | var actual = currentProduct.MinimumPrice;
236 |
237 | // Assert
238 | Assert.AreEqual(expected, actual);
239 | }
240 |
241 | [TestMethod()]
242 | public void MinimumPriceTest_Bulk()
243 | {
244 | // Arrange
245 | var currentProduct = new Product(1, "Bulk Tools", "");
246 | var expected = 9.99m;
247 |
248 | // Act
249 | var actual = currentProduct.MinimumPrice;
250 |
251 | // Assert
252 | Assert.AreEqual(expected, actual);
253 | }
254 |
255 | [TestMethod()]
256 | public void ToStringTest()
257 | {
258 | // Arrange
259 | var currentProduct = new Product(1, "Saw", "");
260 | var expected = "Saw (1)";
261 |
262 | // Act
263 | var actual = currentProduct.ToString();
264 |
265 | // Assert
266 | Assert.AreEqual(expected, actual);
267 | }
268 |
269 | [TestMethod()]
270 | public void CalculateSuggestedPriceTest()
271 | {
272 | // Arrange
273 | var currentProduct = new Product(1, "Saw", "");
274 | currentProduct.Cost = 50m;
275 | var expected = 55m;
276 |
277 | // Act
278 | var actual = currentProduct.CalculateSuggestedPrice(10m);
279 |
280 | // Assert
281 | Assert.AreEqual(expected, actual);
282 | }
283 | }
284 | }
--------------------------------------------------------------------------------
/AcmeApp/Tests/Acme.BizTests/Usings.cs:
--------------------------------------------------------------------------------
1 | global using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | global using Acme.Biz;
3 | global using Acme.Common;
--------------------------------------------------------------------------------
/AcmeApp/Tests/Acme.BizTests/VendorTests.cs:
--------------------------------------------------------------------------------
1 | namespace Acme.BizTests
2 | {
3 | [TestClass()]
4 | public class VendorTests
5 | {
6 | [TestMethod()]
7 | public void SayHello_ValidCompany_Success()
8 | {
9 | // Arrange
10 | var vendor = new Vendor();
11 | vendor.CompanyName = "ABC Corp";
12 | var expected = "Hello ABC Corp";
13 |
14 | // Act
15 | var actual = vendor.SayHello();
16 |
17 | // Assert
18 | Assert.AreEqual(expected, actual);
19 | }
20 |
21 | [TestMethod()]
22 | public void SayHello_EmptyCompany_Success()
23 | {
24 | // Arrange
25 | var vendor = new Vendor();
26 | vendor.CompanyName = "";
27 | var expected = "Hello";
28 |
29 | // Act
30 | var actual = vendor.SayHello();
31 |
32 | // Assert
33 | Assert.AreEqual(expected, actual);
34 | }
35 |
36 | [TestMethod()]
37 | public void SayHello_NullCompany_Success()
38 | {
39 | // Arrange
40 | var vendor = new Vendor();
41 | vendor.CompanyName = null;
42 | var expected = "Hello";
43 |
44 | // Act
45 | var actual = vendor.SayHello();
46 |
47 | // Assert
48 | Assert.AreEqual(expected, actual);
49 | }
50 |
51 | [TestMethod()]
52 | public void PlaceOrder_Test()
53 | {
54 | // Arrange
55 | var vendor = new Vendor();
56 | var product = new Product(1, "Saw", "");
57 | var expected = new OperationResult(true, "Order from Acme, Inc\r\nProduct: Tools-1\r\nQuantity: 12" +
58 | "\r\nInstructions: standard delivery");
59 |
60 | // Act
61 | var actual = vendor.PlaceOrder(product, 12);
62 |
63 | // Assert
64 | Assert.AreEqual(expected.Success, actual.Success);
65 | Assert.AreEqual(expected.Message, actual.Message);
66 | }
67 |
68 | [TestMethod()]
69 | public void PlaceOrder_3Parameters()
70 | {
71 | // Arrange
72 | // Set a delivery date in the future
73 | var deliverBy = DateTimeOffset.Now.AddDays(5);
74 | var vendor = new Vendor();
75 | var product = new Product(1, "Saw", "");
76 | var expected = new OperationResult(true, "Order from Acme, Inc\r\nProduct: Tools-1\r\nQuantity: 12" +
77 | $"\r\nDeliver By: {deliverBy.ToString("d")}" +
78 | "\r\nInstructions: standard delivery");
79 |
80 | // Act
81 | var actual = vendor.PlaceOrder(product, 12, deliverBy.Date);
82 |
83 | // Assert
84 | Assert.AreEqual(expected.Success, actual.Success);
85 | Assert.AreEqual(expected.Message, actual.Message);
86 | }
87 |
88 | [TestMethod()]
89 | public void PlaceOrder_4Parameters()
90 | {
91 | // Arrange
92 | var deliverBy = DateTimeOffset.Now.AddDays(5);
93 | var vendor = new Vendor();
94 | var product = new Product(1, "Saw", "");
95 | var expected = new OperationResult(true, "Order from Acme, Inc\r\nProduct: Tools-1\r\nQuantity: 12" +
96 | $"\r\nDeliver By: {deliverBy.ToString("d")}" +
97 | "\r\nInstructions: Deliver to Suite 42");
98 |
99 | // Act
100 | var actual = vendor.PlaceOrder(product, 12,deliverBy.Date,
101 | "Deliver to Suite 42");
102 |
103 | // Assert
104 | Assert.AreEqual(expected.Success, actual.Success);
105 | Assert.AreEqual(expected.Message, actual.Message);
106 | }
107 |
108 | [TestMethod()]
109 | public void PlaceOrder_NoDeliveryDate()
110 | {
111 | // Arrange
112 | var vendor = new Vendor();
113 | var product = new Product(1, "Saw", "");
114 | var expected = new OperationResult(true, "Order from Acme, Inc\r\nProduct: Tools-1\r\nQuantity: 12" +
115 | "\r\nInstructions: Deliver to Suite 42");
116 |
117 | // Act
118 | var actual = vendor.PlaceOrder(product, 12, instructions: "Deliver to Suite 42");
119 |
120 | // Assert
121 | Assert.AreEqual(expected.Success, actual.Success);
122 | Assert.AreEqual(expected.Message, actual.Message);
123 | }
124 |
125 | [TestMethod()]
126 | [ExpectedException(typeof(ArgumentNullException))]
127 | public void PlaceOrder_NullProduct_Exception()
128 | {
129 | // Arrange
130 | var vendor = new Vendor();
131 |
132 | // Act
133 | var actual = vendor.PlaceOrder(null, 12);
134 |
135 | // Assert
136 | // Expected exception
137 | }
138 |
139 | [TestMethod()]
140 | public void PlaceOrderTest()
141 | {
142 | // Arrange
143 | var vendor = new Vendor();
144 | var product = new Product(1, "Saw", "");
145 | var expected = new OperationResult(true, "Test With Address");
146 |
147 | // Act
148 | //var actual = vendor.PlaceOrder(product, 12, true, false);
149 | //var actual = vendor.PlaceOrder(product, 12,
150 | // sendCopy: false,
151 | // includeAddress: true);
152 | var actual = vendor.PlaceOrder(product, 12,
153 | Vendor.IncludeAddress.Yes,
154 | Vendor.SendCopy.No);
155 |
156 | // Assert
157 | Assert.AreEqual(expected.Success, actual.Success);
158 | Assert.AreEqual(expected.Message, actual.Message);
159 | }
160 |
161 | [TestMethod()]
162 | public void PlaceOrderRefTest()
163 | {
164 | // Arrange
165 | var vendor = new Vendor();
166 | var product = new Product(1, "Saw", "");
167 |
168 | var expected = true;
169 | var expectedOrderText = "Order from Acme";
170 |
171 | // Act
172 | string orderText = "test";
173 | bool actual = vendor.PlaceOrderRef(product, 12,
174 | ref orderText);
175 |
176 | // Assert
177 | Assert.AreEqual(expected, actual);
178 | Assert.AreEqual(expectedOrderText, orderText);
179 | }
180 |
181 | [TestMethod()]
182 | public void PlaceOrderOutTest()
183 | {
184 | // Arrange
185 | var vendor = new Vendor();
186 | var product = new Product(1, "Saw", "");
187 |
188 | var expected = true;
189 | var expectedOrderText = "Order from Acme";
190 |
191 | // Act
192 | string orderText;
193 | bool actual = vendor.PlaceOrderOut(product, 12,
194 | out orderText);
195 |
196 | // Assert
197 | Assert.AreEqual(expected, actual);
198 | Assert.AreEqual(expectedOrderText, orderText);
199 | }
200 | }
201 |
202 | }
203 |
--------------------------------------------------------------------------------
/AcmeApp/Tests/Acme.CommonTests/Acme.CommonTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | enable
7 |
8 | false
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/AcmeApp/Tests/Acme.CommonTests/EmailServiceTests.cs:
--------------------------------------------------------------------------------
1 | namespace Acme.CommonTests
2 | {
3 | [TestClass()]
4 | public class EmailServiceTests
5 | {
6 | [TestMethod()]
7 | public void SendMessage_Success()
8 | {
9 | // Arrange
10 | var email = new EmailService();
11 | var expected = true;
12 |
13 | // Act
14 | var actual = email.SendMessage("Test Message",
15 | "This is a test message", "abc@abc.com");
16 |
17 | // Assert
18 | Assert.AreEqual(expected, actual);
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/AcmeApp/Tests/Acme.CommonTests/LoggingServiceTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Acme.CommonTests
8 | {
9 | [TestClass()]
10 | public class LoggingServiceTests
11 | {
12 | [TestMethod()]
13 | public void LogAction_Success()
14 | {
15 | // Arrange
16 | var expected = "Action: Test Action";
17 |
18 | // Act
19 | var actual = LoggingService.LogAction("Test Action");
20 |
21 | // Assert
22 | Assert.AreEqual(expected, actual);
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/AcmeApp/Tests/Acme.CommonTests/Usings.cs:
--------------------------------------------------------------------------------
1 | global using Microsoft.VisualStudio.TestTools.UnitTesting;
2 | global using Acme.Common;
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Deborah Kurata
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CSharpBP-Basics
2 | Materials for the "C# Best Practices: Improving on the Basics" course
3 |
--------------------------------------------------------------------------------