diff --git a/Tests/EqSamples.Tests/AngularAdvancedSearch/ErrorModelTests.cs b/Tests/EqSamples.Tests/AngularAdvancedSearch/ErrorModelTests.cs new file mode 100644 index 00000000..562a612e --- /dev/null +++ b/Tests/EqSamples.Tests/AngularAdvancedSearch/ErrorModelTests.cs @@ -0,0 +1,45 @@ +extern alias AngularAdvSearch; + +using FluentAssertions; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; +using Moq; +using AngularErrorModel = AngularAdvSearch::EqDemo.Pages.ErrorModel; + +namespace EqSamples.Tests.AngularAdvancedSearch; + +public class ErrorModelTests +{ + [Fact] + public void ShowRequestId_ReturnsTrue_WhenSet() + { + var logger = new Mock>(); + var model = new AngularErrorModel(logger.Object); + model.RequestId = "abc"; + model.ShowRequestId.Should().BeTrue(); + } + + [Fact] + public void ShowRequestId_ReturnsFalse_WhenNull() + { + var logger = new Mock>(); + var model = new AngularErrorModel(logger.Object); + model.RequestId = null; + model.ShowRequestId.Should().BeFalse(); + } + + [Fact] + public void OnGet_SetsRequestId() + { + var logger = new Mock>(); + var model = new AngularErrorModel(logger.Object); + var httpContext = new DefaultHttpContext(); + httpContext.TraceIdentifier = "trace-3"; + model.PageContext = new PageContext { HttpContext = httpContext }; + + model.OnGet(); + + model.RequestId.Should().NotBeNullOrEmpty(); + } +} diff --git a/Tests/EqSamples.Tests/AngularAdvancedSearch/ModelsAndDbContextTests.cs b/Tests/EqSamples.Tests/AngularAdvancedSearch/ModelsAndDbContextTests.cs new file mode 100644 index 00000000..13d9d16d --- /dev/null +++ b/Tests/EqSamples.Tests/AngularAdvancedSearch/ModelsAndDbContextTests.cs @@ -0,0 +1,309 @@ +extern alias AngularAdvSearch; + +using FluentAssertions; +using Microsoft.EntityFrameworkCore; +using AngularAppDbContext = AngularAdvSearch::EqDemo.AppDbContext; +using AngularOrder = AngularAdvSearch::EqDemo.Models.Order; +using AngularCustomer = AngularAdvSearch::EqDemo.Models.Customer; +using AngularEmployee = AngularAdvSearch::EqDemo.Models.Employee; +using AngularProduct = AngularAdvSearch::EqDemo.Models.Product; +using AngularCategory = AngularAdvSearch::EqDemo.Models.Category; +using AngularOrderDetail = AngularAdvSearch::EqDemo.Models.OrderDetail; +using AngularShipper = AngularAdvSearch::EqDemo.Models.Shipper; +using AngularSupplier = AngularAdvSearch::EqDemo.Models.Supplier; +using AngularWeatherForecast = AngularAdvSearch::EqDemo.WeatherForecast; + +namespace EqSamples.Tests.AngularAdvancedSearch; + +public class ModelsAndDbContextTests +{ + private AngularAppDbContext CreateContext() + { + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase($"AngularAdvSearch_{Guid.NewGuid()}") + .Options; + return new AngularAppDbContext(options); + } + + [Fact] + public void WeatherForecast_TemperatureF_ConvertsCorrectly() + { + var forecast = new AngularWeatherForecast { TemperatureC = 0 }; + forecast.TemperatureF.Should().Be(32); + + forecast.TemperatureC = 100; + forecast.TemperatureF.Should().Be(32 + (int)(100 / 0.5556)); + + forecast.TemperatureC = -20; + forecast.TemperatureF.Should().Be(32 + (int)(-20 / 0.5556)); + } + + [Fact] + public void WeatherForecast_Properties_SetAndGet() + { + var date = DateTime.Now; + var forecast = new AngularWeatherForecast + { + Date = date, + TemperatureC = 25, + Summary = "Warm" + }; + + forecast.Date.Should().Be(date); + forecast.TemperatureC.Should().Be(25); + forecast.Summary.Should().Be("Warm"); + } + + [Fact] + public void Order_Name_FormatsCorrectly() + { + var order = new AngularOrder + { + Id = 99, + OrderDate = new DateTime(2024, 12, 25) + }; + + order.Name.Should().Be("0099-2024-12-25"); + } + + [Fact] + public void Employee_FullName_CombinesNames() + { + var emp = new AngularEmployee { FirstName = "Alice", LastName = "Johnson" }; + emp.FullName.Should().Be("Alice Johnson"); + } + + [Fact] + public void Employee_FullName_OnlyFirstName() + { + var emp = new AngularEmployee { FirstName = "Alice", LastName = null }; + emp.FullName.Should().Contain("Alice"); + } + + [Fact] + public void DbContext_HasAllDbSets() + { + using var context = CreateContext(); + + context.Categories.Should().NotBeNull(); + context.Customers.Should().NotBeNull(); + context.Employees.Should().NotBeNull(); + context.Orders.Should().NotBeNull(); + context.Products.Should().NotBeNull(); + context.OrderDetails.Should().NotBeNull(); + context.Shippers.Should().NotBeNull(); + context.Suppliers.Should().NotBeNull(); + } + + [Fact] + public async Task DbContext_CRUD_Operations() + { + using var context = CreateContext(); + + var cat = new AngularCategory { Id = 1, CategoryName = "Beverages" }; + context.Categories.Add(cat); + await context.SaveChangesAsync(); + + var found = await context.Categories.FindAsync(1); + found.Should().NotBeNull(); + found!.CategoryName.Should().Be("Beverages"); + } + + [Fact] + public async Task DbContext_OrderDetail_CompositeKey() + { + using var context = CreateContext(); + + context.OrderDetails.Add(new AngularOrderDetail + { + OrderID = 5, + ProductID = 10, + UnitPrice = 15m, + Quantity = 2, + Discount = 0 + }); + await context.SaveChangesAsync(); + + var found = await context.OrderDetails.FindAsync(5, 10); + found.Should().NotBeNull(); + found!.UnitPrice.Should().Be(15m); + } + + [Fact] + public void AllModelProperties_Customer() + { + var c = new AngularCustomer + { + Id = "X", + CompanyName = "C", + Address = "A", + City = "Ci", + Region = "R", + PostalCode = "P", + Country = "Co", + ContactName = "CN", + ContactTitle = "CT", + Phone = "Ph", + Fax = "F" + }; + + c.Id.Should().Be("X"); + c.CompanyName.Should().Be("C"); + c.Address.Should().Be("A"); + c.City.Should().Be("Ci"); + c.Region.Should().Be("R"); + c.PostalCode.Should().Be("P"); + c.Country.Should().Be("Co"); + c.ContactName.Should().Be("CN"); + c.ContactTitle.Should().Be("CT"); + c.Phone.Should().Be("Ph"); + c.Fax.Should().Be("F"); + } + + [Fact] + public void AllModelProperties_Product() + { + var cat = new AngularCategory { Id = 1 }; + var sup = new AngularSupplier { Id = 1 }; + var p = new AngularProduct + { + Id = 1, + Name = "P", + QuantityPerUnit = "Q", + UnitPrice = 10m, + UnitsInStock = 5, + UnitsOnOrder = 2, + ReorderLevel = 1, + Discontinued = true, + CategoryID = 1, + Category = cat, + SupplierID = 1, + Supplier = sup + }; + + p.Discontinued.Should().BeTrue(); + p.ReorderLevel.Should().Be(1); + p.UnitsOnOrder.Should().Be(2); + p.UnitsInStock.Should().Be(5); + p.Name.Should().Be("P"); + p.Category.Should().BeSameAs(cat); + p.Supplier.Should().BeSameAs(sup); + } + + [Fact] + public void AllModelProperties_Order() + { + var c = new AngularCustomer { Id = "C1" }; + var e = new AngularEmployee { Id = 1 }; + var o = new AngularOrder + { + Id = 1, OrderDate = DateTime.Now, RequiredDate = DateTime.Now, + ShippedDate = DateTime.Now, Freight = 10m, CustomerID = "C1", + Customer = c, EmployeeID = 1, Employee = e, + Items = new List(), + ShipVia = 1, ShipName = "S", ShipAddress = "A", + ShipCity = "C", ShipRegion = "R", ShipPostalCode = "P", + ShipCountry = "Co" + }; + o.ShipName.Should().Be("S"); + o.Customer.Should().BeSameAs(c); + o.Employee.Should().BeSameAs(e); + o.Items.Should().BeEmpty(); + o.ShipVia.Should().Be(1); + o.Freight.Should().Be(10m); + } + + [Fact] + public void AllModelProperties_Employee() + { + var mgr = new AngularEmployee { Id = 2 }; + var emp = new AngularEmployee + { + Id = 1, FirstName = "J", LastName = "D", Title = "T", + TitleOfCourtesy = "Mr.", BirthDate = DateTime.Now, + HireDate = DateTime.Now, Address = "A", City = "C", + Region = "R", PostalCode = "P", Country = "Co", + HomePhone = "H", Extension = "E", + Photo = new byte[] { 1 }, PhotoPath = "/p", + Notes = "N", ReportsTo = 2, Manager = mgr, + Orders = new List() + }; + emp.Title.Should().Be("T"); + emp.TitleOfCourtesy.Should().Be("Mr."); + emp.Manager.Should().BeSameAs(mgr); + emp.Orders.Should().BeEmpty(); + } + + [Fact] + public void AllModelProperties_Category() + { + var c = new AngularCategory + { + Id = 1, CategoryName = "B", Description = "D", + Picture = new byte[] { 1 } + }; + c.CategoryName.Should().Be("B"); + c.Description.Should().Be("D"); + c.Picture.Should().HaveCount(1); + } + + [Fact] + public void AllModelProperties_OrderDetail() + { + var o = new AngularOrder { Id = 1 }; + var p = new AngularProduct { Id = 1 }; + var d = new AngularOrderDetail + { + OrderID = 1, Order = o, ProductID = 1, Product = p, + UnitPrice = 10m, Quantity = 5, Discount = 0.1f + }; + d.Order.Should().BeSameAs(o); + d.Product.Should().BeSameAs(p); + } + + [Fact] + public void Employee_FullName_EmptyFirst() + { + var emp = new AngularEmployee { FirstName = "", LastName = "B" }; + emp.FullName.Should().Be("B"); + } + + [Fact] + public void Employee_FullName_NullFirst() + { + var emp = new AngularEmployee { FirstName = null, LastName = "B" }; + emp.FullName.Should().Be("B"); + } + + [Fact] + public void AllModelProperties_Shipper() + { + var s = new AngularShipper { Id = 1, CompanyName = "S", Phone = "P" }; + s.Id.Should().Be(1); + s.CompanyName.Should().Be("S"); + s.Phone.Should().Be("P"); + } + + [Fact] + public void AllModelProperties_Supplier() + { + var s = new AngularSupplier + { + Id = 1, + CompanyName = "S", + ContactName = "C", + ContactTitle = "T", + Address = "A", + City = "Ci", + Region = "R", + PostalCode = "P", + Country = "Co", + Phone = "Ph", + Fax = "F", + HomePage = "H" + }; + + s.CompanyName.Should().Be("S"); + s.HomePage.Should().Be("H"); + } +} diff --git a/Tests/EqSamples.Tests/AngularAdvancedSearch/WeatherForecastControllerTests.cs b/Tests/EqSamples.Tests/AngularAdvancedSearch/WeatherForecastControllerTests.cs new file mode 100644 index 00000000..9661b0e6 --- /dev/null +++ b/Tests/EqSamples.Tests/AngularAdvancedSearch/WeatherForecastControllerTests.cs @@ -0,0 +1,79 @@ +extern alias AngularAdvSearch; + +using FluentAssertions; +using Microsoft.Extensions.Logging; +using Moq; +using AngularWeatherController = AngularAdvSearch::EqDemo.Controllers.WeatherForecastController; + +namespace EqSamples.Tests.AngularAdvancedSearch; + +public class WeatherForecastControllerTests +{ + [Fact] + public void Get_ReturnsFiveForecasts() + { + var logger = new Mock>(); + var controller = new AngularWeatherController(logger.Object); + + var result = controller.Get(); + + result.Should().HaveCount(5); + } + + [Fact] + public void Get_ForecastsHaveValidTemperatureRange() + { + var logger = new Mock>(); + var controller = new AngularWeatherController(logger.Object); + + var result = controller.Get().ToList(); + + foreach (var forecast in result) + { + forecast.TemperatureC.Should().BeInRange(-20, 54); + } + } + + [Fact] + public void Get_ForecastsHaveFutureDates() + { + var logger = new Mock>(); + var controller = new AngularWeatherController(logger.Object); + + var result = controller.Get().ToList(); + + foreach (var forecast in result) + { + forecast.Date.Should().BeAfter(DateTime.Now); + } + } + + [Fact] + public void Get_ForecastsHaveNonNullSummary() + { + var logger = new Mock>(); + var controller = new AngularWeatherController(logger.Object); + + var result = controller.Get().ToList(); + + foreach (var forecast in result) + { + forecast.Summary.Should().NotBeNullOrEmpty(); + } + } + + [Fact] + public void Get_ForecastsHaveCorrectTemperatureF() + { + var logger = new Mock>(); + var controller = new AngularWeatherController(logger.Object); + + var result = controller.Get().ToList(); + + foreach (var forecast in result) + { + var expectedF = 32 + (int)(forecast.TemperatureC / 0.5556); + forecast.TemperatureF.Should().Be(expectedF); + } + } +} diff --git a/Tests/EqSamples.Tests/EqSamples.Tests.csproj b/Tests/EqSamples.Tests/EqSamples.Tests.csproj new file mode 100644 index 00000000..9c2c408a --- /dev/null +++ b/Tests/EqSamples.Tests/EqSamples.Tests.csproj @@ -0,0 +1,61 @@ + + + + net8.0 + enable + enable + false + true + CS8600;CS8601;CS8602;CS8603;CS8604;CS8618;CS8625;CS0436 + + true + cobertura + ./TestResults/ + [EqDemo.*]* + + [*]AspNetCoreGeneratedDocument.*,[*]*Pages_*,[*]*Views_*,[*]Program,[*]*.Program,[*]*.Startup,[*]*DbInitializeExtensions*,[*]*ReportStore,[*]*CustomEasyQueryManagerSql,[*]*OrderController + line + 95 + + + + + + + + + + + + + + + + + + MvcDataFiltering + + + RazorAdHoc + + + RazorAdvSearch + + + RazorDataFilter + + + AngularAdvSearch + + + + + + + + diff --git a/Tests/EqSamples.Tests/MvcDataFiltering/AppDbContextTests.cs b/Tests/EqSamples.Tests/MvcDataFiltering/AppDbContextTests.cs new file mode 100644 index 00000000..47d171e6 --- /dev/null +++ b/Tests/EqSamples.Tests/MvcDataFiltering/AppDbContextTests.cs @@ -0,0 +1,200 @@ +extern alias MvcDataFiltering; + +using FluentAssertions; +using Microsoft.EntityFrameworkCore; +using MvcAppDbContext = MvcDataFiltering::EqDemo.AppDbContext; +using MvcOrder = MvcDataFiltering::EqDemo.Models.Order; +using MvcCustomer = MvcDataFiltering::EqDemo.Models.Customer; +using MvcEmployee = MvcDataFiltering::EqDemo.Models.Employee; +using MvcProduct = MvcDataFiltering::EqDemo.Models.Product; +using MvcCategory = MvcDataFiltering::EqDemo.Models.Category; +using MvcOrderDetail = MvcDataFiltering::EqDemo.Models.OrderDetail; +using MvcShipper = MvcDataFiltering::EqDemo.Models.Shipper; +using MvcSupplier = MvcDataFiltering::EqDemo.Models.Supplier; + +namespace EqSamples.Tests.MvcDataFiltering; + +public class AppDbContextTests +{ + private MvcAppDbContext CreateContext() + { + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase($"MvcDbContext_{Guid.NewGuid()}") + .Options; + return new MvcAppDbContext(options); + } + + [Fact] + public void DbContext_HasAllDbSets() + { + using var context = CreateContext(); + + context.Categories.Should().NotBeNull(); + context.Customers.Should().NotBeNull(); + context.Employees.Should().NotBeNull(); + context.Orders.Should().NotBeNull(); + context.Products.Should().NotBeNull(); + context.OrderDetails.Should().NotBeNull(); + context.Shippers.Should().NotBeNull(); + context.Suppliers.Should().NotBeNull(); + } + + [Fact] + public async Task DbContext_CanAddAndRetrieveOrder() + { + using var context = CreateContext(); + + var order = new MvcOrder + { + Id = 1, + OrderDate = DateTime.Now, + ShipName = "Test" + }; + + context.Orders.Add(order); + await context.SaveChangesAsync(); + + var retrieved = await context.Orders.FindAsync(1); + retrieved.Should().NotBeNull(); + retrieved!.ShipName.Should().Be("Test"); + } + + [Fact] + public async Task DbContext_OrderDetail_HasCompositeKey() + { + using var context = CreateContext(); + + var detail = new MvcOrderDetail + { + OrderID = 1, + ProductID = 1, + UnitPrice = 10m, + Quantity = 5, + Discount = 0 + }; + + context.OrderDetails.Add(detail); + await context.SaveChangesAsync(); + + var retrieved = await context.OrderDetails.FindAsync(1, 1); + retrieved.Should().NotBeNull(); + retrieved!.UnitPrice.Should().Be(10m); + } + + [Fact] + public async Task DbContext_CanAddAndRetrieveCustomer() + { + using var context = CreateContext(); + + var customer = new MvcCustomer + { + Id = "TEST1", + CompanyName = "Test Company", + ContactName = "John Doe", + Country = "US" + }; + + context.Customers.Add(customer); + await context.SaveChangesAsync(); + + var retrieved = await context.Customers.FindAsync("TEST1"); + retrieved.Should().NotBeNull(); + retrieved!.CompanyName.Should().Be("Test Company"); + } + + [Fact] + public async Task DbContext_CanAddAndRetrieveEmployee() + { + using var context = CreateContext(); + + var employee = new MvcEmployee + { + Id = 1, + FirstName = "Jane", + LastName = "Doe" + }; + + context.Employees.Add(employee); + await context.SaveChangesAsync(); + + var retrieved = await context.Employees.FindAsync(1); + retrieved.Should().NotBeNull(); + retrieved!.FullName.Should().Be("Jane Doe"); + } + + [Fact] + public async Task DbContext_CanAddAndRetrieveProduct() + { + using var context = CreateContext(); + + var product = new MvcProduct + { + Id = 1, + Name = "Widget" + }; + + context.Products.Add(product); + await context.SaveChangesAsync(); + + var retrieved = await context.Products.FindAsync(1); + retrieved.Should().NotBeNull(); + retrieved!.Name.Should().Be("Widget"); + } + + [Fact] + public async Task DbContext_CanAddAndRetrieveCategory() + { + using var context = CreateContext(); + + var cat = new MvcCategory + { + Id = 1, + CategoryName = "Beverages" + }; + + context.Categories.Add(cat); + await context.SaveChangesAsync(); + + var retrieved = await context.Categories.FindAsync(1); + retrieved.Should().NotBeNull(); + retrieved!.CategoryName.Should().Be("Beverages"); + } + + [Fact] + public async Task DbContext_CanAddAndRetrieveShipper() + { + using var context = CreateContext(); + + var shipper = new MvcShipper + { + Id = 1, + CompanyName = "Express Shipping" + }; + + context.Shippers.Add(shipper); + await context.SaveChangesAsync(); + + var retrieved = await context.Shippers.FindAsync(1); + retrieved.Should().NotBeNull(); + retrieved!.CompanyName.Should().Be("Express Shipping"); + } + + [Fact] + public async Task DbContext_CanAddAndRetrieveSupplier() + { + using var context = CreateContext(); + + var supplier = new MvcSupplier + { + Id = 1, + CompanyName = "Acme Supplies" + }; + + context.Suppliers.Add(supplier); + await context.SaveChangesAsync(); + + var retrieved = await context.Suppliers.FindAsync(1); + retrieved.Should().NotBeNull(); + retrieved!.CompanyName.Should().Be("Acme Supplies"); + } +} diff --git a/Tests/EqSamples.Tests/MvcDataFiltering/HomeControllerTests.cs b/Tests/EqSamples.Tests/MvcDataFiltering/HomeControllerTests.cs new file mode 100644 index 00000000..1e392b12 --- /dev/null +++ b/Tests/EqSamples.Tests/MvcDataFiltering/HomeControllerTests.cs @@ -0,0 +1,32 @@ +extern alias MvcDataFiltering; + +using FluentAssertions; +using Microsoft.AspNetCore.Mvc; +using MvcHomeController = MvcDataFiltering::EqDemo.Controllers.HomeController; + +namespace EqSamples.Tests.MvcDataFiltering; + +public class HomeControllerTests +{ + [Fact] + public void Index_ReturnsRedirectToOrderIndex() + { + var controller = new MvcHomeController(); + + var result = controller.Index(); + + var redirect = result.Should().BeOfType().Subject; + redirect.ActionName.Should().Be("Index"); + redirect.ControllerName.Should().Be("Order"); + } + + [Fact] + public void Privacy_ReturnsViewResult() + { + var controller = new MvcHomeController(); + + var result = controller.Privacy(); + + result.Should().BeOfType(); + } +} diff --git a/Tests/EqSamples.Tests/MvcDataFiltering/ModelsTests.cs b/Tests/EqSamples.Tests/MvcDataFiltering/ModelsTests.cs new file mode 100644 index 00000000..4ad56856 --- /dev/null +++ b/Tests/EqSamples.Tests/MvcDataFiltering/ModelsTests.cs @@ -0,0 +1,336 @@ +extern alias MvcDataFiltering; + +using FluentAssertions; +using MvcOrder = MvcDataFiltering::EqDemo.Models.Order; +using MvcCustomer = MvcDataFiltering::EqDemo.Models.Customer; +using MvcEmployee = MvcDataFiltering::EqDemo.Models.Employee; +using MvcProduct = MvcDataFiltering::EqDemo.Models.Product; +using MvcCategory = MvcDataFiltering::EqDemo.Models.Category; +using MvcOrderDetail = MvcDataFiltering::EqDemo.Models.OrderDetail; +using MvcShipper = MvcDataFiltering::EqDemo.Models.Shipper; +using MvcSupplier = MvcDataFiltering::EqDemo.Models.Supplier; +using MvcErrorViewModel = MvcDataFiltering::EqDemo.Models.ErrorViewModel; + +namespace EqSamples.Tests.MvcDataFiltering; + +public class ModelsTests +{ + [Fact] + public void Order_Name_FormatsCorrectly() + { + var order = new MvcOrder + { + Id = 42, + OrderDate = new DateTime(2024, 3, 15) + }; + + order.Name.Should().Be("0042-2024-03-15"); + } + + [Fact] + public void Order_Name_HandlesNullOrderDate() + { + var order = new MvcOrder { Id = 1, OrderDate = null }; + order.Name.Should().NotBeNullOrEmpty(); + } + + [Fact] + public void Order_Properties_SetAndGetCorrectly() + { + var customer = new MvcCustomer { Id = "CUST1" }; + var employee = new MvcEmployee { Id = 1 }; + var order = new MvcOrder + { + Id = 100, + OrderDate = new DateTime(2024, 1, 1), + RequiredDate = new DateTime(2024, 1, 15), + ShippedDate = new DateTime(2024, 1, 10), + Freight = 25.50m, + CustomerID = "CUST1", + Customer = customer, + EmployeeID = 1, + Employee = employee, + Items = new List(), + ShipVia = 2, + ShipName = "Test Ship", + ShipAddress = "123 Test St", + ShipCity = "TestCity", + ShipRegion = "TR", + ShipPostalCode = "12345", + ShipCountry = "US" + }; + + order.Id.Should().Be(100); + order.OrderDate.Should().Be(new DateTime(2024, 1, 1)); + order.RequiredDate.Should().Be(new DateTime(2024, 1, 15)); + order.ShippedDate.Should().Be(new DateTime(2024, 1, 10)); + order.Freight.Should().Be(25.50m); + order.CustomerID.Should().Be("CUST1"); + order.Customer.Should().BeSameAs(customer); + order.EmployeeID.Should().Be(1); + order.Employee.Should().BeSameAs(employee); + order.Items.Should().BeEmpty(); + order.ShipVia.Should().Be(2); + order.ShipName.Should().Be("Test Ship"); + order.ShipAddress.Should().Be("123 Test St"); + order.ShipCity.Should().Be("TestCity"); + order.ShipRegion.Should().Be("TR"); + order.ShipPostalCode.Should().Be("12345"); + order.ShipCountry.Should().Be("US"); + } + + [Fact] + public void Employee_FullName_CombinesFirstAndLastName() + { + var emp = new MvcEmployee { FirstName = "John", LastName = "Doe" }; + emp.FullName.Should().Be("John Doe"); + } + + [Fact] + public void Employee_FullName_HandlesFirstNameOnly() + { + var emp = new MvcEmployee { FirstName = "John", LastName = null }; + emp.FullName.Should().Be("John "); + } + + [Fact] + public void Employee_FullName_HandlesEmptyFirstName() + { + var emp = new MvcEmployee { FirstName = "", LastName = "Doe" }; + emp.FullName.Should().Be("Doe"); + } + + [Fact] + public void Employee_FullName_HandlesNullFirstName() + { + var emp = new MvcEmployee { FirstName = null, LastName = "Doe" }; + emp.FullName.Should().Be("Doe"); + } + + [Fact] + public void Employee_Properties_SetAndGetCorrectly() + { + var manager = new MvcEmployee { Id = 2 }; + var emp = new MvcEmployee + { + Id = 1, + FirstName = "Jane", + LastName = "Smith", + Title = "Sales Rep", + TitleOfCourtesy = "Ms.", + BirthDate = new DateTime(1990, 6, 15), + HireDate = new DateTime(2020, 1, 1), + Address = "456 Elm St", + City = "Portland", + Region = "OR", + PostalCode = "97201", + Country = "USA", + HomePhone = "555-0100", + Extension = "1234", + Photo = new byte[] { 1, 2, 3 }, + PhotoPath = "/photos/jane.jpg", + Notes = "Some notes", + ReportsTo = 2, + Manager = manager, + Orders = new List() + }; + + emp.Id.Should().Be(1); + emp.FirstName.Should().Be("Jane"); + emp.LastName.Should().Be("Smith"); + emp.Title.Should().Be("Sales Rep"); + emp.TitleOfCourtesy.Should().Be("Ms."); + emp.BirthDate.Should().Be(new DateTime(1990, 6, 15)); + emp.HireDate.Should().Be(new DateTime(2020, 1, 1)); + emp.Address.Should().Be("456 Elm St"); + emp.City.Should().Be("Portland"); + emp.Region.Should().Be("OR"); + emp.PostalCode.Should().Be("97201"); + emp.Country.Should().Be("USA"); + emp.HomePhone.Should().Be("555-0100"); + emp.Extension.Should().Be("1234"); + emp.Photo.Should().Equal(new byte[] { 1, 2, 3 }); + emp.PhotoPath.Should().Be("/photos/jane.jpg"); + emp.Notes.Should().Be("Some notes"); + emp.ReportsTo.Should().Be(2); + emp.Manager.Should().BeSameAs(manager); + emp.Orders.Should().BeEmpty(); + } + + [Fact] + public void Customer_Properties_SetAndGetCorrectly() + { + var cust = new MvcCustomer + { + Id = "ALFKI", + CompanyName = "Alfreds Futterkiste", + Address = "Obere Str. 57", + City = "Berlin", + Region = null, + PostalCode = "12209", + Country = "Germany", + ContactName = "Maria Anders", + ContactTitle = "Sales Representative", + Phone = "030-0074321", + Fax = "030-0076545" + }; + + cust.Id.Should().Be("ALFKI"); + cust.CompanyName.Should().Be("Alfreds Futterkiste"); + cust.Address.Should().Be("Obere Str. 57"); + cust.City.Should().Be("Berlin"); + cust.Region.Should().BeNull(); + cust.PostalCode.Should().Be("12209"); + cust.Country.Should().Be("Germany"); + cust.ContactName.Should().Be("Maria Anders"); + cust.ContactTitle.Should().Be("Sales Representative"); + cust.Phone.Should().Be("030-0074321"); + cust.Fax.Should().Be("030-0076545"); + } + + [Fact] + public void Product_Properties_SetAndGetCorrectly() + { + var cat = new MvcCategory { Id = 1 }; + var sup = new MvcSupplier { Id = 1 }; + var product = new MvcProduct + { + Id = 10, + Name = "Chai", + QuantityPerUnit = "10 boxes x 20 bags", + UnitPrice = 18.00m, + UnitsInStock = 39, + UnitsOnOrder = 0, + ReorderLevel = 10, + Discontinued = false, + CategoryID = 1, + Category = cat, + SupplierID = 1, + Supplier = sup + }; + + product.Id.Should().Be(10); + product.Name.Should().Be("Chai"); + product.QuantityPerUnit.Should().Be("10 boxes x 20 bags"); + product.UnitPrice.Should().Be(18.00m); + product.UnitsInStock.Should().Be(39); + product.UnitsOnOrder.Should().Be(0); + product.ReorderLevel.Should().Be(10); + product.Discontinued.Should().BeFalse(); + product.CategoryID.Should().Be(1); + product.Category.Should().BeSameAs(cat); + product.SupplierID.Should().Be(1); + product.Supplier.Should().BeSameAs(sup); + } + + [Fact] + public void Category_Properties_SetAndGetCorrectly() + { + var category = new MvcCategory + { + Id = 1, + CategoryName = "Beverages", + Description = "Soft drinks, coffees, teas", + Picture = new byte[] { 0xFF, 0xD8 } + }; + + category.Id.Should().Be(1); + category.CategoryName.Should().Be("Beverages"); + category.Description.Should().Be("Soft drinks, coffees, teas"); + category.Picture.Should().Equal(new byte[] { 0xFF, 0xD8 }); + } + + [Fact] + public void OrderDetail_Properties_SetAndGetCorrectly() + { + var product = new MvcProduct { Id = 1 }; + var order = new MvcOrder { Id = 100 }; + var detail = new MvcOrderDetail + { + OrderID = 100, + Order = order, + ProductID = 1, + Product = product, + UnitPrice = 14.00m, + Quantity = 12, + Discount = 0.1f + }; + + detail.OrderID.Should().Be(100); + detail.Order.Should().BeSameAs(order); + detail.ProductID.Should().Be(1); + detail.Product.Should().BeSameAs(product); + detail.UnitPrice.Should().Be(14.00m); + detail.Quantity.Should().Be(12); + detail.Discount.Should().BeApproximately(0.1f, 0.001f); + } + + [Fact] + public void Shipper_Properties_SetAndGetCorrectly() + { + var shipper = new MvcShipper + { + Id = 1, + CompanyName = "Speedy Express", + Phone = "(503) 555-9831" + }; + + shipper.Id.Should().Be(1); + shipper.CompanyName.Should().Be("Speedy Express"); + shipper.Phone.Should().Be("(503) 555-9831"); + } + + [Fact] + public void Supplier_Properties_SetAndGetCorrectly() + { + var supplier = new MvcSupplier + { + Id = 1, + CompanyName = "Exotic Liquids", + ContactName = "Charlotte Cooper", + ContactTitle = "Purchasing Manager", + Address = "49 Gilbert St.", + City = "London", + Region = null, + PostalCode = "EC1 4SD", + Country = "UK", + Phone = "(171) 555-2222", + Fax = null, + HomePage = null + }; + + supplier.Id.Should().Be(1); + supplier.CompanyName.Should().Be("Exotic Liquids"); + supplier.ContactName.Should().Be("Charlotte Cooper"); + supplier.ContactTitle.Should().Be("Purchasing Manager"); + supplier.Address.Should().Be("49 Gilbert St."); + supplier.City.Should().Be("London"); + supplier.Region.Should().BeNull(); + supplier.PostalCode.Should().Be("EC1 4SD"); + supplier.Country.Should().Be("UK"); + supplier.Phone.Should().Be("(171) 555-2222"); + supplier.Fax.Should().BeNull(); + supplier.HomePage.Should().BeNull(); + } + + [Fact] + public void ErrorViewModel_ShowRequestId_ReturnsTrueWhenRequestIdIsSet() + { + var model = new MvcErrorViewModel { RequestId = "abc123" }; + model.ShowRequestId.Should().BeTrue(); + } + + [Fact] + public void ErrorViewModel_ShowRequestId_ReturnsFalseWhenRequestIdIsNull() + { + var model = new MvcErrorViewModel { RequestId = null }; + model.ShowRequestId.Should().BeFalse(); + } + + [Fact] + public void ErrorViewModel_ShowRequestId_ReturnsFalseWhenRequestIdIsEmpty() + { + var model = new MvcErrorViewModel { RequestId = string.Empty }; + model.ShowRequestId.Should().BeFalse(); + } +} diff --git a/Tests/EqSamples.Tests/MvcDataFiltering/OrderControllerTests.cs b/Tests/EqSamples.Tests/MvcDataFiltering/OrderControllerTests.cs new file mode 100644 index 00000000..4ad459a6 --- /dev/null +++ b/Tests/EqSamples.Tests/MvcDataFiltering/OrderControllerTests.cs @@ -0,0 +1,39 @@ +extern alias MvcDataFiltering; + +using FluentAssertions; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Moq; +using MvcOrder = MvcDataFiltering::EqDemo.Models.Order; +using MvcCustomer = MvcDataFiltering::EqDemo.Models.Customer; +using MvcEmployee = MvcDataFiltering::EqDemo.Models.Employee; +using MvcAppDbContext = MvcDataFiltering::EqDemo.AppDbContext; +using MvcOrderController = MvcDataFiltering::EqDemo.Controllers.OrderController; + +namespace EqSamples.Tests.MvcDataFiltering; + +public class OrderControllerTests +{ + private MvcAppDbContext CreateInMemoryContext() + { + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase(databaseName: $"MvcDataFiltering_{Guid.NewGuid()}") + .Options; + return new MvcAppDbContext(options); + } + + [Fact] + public void Index_ReturnsViewResult_WithOrdersViewName() + { + using var context = CreateInMemoryContext(); + var serviceProvider = new Mock(); + serviceProvider.Setup(sp => sp.GetService(It.IsAny())).Returns(null!); + + var controller = new MvcOrderController(serviceProvider.Object, context); + + var result = controller.Index(); + + var viewResult = result.Should().BeOfType().Subject; + viewResult.ViewName.Should().Be("Orders"); + } +} diff --git a/Tests/EqSamples.Tests/RazorAdHocReporting/AppDbContextTests.cs b/Tests/EqSamples.Tests/RazorAdHocReporting/AppDbContextTests.cs new file mode 100644 index 00000000..92701334 --- /dev/null +++ b/Tests/EqSamples.Tests/RazorAdHocReporting/AppDbContextTests.cs @@ -0,0 +1,127 @@ +extern alias RazorAdHoc; + +using FluentAssertions; +using Microsoft.EntityFrameworkCore; +using RazorAppDbContext = RazorAdHoc::EqDemo.AppDbContext; +using RazorReport = RazorAdHoc::EqDemo.Models.Report; +using RazorOrder = RazorAdHoc::EqDemo.Models.Order; +using RazorCustomer = RazorAdHoc::EqDemo.Models.Customer; +using RazorEmployee = RazorAdHoc::EqDemo.Models.Employee; +using RazorProduct = RazorAdHoc::EqDemo.Models.Product; +using RazorCategory = RazorAdHoc::EqDemo.Models.Category; +using RazorOrderDetail = RazorAdHoc::EqDemo.Models.OrderDetail; +using RazorShipper = RazorAdHoc::EqDemo.Models.Shipper; +using RazorSupplier = RazorAdHoc::EqDemo.Models.Supplier; + +namespace EqSamples.Tests.RazorAdHocReporting; + +public class AppDbContextTests +{ + private RazorAppDbContext CreateContext() + { + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase($"RazorAdHoc_{Guid.NewGuid()}") + .Options; + return new RazorAppDbContext(options); + } + + [Fact] + public void DbContext_HasAllDbSets() + { + using var context = CreateContext(); + + context.Categories.Should().NotBeNull(); + context.Customers.Should().NotBeNull(); + context.Employees.Should().NotBeNull(); + context.Orders.Should().NotBeNull(); + context.Products.Should().NotBeNull(); + context.OrderDetails.Should().NotBeNull(); + context.Shippers.Should().NotBeNull(); + context.Suppliers.Should().NotBeNull(); + context.Reports.Should().NotBeNull(); + } + + [Fact] + public async Task DbContext_CanAddAndRetrieveReport() + { + using var context = CreateContext(); + + var report = new RazorReport + { + Id = "r1", + Name = "Test Report", + Description = "A test", + ModelId = "model1", + QueryJson = "{}", + OwnerId = "user1" + }; + + context.Reports.Add(report); + await context.SaveChangesAsync(); + + var retrieved = await context.Reports.FindAsync("r1"); + retrieved.Should().NotBeNull(); + retrieved!.Name.Should().Be("Test Report"); + } + + [Fact] + public async Task DbContext_CanQueryReportsByOwner() + { + using var context = CreateContext(); + + context.Reports.AddRange( + new RazorReport { Id = "r1", OwnerId = "user1", Name = "Report 1", ModelId = "m1" }, + new RazorReport { Id = "r2", OwnerId = "user2", Name = "Report 2", ModelId = "m1" }, + new RazorReport { Id = "r3", OwnerId = "user1", Name = "Report 3", ModelId = "m1" } + ); + await context.SaveChangesAsync(); + + var user1Reports = await context.Reports.Where(r => r.OwnerId == "user1").ToListAsync(); + user1Reports.Should().HaveCount(2); + } + + [Fact] + public async Task DbContext_OrderDetail_HasCompositeKey() + { + using var context = CreateContext(); + + var detail = new RazorOrderDetail + { + OrderID = 1, + ProductID = 1, + UnitPrice = 10m, + Quantity = 5, + Discount = 0 + }; + + context.OrderDetails.Add(detail); + await context.SaveChangesAsync(); + + var retrieved = await context.OrderDetails.FindAsync(1, 1); + retrieved.Should().NotBeNull(); + } + + [Fact] + public async Task DbContext_CanAddMultipleEntities() + { + using var context = CreateContext(); + + context.Categories.Add(new RazorCategory { Id = 1, CategoryName = "Beverages" }); + context.Customers.Add(new RazorCustomer { Id = "C1", CompanyName = "Co1" }); + context.Employees.Add(new RazorEmployee { Id = 1, FirstName = "A", LastName = "B" }); + context.Shippers.Add(new RazorShipper { Id = 1, CompanyName = "Ship1" }); + context.Suppliers.Add(new RazorSupplier { Id = 1, CompanyName = "Sup1" }); + context.Products.Add(new RazorProduct { Id = 1, Name = "P1" }); + context.Orders.Add(new RazorOrder { Id = 1 }); + + await context.SaveChangesAsync(); + + (await context.Categories.CountAsync()).Should().Be(1); + (await context.Customers.CountAsync()).Should().Be(1); + (await context.Employees.CountAsync()).Should().Be(1); + (await context.Shippers.CountAsync()).Should().Be(1); + (await context.Suppliers.CountAsync()).Should().Be(1); + (await context.Products.CountAsync()).Should().Be(1); + (await context.Orders.CountAsync()).Should().Be(1); + } +} diff --git a/Tests/EqSamples.Tests/RazorAdHocReporting/DefaultReportGeneratorTests.cs b/Tests/EqSamples.Tests/RazorAdHocReporting/DefaultReportGeneratorTests.cs new file mode 100644 index 00000000..dcfc61c2 --- /dev/null +++ b/Tests/EqSamples.Tests/RazorAdHocReporting/DefaultReportGeneratorTests.cs @@ -0,0 +1,97 @@ +extern alias RazorAdHoc; + +using FluentAssertions; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; +using Moq; +using RazorAppDbContext = RazorAdHoc::EqDemo.AppDbContext; +using RazorDefaultReportGenerator = RazorAdHoc::EqDemo.Services.DefaultReportGenerator; + +namespace EqSamples.Tests.RazorAdHocReporting; + +public class DefaultReportGeneratorTests : IDisposable +{ + private readonly string _tempDir; + private readonly string _seedDir; + + public DefaultReportGeneratorTests() + { + _tempDir = Path.Combine(Path.GetTempPath(), $"EqTest_{Guid.NewGuid()}"); + // Production code uses: Path.Combine(env.ContentRootPath, $"App_Data\\Seed") + // On Linux this produces a literal backslash path, so recreate that exact path + _seedDir = Path.Combine(_tempDir, $"App_Data\\Seed"); + Directory.CreateDirectory(_seedDir); + } + + public void Dispose() + { + if (Directory.Exists(_tempDir)) + Directory.Delete(_tempDir, true); + } + + private RazorAppDbContext CreateContext() + { + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase($"ReportGen_{Guid.NewGuid()}") + .Options; + return new RazorAppDbContext(options); + } + + [Fact] + public async Task GenerateAsync_CreatesReportsFromJsonFiles() + { + File.WriteAllText(Path.Combine(_seedDir, "report1.json"), + "{\"name\": \"Report 1\", \"desc\": \"Desc 1\"}"); + File.WriteAllText(Path.Combine(_seedDir, "report2.json"), + "{\"name\": \"Report 2\", \"desc\": \"Desc 2\"}"); + + var mockEnv = new Mock(); + mockEnv.Setup(e => e.ContentRootPath).Returns(_tempDir); + + using var context = CreateContext(); + var generator = new RazorDefaultReportGenerator(mockEnv.Object, context); + var user = new IdentityUser { Id = "test-user-123" }; + + await generator.GenerateAsync(user); + + var reports = await context.Reports.ToListAsync(); + reports.Should().HaveCount(2); + reports.Should().Contain(r => r.Name == "Report 1"); + reports.Should().Contain(r => r.Name == "Report 2"); + reports.Should().OnlyContain(r => r.OwnerId == "test-user-123"); + reports.Should().OnlyContain(r => r.ModelId == "adhoc-reporting"); + } + + [Fact] + public async Task GenerateAsync_NoJsonFiles_NoReportsCreated() + { + var mockEnv = new Mock(); + mockEnv.Setup(e => e.ContentRootPath).Returns(_tempDir); + + using var context = CreateContext(); + var generator = new RazorDefaultReportGenerator(mockEnv.Object, context); + var user = new IdentityUser { Id = "user-1" }; + + await generator.GenerateAsync(user); + + (await context.Reports.CountAsync()).Should().Be(0); + } + + [Fact] + public async Task GenerateAsync_SetsUniqueIds() + { + File.WriteAllText(Path.Combine(_seedDir, "a.json"), "{\"name\":\"A\"}"); + File.WriteAllText(Path.Combine(_seedDir, "b.json"), "{\"name\":\"B\"}"); + + var mockEnv = new Mock(); + mockEnv.Setup(e => e.ContentRootPath).Returns(_tempDir); + + using var context = CreateContext(); + var generator = new RazorDefaultReportGenerator(mockEnv.Object, context); + await generator.GenerateAsync(new IdentityUser { Id = "u1" }); + + var reports = await context.Reports.ToListAsync(); + reports.Select(r => r.Id).Distinct().Should().HaveCount(2); + } +} diff --git a/Tests/EqSamples.Tests/RazorAdHocReporting/ErrorModelTests.cs b/Tests/EqSamples.Tests/RazorAdHocReporting/ErrorModelTests.cs new file mode 100644 index 00000000..ea775e6e --- /dev/null +++ b/Tests/EqSamples.Tests/RazorAdHocReporting/ErrorModelTests.cs @@ -0,0 +1,58 @@ +extern alias RazorAdHoc; + +using FluentAssertions; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; +using Moq; +using RazorErrorModel = RazorAdHoc::EqDemo.Pages.ErrorModel; + +namespace EqSamples.Tests.RazorAdHocReporting; + +public class ErrorModelTests +{ + [Fact] + public void ShowRequestId_ReturnsTrue_WhenRequestIdIsSet() + { + var logger = new Mock>(); + var model = new RazorErrorModel(logger.Object); + model.RequestId = "abc123"; + + model.ShowRequestId.Should().BeTrue(); + } + + [Fact] + public void ShowRequestId_ReturnsFalse_WhenRequestIdIsNull() + { + var logger = new Mock>(); + var model = new RazorErrorModel(logger.Object); + model.RequestId = null; + + model.ShowRequestId.Should().BeFalse(); + } + + [Fact] + public void ShowRequestId_ReturnsFalse_WhenRequestIdIsEmpty() + { + var logger = new Mock>(); + var model = new RazorErrorModel(logger.Object); + model.RequestId = ""; + + model.ShowRequestId.Should().BeFalse(); + } + + [Fact] + public void OnGet_SetsRequestId() + { + var logger = new Mock>(); + var model = new RazorErrorModel(logger.Object); + + var httpContext = new DefaultHttpContext(); + httpContext.TraceIdentifier = "test-trace-id"; + model.PageContext = new PageContext { HttpContext = httpContext }; + + model.OnGet(); + + model.RequestId.Should().NotBeNullOrEmpty(); + } +} diff --git a/Tests/EqSamples.Tests/RazorAdHocReporting/IdentityPageModelsTests.cs b/Tests/EqSamples.Tests/RazorAdHocReporting/IdentityPageModelsTests.cs new file mode 100644 index 00000000..2d302d0b --- /dev/null +++ b/Tests/EqSamples.Tests/RazorAdHocReporting/IdentityPageModelsTests.cs @@ -0,0 +1,526 @@ +extern alias RazorAdHoc; + +using FluentAssertions; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.Mvc.Routing; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Moq; +using RazorLoginModel = RazorAdHoc::EqDemo.Areas.Identity.Pages.Account.LoginModel; +using RazorLogoutModel = RazorAdHoc::EqDemo.Areas.Identity.Pages.Account.LogoutModel; +using RazorRegisterModel = RazorAdHoc::EqDemo.Areas.Identity.Pages.Account.RegisterModel; + +namespace EqSamples.Tests.RazorAdHocReporting; + +public class IdentityPageModelsTests : IDisposable +{ + private readonly List _tempDirs = new(); + private readonly List _contexts = new(); + + public void Dispose() + { + foreach (var ctx in _contexts) + ctx.Dispose(); + foreach (var dir in _tempDirs) + { + if (Directory.Exists(dir)) + Directory.Delete(dir, recursive: true); + } + } + + private static Mock> CreateMockSignInManager() + { + var userStoreMock = new Mock>(); + var userManager = new Mock>( + userStoreMock.Object, null!, null!, null!, null!, null!, null!, null!, null!); + return new Mock>( + userManager.Object, + new Mock().Object, + new Mock>().Object, + new Mock>().Object, + new Mock>>().Object, + new Mock().Object, + new Mock>().Object); + } + + private static Mock> CreateMockUserManager() + { + var userStoreMock = new Mock>(); + return new Mock>( + userStoreMock.Object, null!, null!, null!, null!, null!, null!, null!, null!); + } + + private static PageContext CreatePageContext() + { + var httpContext = new DefaultHttpContext(); + var routeData = new RouteData(); + var pageActionDescriptor = new CompiledPageActionDescriptor(); + return new PageContext(new ActionContext(httpContext, routeData, pageActionDescriptor)); + } + + // ─── LoginModel Tests ─── + + [Fact] + public void LoginModel_InputModel_Properties() + { + var input = new RazorLoginModel.InputModel + { + Email = "test@example.com", + Password = "P@ss1", + RememberMe = true + }; + input.Email.Should().Be("test@example.com"); + input.Password.Should().Be("P@ss1"); + input.RememberMe.Should().BeTrue(); + } + + [Fact] + public void LoginModel_Properties_SetAndGet() + { + var signInMgr = CreateMockSignInManager(); + var logger = new Mock>(); + var model = new RazorLoginModel(signInMgr.Object, logger.Object); + + model.ReturnUrl = "/dashboard"; + model.ReturnUrl.Should().Be("/dashboard"); + + model.ErrorMessage = "Bad login"; + model.ErrorMessage.Should().Be("Bad login"); + + model.ExternalLogins = new List(); + model.ExternalLogins.Should().BeEmpty(); + } + + [Fact] + public async Task LoginModel_OnPostAsync_InvalidModelState_ReturnsPage() + { + var signInMgr = CreateMockSignInManager(); + var logger = new Mock>(); + var model = new RazorLoginModel(signInMgr.Object, logger.Object); + model.PageContext = CreatePageContext(); + + var urlHelper = new Mock(); + urlHelper.Setup(u => u.Content(It.IsAny())).Returns("/"); + model.Url = urlHelper.Object; + + model.ModelState.AddModelError("", "error"); + + var result = await model.OnPostAsync(); + + result.Should().BeOfType(); + } + + [Fact] + public async Task LoginModel_OnGetAsync_WithEmptyErrorMessage_SetsReturnUrl() + { + var signInMgr = CreateMockSignInManager(); + signInMgr.Setup(s => s.GetExternalAuthenticationSchemesAsync()) + .ReturnsAsync(new List()); + + var logger = new Mock>(); + var model = new RazorLoginModel(signInMgr.Object, logger.Object); + + var httpContext = new DefaultHttpContext(); + var serviceProvider = new Mock(); + var authService = new Mock(); + authService.Setup(a => a.SignOutAsync(It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(Task.CompletedTask); + serviceProvider.Setup(sp => sp.GetService(typeof(IAuthenticationService))) + .Returns(authService.Object); + httpContext.RequestServices = serviceProvider.Object; + + model.PageContext = new PageContext { HttpContext = httpContext }; + + var urlHelper = new Mock(); + urlHelper.Setup(u => u.Content(It.IsAny())).Returns("/"); + model.Url = urlHelper.Object; + + model.ErrorMessage = null; + + await model.OnGetAsync("/dashboard"); + + model.ReturnUrl.Should().Be("/dashboard"); + model.ExternalLogins.Should().BeEmpty(); + } + + [Fact] + public async Task LoginModel_OnGetAsync_WithErrorMessage_AddsModelError() + { + var signInMgr = CreateMockSignInManager(); + signInMgr.Setup(s => s.GetExternalAuthenticationSchemesAsync()) + .ReturnsAsync(new List()); + + var logger = new Mock>(); + var model = new RazorLoginModel(signInMgr.Object, logger.Object); + + var httpContext = new DefaultHttpContext(); + var serviceProvider = new Mock(); + var authService = new Mock(); + authService.Setup(a => a.SignOutAsync(It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(Task.CompletedTask); + serviceProvider.Setup(sp => sp.GetService(typeof(IAuthenticationService))) + .Returns(authService.Object); + httpContext.RequestServices = serviceProvider.Object; + + model.PageContext = new PageContext { HttpContext = httpContext }; + + var urlHelper = new Mock(); + urlHelper.Setup(u => u.Content(It.IsAny())).Returns("/"); + model.Url = urlHelper.Object; + + model.ErrorMessage = "Bad creds"; + + await model.OnGetAsync(); + + model.ReturnUrl.Should().Be("/"); + model.ModelState.ErrorCount.Should().BeGreaterThan(0); + } + + [Fact] + public async Task LoginModel_OnPostAsync_ValidModelState_SuccessLogin_Redirects() + { + var signInMgr = CreateMockSignInManager(); + signInMgr.Setup(s => s.PasswordSignInAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Microsoft.AspNetCore.Identity.SignInResult.Success); + + var logger = new Mock>(); + var model = new RazorLoginModel(signInMgr.Object, logger.Object); + model.PageContext = CreatePageContext(); + model.Input = new RazorLoginModel.InputModel { Email = "a@b.c", Password = "pass", RememberMe = false }; + + var urlHelper = new Mock(); + urlHelper.Setup(u => u.Content(It.IsAny())).Returns("/"); + urlHelper.Setup(u => u.IsLocalUrl(It.IsAny())).Returns(true); + model.Url = urlHelper.Object; + + var result = await model.OnPostAsync("/home"); + + result.Should().BeOfType(); + } + + [Fact] + public async Task LoginModel_OnPostAsync_LockedOut_RedirectsToLockout() + { + var signInMgr = CreateMockSignInManager(); + signInMgr.Setup(s => s.PasswordSignInAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Microsoft.AspNetCore.Identity.SignInResult.LockedOut); + + var logger = new Mock>(); + var model = new RazorLoginModel(signInMgr.Object, logger.Object); + model.PageContext = CreatePageContext(); + model.Input = new RazorLoginModel.InputModel { Email = "a@b.c", Password = "pass", RememberMe = false }; + + var urlHelper = new Mock(); + urlHelper.Setup(u => u.Content(It.IsAny())).Returns("/"); + model.Url = urlHelper.Object; + + var result = await model.OnPostAsync(); + + result.Should().BeOfType(); + } + + [Fact] + public async Task LoginModel_OnPostAsync_TwoFactor_RedirectsToLoginWith2fa() + { + var signInMgr = CreateMockSignInManager(); + signInMgr.Setup(s => s.PasswordSignInAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Microsoft.AspNetCore.Identity.SignInResult.TwoFactorRequired); + + var logger = new Mock>(); + var model = new RazorLoginModel(signInMgr.Object, logger.Object); + model.PageContext = CreatePageContext(); + model.Input = new RazorLoginModel.InputModel { Email = "a@b.c", Password = "pass", RememberMe = false }; + + var urlHelper = new Mock(); + urlHelper.Setup(u => u.Content(It.IsAny())).Returns("/"); + model.Url = urlHelper.Object; + + var result = await model.OnPostAsync(); + + result.Should().BeOfType(); + } + + [Fact] + public async Task LoginModel_OnPostAsync_Failed_ReturnsPage() + { + var signInMgr = CreateMockSignInManager(); + signInMgr.Setup(s => s.PasswordSignInAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .ReturnsAsync(Microsoft.AspNetCore.Identity.SignInResult.Failed); + + var logger = new Mock>(); + var model = new RazorLoginModel(signInMgr.Object, logger.Object); + model.PageContext = CreatePageContext(); + model.Input = new RazorLoginModel.InputModel { Email = "a@b.c", Password = "pass", RememberMe = false }; + + var urlHelper = new Mock(); + urlHelper.Setup(u => u.Content(It.IsAny())).Returns("/"); + model.Url = urlHelper.Object; + + var result = await model.OnPostAsync(); + + result.Should().BeOfType(); + } + + // ─── LogoutModel Tests ─── + + [Fact] + public void LogoutModel_OnGet_DoesNotThrow() + { + var signInMgr = CreateMockSignInManager(); + var logger = new Mock>(); + var model = new RazorLogoutModel(signInMgr.Object, logger.Object); + + var exception = Record.Exception(() => model.OnGet()); + exception.Should().BeNull(); + } + + [Fact] + public async Task LogoutModel_OnPost_WithNullReturnUrl_ReturnsRedirectToPage() + { + var signInMgr = CreateMockSignInManager(); + var logger = new Mock>(); + var model = new RazorLogoutModel(signInMgr.Object, logger.Object); + model.PageContext = CreatePageContext(); + + // Configure mock URL helper + var urlHelper = new Mock(); + urlHelper.Setup(u => u.IsLocalUrl(It.IsAny())).Returns(true); + model.Url = urlHelper.Object; + + var result = await model.OnPost(null); + + signInMgr.Verify(s => s.SignOutAsync(), Times.Once); + result.Should().BeOfType(); + } + + [Fact] + public async Task LogoutModel_OnPost_WithReturnUrl_ReturnsLocalRedirect() + { + var signInMgr = CreateMockSignInManager(); + var logger = new Mock>(); + var model = new RazorLogoutModel(signInMgr.Object, logger.Object); + model.PageContext = CreatePageContext(); + + var result = await model.OnPost("/home"); + + signInMgr.Verify(s => s.SignOutAsync(), Times.Once); + result.Should().BeOfType(); + } + + // ─── RegisterModel Tests ─── + + [Fact] + public void RegisterModel_InputModel_Properties() + { + var input = new RazorRegisterModel.InputModel + { + Email = "new@example.com", + Password = "P@ss1234", + ConfirmPassword = "P@ss1234" + }; + input.Email.Should().Be("new@example.com"); + input.Password.Should().Be("P@ss1234"); + input.ConfirmPassword.Should().Be("P@ss1234"); + } + + private RazorAdHoc::EqDemo.Services.DefaultReportGenerator CreateReportGenerator() + { + var tmpDir = Path.Combine(Path.GetTempPath(), $"EqIdentity_{Guid.NewGuid()}"); + var seedDir = Path.Combine(tmpDir, $"App_Data\\Seed"); + Directory.CreateDirectory(seedDir); + _tempDirs.Add(tmpDir); + var mockEnv = new Mock(); + mockEnv.Setup(e => e.ContentRootPath).Returns(tmpDir); + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase($"Identity_{Guid.NewGuid()}") + .Options; + var ctx = new RazorAdHoc::EqDemo.AppDbContext(options); + _contexts.Add(ctx); + return new RazorAdHoc::EqDemo.Services.DefaultReportGenerator(mockEnv.Object, ctx); + } + + [Fact] + public void RegisterModel_OnGet_SetsReturnUrl() + { + var userMgr = CreateMockUserManager(); + var signInMgr = CreateMockSignInManager(); + var logger = new Mock>(); + var emailSender = new Mock(); + var reportGen = CreateReportGenerator(); + + var model = new RazorRegisterModel( + userMgr.Object, signInMgr.Object, logger.Object, + emailSender.Object, reportGen); + + model.OnGet("/return"); + model.ReturnUrl.Should().Be("/return"); + } + + [Fact] + public void RegisterModel_OnGet_NullReturnUrl() + { + var userMgr = CreateMockUserManager(); + var signInMgr = CreateMockSignInManager(); + var logger = new Mock>(); + var emailSender = new Mock(); + var reportGen = CreateReportGenerator(); + + var model = new RazorRegisterModel( + userMgr.Object, signInMgr.Object, logger.Object, + emailSender.Object, reportGen); + + model.OnGet(null); + model.ReturnUrl.Should().BeNull(); + } + + [Fact] + public async Task RegisterModel_OnPostAsync_UserCreationFails_ReturnsPageWithErrors() + { + var userMgr = CreateMockUserManager(); + userMgr.Setup(u => u.CreateAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(IdentityResult.Failed(new IdentityError { Description = "Password too weak" })); + + var signInMgr = CreateMockSignInManager(); + var logger = new Mock>(); + var emailSender = new Mock(); + var reportGen = CreateReportGenerator(); + + var model = new RazorRegisterModel( + userMgr.Object, signInMgr.Object, logger.Object, + emailSender.Object, reportGen); + model.PageContext = CreatePageContext(); + model.Input = new RazorRegisterModel.InputModel + { + Email = "a@b.c", Password = "P@ss1234", ConfirmPassword = "P@ss1234" + }; + + var urlHelper = new Mock(); + urlHelper.Setup(u => u.Content(It.IsAny())).Returns("/"); + model.Url = urlHelper.Object; + + var result = await model.OnPostAsync(); + result.Should().BeOfType(); + model.ModelState.ErrorCount.Should().BeGreaterThan(0); + } + + [Fact] + public async Task RegisterModel_OnPostAsync_Success_RedirectsLocal() + { + var userMgr = CreateMockUserManager(); + userMgr.Setup(u => u.CreateAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(IdentityResult.Success); + userMgr.Setup(u => u.AddToRoleAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(IdentityResult.Success); + userMgr.Setup(u => u.GenerateEmailConfirmationTokenAsync(It.IsAny())) + .ReturnsAsync("token123"); + + var signInMgr = CreateMockSignInManager(); + var logger = new Mock>(); + var emailSender = new Mock(); + emailSender.Setup(e => e.SendEmailAsync(It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(Task.CompletedTask); + var reportGen = CreateReportGenerator(); + + var model = new RazorRegisterModel( + userMgr.Object, signInMgr.Object, logger.Object, + emailSender.Object, reportGen); + + var httpContext = new DefaultHttpContext(); + httpContext.Request.Scheme = "https"; + model.PageContext = new PageContext + { + HttpContext = httpContext + }; + + model.Input = new RazorRegisterModel.InputModel + { + Email = "new@test.com", Password = "P@ss1234", ConfirmPassword = "P@ss1234" + }; + + var urlHelper = new Mock(); + urlHelper.Setup(u => u.Content(It.IsAny())).Returns("/"); + urlHelper.Setup(u => u.IsLocalUrl(It.IsAny())).Returns(true); + urlHelper.Setup(u => u.RouteUrl(It.IsAny())) + .Returns("/confirm?code=token123"); + var actionContext = new ActionContext(httpContext, new RouteData(), new CompiledPageActionDescriptor()); + urlHelper.Setup(u => u.ActionContext).Returns(actionContext); + model.Url = urlHelper.Object; + + var result = await model.OnPostAsync("/home"); + + result.Should().BeOfType(); + signInMgr.Verify(s => s.SignInAsync(It.IsAny(), false, null), Times.Once); + } + + [Fact] + public async Task RegisterModel_OnPostAsync_Success_AddToRoleFails_StillRedirects() + { + var userMgr = CreateMockUserManager(); + userMgr.Setup(u => u.CreateAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(IdentityResult.Success); + userMgr.Setup(u => u.AddToRoleAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(IdentityResult.Failed()); + userMgr.Setup(u => u.GenerateEmailConfirmationTokenAsync(It.IsAny())) + .ReturnsAsync("token"); + + var signInMgr = CreateMockSignInManager(); + var logger = new Mock>(); + var emailSender = new Mock(); + emailSender.Setup(e => e.SendEmailAsync(It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(Task.CompletedTask); + var reportGen = CreateReportGenerator(); + + var model = new RazorRegisterModel( + userMgr.Object, signInMgr.Object, logger.Object, + emailSender.Object, reportGen); + + var httpContext = new DefaultHttpContext(); + httpContext.Request.Scheme = "https"; + model.PageContext = new PageContext { HttpContext = httpContext }; + model.Input = new RazorRegisterModel.InputModel + { + Email = "a@b.c", Password = "P@ss1234", ConfirmPassword = "P@ss1234" + }; + + var urlHelper = new Mock(); + urlHelper.Setup(u => u.Content(It.IsAny())).Returns("/"); + urlHelper.Setup(u => u.RouteUrl(It.IsAny())) + .Returns("/confirm"); + var actionContext = new ActionContext(httpContext, new RouteData(), new CompiledPageActionDescriptor()); + urlHelper.Setup(u => u.ActionContext).Returns(actionContext); + model.Url = urlHelper.Object; + + var result = await model.OnPostAsync("/home"); + result.Should().BeOfType(); + } + + [Fact] + public async Task RegisterModel_OnPostAsync_InvalidModelState_ReturnsPage() + { + var userMgr = CreateMockUserManager(); + var signInMgr = CreateMockSignInManager(); + var logger = new Mock>(); + var emailSender = new Mock(); + var reportGen = CreateReportGenerator(); + + var model = new RazorRegisterModel( + userMgr.Object, signInMgr.Object, logger.Object, + emailSender.Object, reportGen); + model.PageContext = CreatePageContext(); + + var urlHelper = new Mock(); + urlHelper.Setup(u => u.Content(It.IsAny())).Returns("/"); + model.Url = urlHelper.Object; + + model.ModelState.AddModelError("", "error"); + + var result = await model.OnPostAsync(); + result.Should().BeOfType(); + } +} diff --git a/Tests/EqSamples.Tests/RazorAdHocReporting/ModelsTests.cs b/Tests/EqSamples.Tests/RazorAdHocReporting/ModelsTests.cs new file mode 100644 index 00000000..2c4a9f4d --- /dev/null +++ b/Tests/EqSamples.Tests/RazorAdHocReporting/ModelsTests.cs @@ -0,0 +1,222 @@ +extern alias RazorAdHoc; + +using FluentAssertions; +using RazorOrder = RazorAdHoc::EqDemo.Models.Order; +using RazorCustomer = RazorAdHoc::EqDemo.Models.Customer; +using RazorEmployee = RazorAdHoc::EqDemo.Models.Employee; +using RazorProduct = RazorAdHoc::EqDemo.Models.Product; +using RazorCategory = RazorAdHoc::EqDemo.Models.Category; +using RazorOrderDetail = RazorAdHoc::EqDemo.Models.OrderDetail; +using RazorShipper = RazorAdHoc::EqDemo.Models.Shipper; +using RazorSupplier = RazorAdHoc::EqDemo.Models.Supplier; + +namespace EqSamples.Tests.RazorAdHocReporting; + +public class ModelsTests +{ + [Fact] + public void Order_Name_FormatsCorrectly() + { + var order = new RazorOrder { Id = 42, OrderDate = new DateTime(2024, 3, 15) }; + order.Name.Should().Be("0042-2024-03-15"); + } + + [Fact] + public void Order_Name_HandlesNullOrderDate() + { + var order = new RazorOrder { Id = 1, OrderDate = null }; + order.Name.Should().NotBeNullOrEmpty(); + } + + [Fact] + public void Order_AllProperties() + { + var c = new RazorCustomer { Id = "C1" }; + var e = new RazorEmployee { Id = 1 }; + var o = new RazorOrder + { + Id = 1, OrderDate = DateTime.Now, RequiredDate = DateTime.Now, + ShippedDate = DateTime.Now, Freight = 10m, CustomerID = "C1", + Customer = c, EmployeeID = 1, Employee = e, + Items = new List(), + ShipVia = 1, ShipName = "S", ShipAddress = "A", + ShipCity = "C", ShipRegion = "R", ShipPostalCode = "P", + ShipCountry = "Co" + }; + + o.Id.Should().Be(1); + o.CustomerID.Should().Be("C1"); + o.Customer.Should().BeSameAs(c); + o.EmployeeID.Should().Be(1); + o.Employee.Should().BeSameAs(e); + o.Items.Should().BeEmpty(); + o.ShipVia.Should().Be(1); + o.ShipName.Should().Be("S"); + o.ShipAddress.Should().Be("A"); + o.ShipCity.Should().Be("C"); + o.ShipRegion.Should().Be("R"); + o.ShipPostalCode.Should().Be("P"); + o.ShipCountry.Should().Be("Co"); + o.Freight.Should().Be(10m); + o.RequiredDate.Should().NotBeNull(); + o.ShippedDate.Should().NotBeNull(); + } + + [Fact] + public void Employee_FullName_CombinesFirstAndLast() + { + var emp = new RazorEmployee { FirstName = "John", LastName = "Doe" }; + emp.FullName.Should().Be("John Doe"); + } + + [Fact] + public void Employee_FullName_EmptyFirstName() + { + var emp = new RazorEmployee { FirstName = "", LastName = "Doe" }; + emp.FullName.Should().Be("Doe"); + } + + [Fact] + public void Employee_FullName_NullFirstName() + { + var emp = new RazorEmployee { FirstName = null, LastName = "Doe" }; + emp.FullName.Should().Be("Doe"); + } + + [Fact] + public void Employee_FullName_NullLastName() + { + var emp = new RazorEmployee { FirstName = "John", LastName = null }; + emp.FullName.Should().Contain("John"); + } + + [Fact] + public void Employee_AllProperties() + { + var mgr = new RazorEmployee { Id = 2 }; + var emp = new RazorEmployee + { + Id = 1, FirstName = "J", LastName = "D", Title = "T", + TitleOfCourtesy = "Mr.", BirthDate = DateTime.Now, + HireDate = DateTime.Now, Address = "A", City = "C", + Region = "R", PostalCode = "P", Country = "Co", + HomePhone = "H", Extension = "E", + Photo = new byte[] { 1 }, PhotoPath = "/p", + Notes = "N", ReportsTo = 2, Manager = mgr, + Orders = new List() + }; + + emp.Title.Should().Be("T"); + emp.TitleOfCourtesy.Should().Be("Mr."); + emp.BirthDate.Should().NotBeNull(); + emp.HireDate.Should().NotBeNull(); + emp.Address.Should().Be("A"); + emp.City.Should().Be("C"); + emp.Region.Should().Be("R"); + emp.PostalCode.Should().Be("P"); + emp.Country.Should().Be("Co"); + emp.HomePhone.Should().Be("H"); + emp.Extension.Should().Be("E"); + emp.Photo.Should().HaveCount(1); + emp.PhotoPath.Should().Be("/p"); + emp.Notes.Should().Be("N"); + emp.ReportsTo.Should().Be(2); + emp.Manager.Should().BeSameAs(mgr); + emp.Orders.Should().BeEmpty(); + } + + [Fact] + public void Customer_AllProperties() + { + var c = new RazorCustomer + { + Id = "X", CompanyName = "C", Address = "A", City = "Ci", + Region = "R", PostalCode = "P", Country = "Co", + ContactName = "CN", ContactTitle = "CT", Phone = "Ph", Fax = "F" + }; + c.Id.Should().Be("X"); + c.CompanyName.Should().Be("C"); + c.Address.Should().Be("A"); + c.City.Should().Be("Ci"); + c.Region.Should().Be("R"); + c.PostalCode.Should().Be("P"); + c.Country.Should().Be("Co"); + c.ContactName.Should().Be("CN"); + c.ContactTitle.Should().Be("CT"); + c.Phone.Should().Be("Ph"); + c.Fax.Should().Be("F"); + } + + [Fact] + public void Product_AllProperties() + { + var cat = new RazorCategory { Id = 1 }; + var sup = new RazorSupplier { Id = 1 }; + var p = new RazorProduct + { + Id = 1, Name = "P", QuantityPerUnit = "Q", UnitPrice = 10m, + UnitsInStock = 5, UnitsOnOrder = 2, ReorderLevel = 1, + Discontinued = true, CategoryID = 1, Category = cat, + SupplierID = 1, Supplier = sup + }; + p.Name.Should().Be("P"); + p.Discontinued.Should().BeTrue(); + p.Category.Should().BeSameAs(cat); + p.Supplier.Should().BeSameAs(sup); + } + + [Fact] + public void Category_AllProperties() + { + var c = new RazorCategory + { + Id = 1, CategoryName = "B", Description = "D", + Picture = new byte[] { 1 } + }; + c.CategoryName.Should().Be("B"); + c.Description.Should().Be("D"); + c.Picture.Should().HaveCount(1); + } + + [Fact] + public void OrderDetail_AllProperties() + { + var order = new RazorOrder { Id = 1 }; + var product = new RazorProduct { Id = 1 }; + var d = new RazorOrderDetail + { + OrderID = 1, Order = order, ProductID = 1, Product = product, + UnitPrice = 10m, Quantity = 5, Discount = 0.1f + }; + d.OrderID.Should().Be(1); + d.Order.Should().BeSameAs(order); + d.ProductID.Should().Be(1); + d.Product.Should().BeSameAs(product); + d.UnitPrice.Should().Be(10m); + d.Quantity.Should().Be(5); + d.Discount.Should().BeApproximately(0.1f, 0.001f); + } + + [Fact] + public void Shipper_AllProperties() + { + var s = new RazorShipper { Id = 1, CompanyName = "S", Phone = "P" }; + s.Id.Should().Be(1); + s.CompanyName.Should().Be("S"); + s.Phone.Should().Be("P"); + } + + [Fact] + public void Supplier_AllProperties() + { + var s = new RazorSupplier + { + Id = 1, CompanyName = "S", ContactName = "C", ContactTitle = "T", + Address = "A", City = "Ci", Region = "R", PostalCode = "P", + Country = "Co", Phone = "Ph", Fax = "F", HomePage = "H" + }; + s.CompanyName.Should().Be("S"); + s.ContactName.Should().Be("C"); + s.HomePage.Should().Be("H"); + } +} diff --git a/Tests/EqSamples.Tests/RazorAdHocReporting/PageModelsTests.cs b/Tests/EqSamples.Tests/RazorAdHocReporting/PageModelsTests.cs new file mode 100644 index 00000000..46a48596 --- /dev/null +++ b/Tests/EqSamples.Tests/RazorAdHocReporting/PageModelsTests.cs @@ -0,0 +1,32 @@ +extern alias RazorAdHoc; + +using FluentAssertions; +using Microsoft.Extensions.Logging; +using Moq; +using RazorIndexModel = RazorAdHoc::EqDemo.Pages.IndexModel; +using RazorPrivacyModel = RazorAdHoc::EqDemo.Pages.PrivacyModel; + +namespace EqSamples.Tests.RazorAdHocReporting; + +public class PageModelsTests +{ + [Fact] + public void IndexModel_OnGet_DoesNotThrow() + { + var logger = new Mock>(); + var model = new RazorIndexModel(logger.Object); + + var exception = Record.Exception(() => model.OnGet()); + exception.Should().BeNull(); + } + + [Fact] + public void PrivacyModel_OnGet_DoesNotThrow() + { + var logger = new Mock>(); + var model = new RazorPrivacyModel(logger.Object); + + var exception = Record.Exception(() => model.OnGet()); + exception.Should().BeNull(); + } +} diff --git a/Tests/EqSamples.Tests/RazorAdHocReporting/ReportModelTests.cs b/Tests/EqSamples.Tests/RazorAdHocReporting/ReportModelTests.cs new file mode 100644 index 00000000..d00d17c7 --- /dev/null +++ b/Tests/EqSamples.Tests/RazorAdHocReporting/ReportModelTests.cs @@ -0,0 +1,45 @@ +extern alias RazorAdHoc; + +using FluentAssertions; +using RazorReport = RazorAdHoc::EqDemo.Models.Report; + +namespace EqSamples.Tests.RazorAdHocReporting; + +public class ReportModelTests +{ + [Fact] + public void Report_Properties_SetAndGetCorrectly() + { + var report = new RazorReport + { + Id = "report-001", + Name = "Sales Report", + Description = "Monthly sales overview", + ModelId = "adhoc-reporting", + QueryJson = "{\"columns\":[]}", + OwnerId = "user-123" + }; + + report.Id.Should().Be("report-001"); + report.Name.Should().Be("Sales Report"); + report.Description.Should().Be("Monthly sales overview"); + report.ModelId.Should().Be("adhoc-reporting"); + report.QueryJson.Should().Be("{\"columns\":[]}"); + report.OwnerId.Should().Be("user-123"); + report.Owner.Should().BeNull(); + } + + [Fact] + public void Report_DefaultValues_AreNull() + { + var report = new RazorReport(); + + report.Id.Should().BeNull(); + report.Name.Should().BeNull(); + report.Description.Should().BeNull(); + report.ModelId.Should().BeNull(); + report.QueryJson.Should().BeNull(); + report.OwnerId.Should().BeNull(); + report.Owner.Should().BeNull(); + } +} diff --git a/Tests/EqSamples.Tests/RazorAdHocReporting/ReportStoreTests.cs b/Tests/EqSamples.Tests/RazorAdHocReporting/ReportStoreTests.cs new file mode 100644 index 00000000..402e1655 --- /dev/null +++ b/Tests/EqSamples.Tests/RazorAdHocReporting/ReportStoreTests.cs @@ -0,0 +1,137 @@ +extern alias RazorAdHoc; + +using System.Security.Claims; +using FluentAssertions; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using RazorAppDbContext = RazorAdHoc::EqDemo.AppDbContext; +using RazorReport = RazorAdHoc::EqDemo.Models.Report; +using RazorReportStore = RazorAdHoc::EqDemo.ReportStore; + +namespace EqSamples.Tests.RazorAdHocReporting; + +public class ReportStoreTests +{ + private RazorAppDbContext CreateContext(string dbName) + { + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase(dbName) + .Options; + return new RazorAppDbContext(options); + } + + private (RazorReportStore store, RazorAppDbContext context) CreateStoreWithUser(string userId, string? dbName = null) + { + dbName ??= $"ReportStore_{Guid.NewGuid()}"; + var context = CreateContext(dbName); + + var claims = new List { new Claim(ClaimTypes.NameIdentifier, userId) }; + var identity = new ClaimsIdentity(claims, "TestAuth"); + var principal = new ClaimsPrincipal(identity); + var httpContext = new DefaultHttpContext { User = principal }; + + var httpContextAccessor = new Mock(); + httpContextAccessor.Setup(a => a.HttpContext).Returns(httpContext); + + var serviceProvider = new Mock(); + serviceProvider.Setup(sp => sp.GetService(typeof(IHttpContextAccessor))) + .Returns(httpContextAccessor.Object); + serviceProvider.Setup(sp => sp.GetService(typeof(RazorAppDbContext))) + .Returns(context); + + var store = new RazorReportStore(serviceProvider.Object); + return (store, context); + } + + [Fact] + public async Task GetAllQueriesAsync_ReturnsOnlyUserReports() + { + var dbName = $"ReportStore_{Guid.NewGuid()}"; + + using var setupContext = CreateContext(dbName); + setupContext.Reports.AddRange( + new RazorReport { Id = "r1", OwnerId = "user1", ModelId = "m1", Name = "R1" }, + new RazorReport { Id = "r2", OwnerId = "user2", ModelId = "m1", Name = "R2" }, + new RazorReport { Id = "r3", OwnerId = "user1", ModelId = "m1", Name = "R3" } + ); + await setupContext.SaveChangesAsync(); + + var (store, context) = CreateStoreWithUser("user1", dbName); + using (context) + { + var result = await store.GetAllQueriesAsync("m1"); + result.Should().HaveCount(2); + } + } + + [Fact] + public async Task GetAllQueriesAsync_ReturnsEmptyForNoMatches() + { + var (store, context) = CreateStoreWithUser("user1"); + using (context) + { + var result = await store.GetAllQueriesAsync("nonexistent"); + result.Should().BeEmpty(); + } + } + + [Fact] + public async Task RemoveQueryAsync_RemovesExistingReport() + { + var dbName = $"ReportStore_{Guid.NewGuid()}"; + + using var setupContext = CreateContext(dbName); + setupContext.Reports.Add(new RazorReport { Id = "r1", OwnerId = "user1", ModelId = "m1", Name = "R1" }); + await setupContext.SaveChangesAsync(); + + var (store, context) = CreateStoreWithUser("user1", dbName); + using (context) + { + var removed = await store.RemoveQueryAsync("m1", "r1"); + removed.Should().BeTrue(); + + (await context.Reports.FindAsync("r1")).Should().BeNull(); + } + } + + [Fact] + public async Task RemoveQueryAsync_ReturnsFalseForNonexistentReport() + { + var (store, context) = CreateStoreWithUser("user1"); + using (context) + { + var removed = await store.RemoveQueryAsync("m1", "nonexistent"); + removed.Should().BeFalse(); + } + } + + [Fact] + public async Task RemoveQueryAsync_ReturnsFalseForOtherUsersReport() + { + var dbName = $"ReportStore_{Guid.NewGuid()}"; + + using var setupContext = CreateContext(dbName); + setupContext.Reports.Add(new RazorReport { Id = "r1", OwnerId = "user2", ModelId = "m1", Name = "R1" }); + await setupContext.SaveChangesAsync(); + + var (store, context) = CreateStoreWithUser("user1", dbName); + using (context) + { + var removed = await store.RemoveQueryAsync("m1", "r1"); + removed.Should().BeFalse(); + } + } + + [Fact] + public void Constructor_ThrowsWhenServiceMissing() + { + var sp = new Mock(); + sp.Setup(s => s.GetService(typeof(IHttpContextAccessor))).Returns(null!); + + Action act = () => new RazorReportStore(sp.Object); + + act.Should().Throw(); + } +} diff --git a/Tests/EqSamples.Tests/RazorAdvancedSearch/AppDbContextTests.cs b/Tests/EqSamples.Tests/RazorAdvancedSearch/AppDbContextTests.cs new file mode 100644 index 00000000..d52f66ab --- /dev/null +++ b/Tests/EqSamples.Tests/RazorAdvancedSearch/AppDbContextTests.cs @@ -0,0 +1,67 @@ +extern alias RazorAdvSearch; + +using FluentAssertions; +using Microsoft.EntityFrameworkCore; +using RazorAppDbContext = RazorAdvSearch::EqDemo.AppDbContext; +using RazorOrder = RazorAdvSearch::EqDemo.Models.Order; +using RazorOrderDetail = RazorAdvSearch::EqDemo.Models.OrderDetail; + +namespace EqSamples.Tests.RazorAdvancedSearch; + +public class AppDbContextTests +{ + private RazorAppDbContext CreateContext() + { + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase($"RazorAdvSearch_{Guid.NewGuid()}") + .Options; + return new RazorAppDbContext(options); + } + + [Fact] + public void DbContext_HasAllDbSets() + { + using var context = CreateContext(); + + context.Categories.Should().NotBeNull(); + context.Customers.Should().NotBeNull(); + context.Employees.Should().NotBeNull(); + context.Orders.Should().NotBeNull(); + context.Products.Should().NotBeNull(); + context.OrderDetails.Should().NotBeNull(); + context.Shippers.Should().NotBeNull(); + context.Suppliers.Should().NotBeNull(); + } + + [Fact] + public async Task DbContext_OrderDetail_HasCompositeKey() + { + using var context = CreateContext(); + + context.OrderDetails.Add(new RazorOrderDetail + { + OrderID = 10, + ProductID = 20, + UnitPrice = 5m, + Quantity = 3, + Discount = 0 + }); + await context.SaveChangesAsync(); + + var found = await context.OrderDetails.FindAsync(10, 20); + found.Should().NotBeNull(); + } + + [Fact] + public async Task DbContext_CanAddAndQueryOrders() + { + using var context = CreateContext(); + + context.Orders.Add(new RazorOrder { Id = 1, ShipCity = "NYC" }); + context.Orders.Add(new RazorOrder { Id = 2, ShipCity = "LA" }); + await context.SaveChangesAsync(); + + var nycOrders = await context.Orders.Where(o => o.ShipCity == "NYC").ToListAsync(); + nycOrders.Should().HaveCount(1); + } +} diff --git a/Tests/EqSamples.Tests/RazorAdvancedSearch/ErrorModelTests.cs b/Tests/EqSamples.Tests/RazorAdvancedSearch/ErrorModelTests.cs new file mode 100644 index 00000000..904917d0 --- /dev/null +++ b/Tests/EqSamples.Tests/RazorAdvancedSearch/ErrorModelTests.cs @@ -0,0 +1,45 @@ +extern alias RazorAdvSearch; + +using FluentAssertions; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; +using Moq; +using RazorErrorModel = RazorAdvSearch::EqDemo.Pages.ErrorModel; + +namespace EqSamples.Tests.RazorAdvancedSearch; + +public class ErrorModelTests +{ + [Fact] + public void ShowRequestId_ReturnsTrue_WhenSet() + { + var logger = new Mock>(); + var model = new RazorErrorModel(logger.Object); + model.RequestId = "abc"; + model.ShowRequestId.Should().BeTrue(); + } + + [Fact] + public void ShowRequestId_ReturnsFalse_WhenNull() + { + var logger = new Mock>(); + var model = new RazorErrorModel(logger.Object); + model.RequestId = null; + model.ShowRequestId.Should().BeFalse(); + } + + [Fact] + public void OnGet_SetsRequestId() + { + var logger = new Mock>(); + var model = new RazorErrorModel(logger.Object); + var httpContext = new DefaultHttpContext(); + httpContext.TraceIdentifier = "trace-1"; + model.PageContext = new PageContext { HttpContext = httpContext }; + + model.OnGet(); + + model.RequestId.Should().NotBeNullOrEmpty(); + } +} diff --git a/Tests/EqSamples.Tests/RazorAdvancedSearch/ModelsTests.cs b/Tests/EqSamples.Tests/RazorAdvancedSearch/ModelsTests.cs new file mode 100644 index 00000000..104c65c7 --- /dev/null +++ b/Tests/EqSamples.Tests/RazorAdvancedSearch/ModelsTests.cs @@ -0,0 +1,158 @@ +extern alias RazorAdvSearch; + +using FluentAssertions; +using RazorOrder = RazorAdvSearch::EqDemo.Models.Order; +using RazorCustomer = RazorAdvSearch::EqDemo.Models.Customer; +using RazorEmployee = RazorAdvSearch::EqDemo.Models.Employee; +using RazorProduct = RazorAdvSearch::EqDemo.Models.Product; +using RazorCategory = RazorAdvSearch::EqDemo.Models.Category; +using RazorOrderDetail = RazorAdvSearch::EqDemo.Models.OrderDetail; +using RazorShipper = RazorAdvSearch::EqDemo.Models.Shipper; +using RazorSupplier = RazorAdvSearch::EqDemo.Models.Supplier; + +namespace EqSamples.Tests.RazorAdvancedSearch; + +public class ModelsTests +{ + [Fact] + public void Order_Name_FormatsCorrectly() + { + var order = new RazorOrder { Id = 99, OrderDate = new DateTime(2024, 12, 25) }; + order.Name.Should().Be("0099-2024-12-25"); + } + + [Fact] + public void Order_AllProperties() + { + var c = new RazorCustomer { Id = "C1" }; + var e = new RazorEmployee { Id = 1 }; + var o = new RazorOrder + { + Id = 1, OrderDate = DateTime.Now, RequiredDate = DateTime.Now, + ShippedDate = DateTime.Now, Freight = 10m, CustomerID = "C1", + Customer = c, EmployeeID = 1, Employee = e, + Items = new List(), + ShipVia = 1, ShipName = "S", ShipAddress = "A", + ShipCity = "C", ShipRegion = "R", ShipPostalCode = "P", + ShipCountry = "Co" + }; + o.ShipName.Should().Be("S"); + o.Customer.Should().BeSameAs(c); + o.Employee.Should().BeSameAs(e); + } + + [Fact] + public void Employee_FullName_CombinesNames() + { + var emp = new RazorEmployee { FirstName = "A", LastName = "B" }; + emp.FullName.Should().Be("A B"); + } + + [Fact] + public void Employee_FullName_EmptyFirst() + { + var emp = new RazorEmployee { FirstName = "", LastName = "B" }; + emp.FullName.Should().Be("B"); + } + + [Fact] + public void Employee_FullName_NullFirst() + { + var emp = new RazorEmployee { FirstName = null, LastName = "B" }; + emp.FullName.Should().Be("B"); + } + + [Fact] + public void Employee_AllProperties() + { + var mgr = new RazorEmployee { Id = 2 }; + var emp = new RazorEmployee + { + Id = 1, FirstName = "J", LastName = "D", Title = "T", + TitleOfCourtesy = "Mr.", BirthDate = DateTime.Now, + HireDate = DateTime.Now, Address = "A", City = "C", + Region = "R", PostalCode = "P", Country = "Co", + HomePhone = "H", Extension = "E", + Photo = new byte[] { 1 }, PhotoPath = "/p", + Notes = "N", ReportsTo = 2, Manager = mgr, + Orders = new List() + }; + emp.Title.Should().Be("T"); + emp.Manager.Should().BeSameAs(mgr); + emp.Orders.Should().BeEmpty(); + } + + [Fact] + public void Customer_AllProperties() + { + var c = new RazorCustomer + { + Id = "X", CompanyName = "C", Address = "A", City = "Ci", + Region = "R", PostalCode = "P", Country = "Co", + ContactName = "CN", ContactTitle = "CT", Phone = "Ph", Fax = "F" + }; + c.CompanyName.Should().Be("C"); + c.Fax.Should().Be("F"); + } + + [Fact] + public void Product_AllProperties() + { + var cat = new RazorCategory { Id = 1 }; + var sup = new RazorSupplier { Id = 1 }; + var p = new RazorProduct + { + Id = 1, Name = "P", QuantityPerUnit = "Q", UnitPrice = 10m, + UnitsInStock = 5, UnitsOnOrder = 2, ReorderLevel = 1, + Discontinued = true, CategoryID = 1, Category = cat, + SupplierID = 1, Supplier = sup + }; + p.Name.Should().Be("P"); + p.Discontinued.Should().BeTrue(); + } + + [Fact] + public void Category_AllProperties() + { + var c = new RazorCategory + { + Id = 1, CategoryName = "B", Description = "D", + Picture = new byte[] { 1 } + }; + c.CategoryName.Should().Be("B"); + } + + [Fact] + public void OrderDetail_AllProperties() + { + var o = new RazorOrder { Id = 1 }; + var p = new RazorProduct { Id = 1 }; + var d = new RazorOrderDetail + { + OrderID = 1, Order = o, ProductID = 1, Product = p, + UnitPrice = 10m, Quantity = 5, Discount = 0.1f + }; + d.UnitPrice.Should().Be(10m); + d.Order.Should().BeSameAs(o); + d.Product.Should().BeSameAs(p); + } + + [Fact] + public void Shipper_AllProperties() + { + var s = new RazorShipper { Id = 1, CompanyName = "S", Phone = "P" }; + s.CompanyName.Should().Be("S"); + } + + [Fact] + public void Supplier_AllProperties() + { + var s = new RazorSupplier + { + Id = 1, CompanyName = "S", ContactName = "C", ContactTitle = "T", + Address = "A", City = "Ci", Region = "R", PostalCode = "P", + Country = "Co", Phone = "Ph", Fax = "F", HomePage = "H" + }; + s.HomePage.Should().Be("H"); + } +} diff --git a/Tests/EqSamples.Tests/RazorAdvancedSearch/PageModelsTests.cs b/Tests/EqSamples.Tests/RazorAdvancedSearch/PageModelsTests.cs new file mode 100644 index 00000000..7570cde6 --- /dev/null +++ b/Tests/EqSamples.Tests/RazorAdvancedSearch/PageModelsTests.cs @@ -0,0 +1,43 @@ +extern alias RazorAdvSearch; + +using FluentAssertions; +using Microsoft.Extensions.Logging; +using Moq; +using RazorIndexModel = RazorAdvSearch::EqDemo.Pages.IndexModel; +using RazorPrivacyModel = RazorAdvSearch::EqDemo.Pages.PrivacyModel; +using RazorAboutModel = RazorAdvSearch::EqDemo.Pages.AboutModel; + +namespace EqSamples.Tests.RazorAdvancedSearch; + +public class PageModelsTests +{ + [Fact] + public void IndexModel_OnGet_DoesNotThrow() + { + var logger = new Mock>(); + var model = new RazorIndexModel(logger.Object); + + var exception = Record.Exception(() => model.OnGet()); + exception.Should().BeNull(); + } + + [Fact] + public void PrivacyModel_OnGet_DoesNotThrow() + { + var logger = new Mock>(); + var model = new RazorPrivacyModel(logger.Object); + + var exception = Record.Exception(() => model.OnGet()); + exception.Should().BeNull(); + } + + [Fact] + public void AboutModel_OnGet_DoesNotThrow() + { + var logger = new Mock>(); + var model = new RazorAboutModel(logger.Object); + + var exception = Record.Exception(() => model.OnGet()); + exception.Should().BeNull(); + } +} diff --git a/Tests/EqSamples.Tests/RazorAdvancedSearch/ValuesControllerTests.cs b/Tests/EqSamples.Tests/RazorAdvancedSearch/ValuesControllerTests.cs new file mode 100644 index 00000000..00ffa996 --- /dev/null +++ b/Tests/EqSamples.Tests/RazorAdvancedSearch/ValuesControllerTests.cs @@ -0,0 +1,32 @@ +extern alias RazorAdvSearch; + +using FluentAssertions; +using RazorValuesController = RazorAdvSearch::EqDemo.AspNetCoreRazor.AdvancedSearch.ValuesController; + +namespace EqSamples.Tests.RazorAdvancedSearch; + +public class ValuesControllerTests +{ + [Fact] + public void GetList1_ReturnsThreeItems() + { + var controller = new RazorValuesController(); + + var result = controller.GetList1(); + + result.Should().HaveCount(3); + } + + [Fact] + public void GetList1_ItemsAreNotNull() + { + var controller = new RazorValuesController(); + + var result = controller.GetList1().ToList(); + + foreach (var item in result) + { + item.Should().NotBeNull(); + } + } +} diff --git a/Tests/EqSamples.Tests/RazorDataFiltering/AppDbContextTests.cs b/Tests/EqSamples.Tests/RazorDataFiltering/AppDbContextTests.cs new file mode 100644 index 00000000..ff78f034 --- /dev/null +++ b/Tests/EqSamples.Tests/RazorDataFiltering/AppDbContextTests.cs @@ -0,0 +1,99 @@ +extern alias RazorDataFilter; + +using FluentAssertions; +using Microsoft.EntityFrameworkCore; +using RazorAppDbContext = RazorDataFilter::EqDemo.AppDbContext; +using RazorOrder = RazorDataFilter::EqDemo.Models.Order; +using RazorCustomer = RazorDataFilter::EqDemo.Models.Customer; +using RazorEmployee = RazorDataFilter::EqDemo.Models.Employee; +using RazorOrderDetail = RazorDataFilter::EqDemo.Models.OrderDetail; + +namespace EqSamples.Tests.RazorDataFiltering; + +public class AppDbContextTests +{ + private RazorAppDbContext CreateContext() + { + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase($"RazorDataFilter_{Guid.NewGuid()}") + .Options; + return new RazorAppDbContext(options); + } + + [Fact] + public void DbContext_HasAllDbSets() + { + using var context = CreateContext(); + + context.Categories.Should().NotBeNull(); + context.Customers.Should().NotBeNull(); + context.Employees.Should().NotBeNull(); + context.Orders.Should().NotBeNull(); + context.Products.Should().NotBeNull(); + context.OrderDetails.Should().NotBeNull(); + context.Shippers.Should().NotBeNull(); + context.Suppliers.Should().NotBeNull(); + } + + [Fact] + public async Task DbContext_CanCRUD_Order() + { + using var context = CreateContext(); + + var order = new RazorOrder { Id = 1, ShipName = "Test" }; + context.Orders.Add(order); + await context.SaveChangesAsync(); + + var retrieved = await context.Orders.FindAsync(1); + retrieved.Should().NotBeNull(); + + retrieved!.ShipName = "Updated"; + context.Update(retrieved); + await context.SaveChangesAsync(); + + var updated = await context.Orders.FindAsync(1); + updated!.ShipName.Should().Be("Updated"); + + context.Orders.Remove(updated); + await context.SaveChangesAsync(); + (await context.Orders.FindAsync(1)).Should().BeNull(); + } + + [Fact] + public async Task DbContext_OrderDetail_CompositeKey_Works() + { + using var context = CreateContext(); + + context.OrderDetails.Add(new RazorOrderDetail { OrderID = 1, ProductID = 1, UnitPrice = 10, Quantity = 1, Discount = 0 }); + context.OrderDetails.Add(new RazorOrderDetail { OrderID = 1, ProductID = 2, UnitPrice = 20, Quantity = 2, Discount = 0 }); + await context.SaveChangesAsync(); + + (await context.OrderDetails.CountAsync()).Should().Be(2); + (await context.OrderDetails.FindAsync(1, 2)).Should().NotBeNull(); + } + + [Fact] + public async Task DbContext_Models_NavigationProperties() + { + using var context = CreateContext(); + + var customer = new RazorCustomer { Id = "C1", CompanyName = "TestCo" }; + var employee = new RazorEmployee { Id = 1, FirstName = "John", LastName = "Doe" }; + var order = new RazorOrder { Id = 1, CustomerID = "C1", EmployeeID = 1 }; + + context.Customers.Add(customer); + context.Employees.Add(employee); + context.Orders.Add(order); + await context.SaveChangesAsync(); + + var loaded = await context.Orders + .Include(o => o.Customer) + .Include(o => o.Employee) + .FirstAsync(o => o.Id == 1); + + loaded.Customer.Should().NotBeNull(); + loaded.Customer!.CompanyName.Should().Be("TestCo"); + loaded.Employee.Should().NotBeNull(); + loaded.Employee!.FullName.Should().Be("John Doe"); + } +} diff --git a/Tests/EqSamples.Tests/RazorDataFiltering/ErrorModelTests.cs b/Tests/EqSamples.Tests/RazorDataFiltering/ErrorModelTests.cs new file mode 100644 index 00000000..0ae103d3 --- /dev/null +++ b/Tests/EqSamples.Tests/RazorDataFiltering/ErrorModelTests.cs @@ -0,0 +1,45 @@ +extern alias RazorDataFilter; + +using FluentAssertions; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; +using Moq; +using RazorErrorModel = RazorDataFilter::EqDemo.Pages.ErrorModel; + +namespace EqSamples.Tests.RazorDataFiltering; + +public class ErrorModelTests +{ + [Fact] + public void ShowRequestId_ReturnsTrue_WhenSet() + { + var logger = new Mock>(); + var model = new RazorErrorModel(logger.Object); + model.RequestId = "x"; + model.ShowRequestId.Should().BeTrue(); + } + + [Fact] + public void ShowRequestId_ReturnsFalse_WhenNull() + { + var logger = new Mock>(); + var model = new RazorErrorModel(logger.Object); + model.RequestId = null; + model.ShowRequestId.Should().BeFalse(); + } + + [Fact] + public void OnGet_SetsRequestId() + { + var logger = new Mock>(); + var model = new RazorErrorModel(logger.Object); + var httpContext = new DefaultHttpContext(); + httpContext.TraceIdentifier = "trace-2"; + model.PageContext = new PageContext { HttpContext = httpContext }; + + model.OnGet(); + + model.RequestId.Should().NotBeNullOrEmpty(); + } +} diff --git a/Tests/EqSamples.Tests/RazorDataFiltering/ModelsTests.cs b/Tests/EqSamples.Tests/RazorDataFiltering/ModelsTests.cs new file mode 100644 index 00000000..0a68537c --- /dev/null +++ b/Tests/EqSamples.Tests/RazorDataFiltering/ModelsTests.cs @@ -0,0 +1,146 @@ +extern alias RazorDataFilter; + +using FluentAssertions; +using RazorOrder = RazorDataFilter::EqDemo.Models.Order; +using RazorCustomer = RazorDataFilter::EqDemo.Models.Customer; +using RazorEmployee = RazorDataFilter::EqDemo.Models.Employee; +using RazorProduct = RazorDataFilter::EqDemo.Models.Product; +using RazorCategory = RazorDataFilter::EqDemo.Models.Category; +using RazorOrderDetail = RazorDataFilter::EqDemo.Models.OrderDetail; +using RazorShipper = RazorDataFilter::EqDemo.Models.Shipper; +using RazorSupplier = RazorDataFilter::EqDemo.Models.Supplier; + +namespace EqSamples.Tests.RazorDataFiltering; + +public class ModelsTests +{ + [Fact] + public void Order_AllProperties() + { + var c = new RazorCustomer { Id = "C1" }; + var e = new RazorEmployee { Id = 1 }; + var o = new RazorOrder + { + Id = 1, OrderDate = DateTime.Now, RequiredDate = DateTime.Now, + ShippedDate = DateTime.Now, Freight = 10m, CustomerID = "C1", + Customer = c, EmployeeID = 1, Employee = e, + Items = new List(), + ShipVia = 1, ShipName = "S", ShipAddress = "A", + ShipCity = "C", ShipRegion = "R", ShipPostalCode = "P", + ShipCountry = "Co" + }; + o.ShipName.Should().Be("S"); + o.Customer.Should().BeSameAs(c); + } + + [Fact] + public void Employee_FullName_CombinesNames() + { + var emp = new RazorEmployee { FirstName = "A", LastName = "B" }; + emp.FullName.Should().Be("A B"); + } + + [Fact] + public void Employee_FullName_EmptyFirst() + { + var emp = new RazorEmployee { FirstName = "", LastName = "B" }; + emp.FullName.Should().Be("B"); + } + + [Fact] + public void Employee_FullName_NullFirst() + { + var emp = new RazorEmployee { FirstName = null, LastName = "B" }; + emp.FullName.Should().Be("B"); + } + + [Fact] + public void Employee_AllProperties() + { + var mgr = new RazorEmployee { Id = 2 }; + var emp = new RazorEmployee + { + Id = 1, FirstName = "J", LastName = "D", Title = "T", + TitleOfCourtesy = "Mr.", BirthDate = DateTime.Now, + HireDate = DateTime.Now, Address = "A", City = "C", + Region = "R", PostalCode = "P", Country = "Co", + HomePhone = "H", Extension = "E", + Photo = new byte[] { 1 }, PhotoPath = "/p", + Notes = "N", ReportsTo = 2, Manager = mgr, + Orders = new List() + }; + emp.Title.Should().Be("T"); + emp.Manager.Should().BeSameAs(mgr); + } + + [Fact] + public void Customer_AllProperties() + { + var c = new RazorCustomer + { + Id = "X", CompanyName = "C", Address = "A", City = "Ci", + Region = "R", PostalCode = "P", Country = "Co", + ContactName = "CN", ContactTitle = "CT", Phone = "Ph", Fax = "F" + }; + c.CompanyName.Should().Be("C"); + } + + [Fact] + public void Product_AllProperties() + { + var cat = new RazorCategory { Id = 1 }; + var sup = new RazorSupplier { Id = 1 }; + var p = new RazorProduct + { + Id = 1, Name = "P", QuantityPerUnit = "Q", UnitPrice = 10m, + UnitsInStock = 5, UnitsOnOrder = 2, ReorderLevel = 1, + Discontinued = true, CategoryID = 1, Category = cat, + SupplierID = 1, Supplier = sup + }; + p.Discontinued.Should().BeTrue(); + } + + [Fact] + public void Category_AllProperties() + { + var c = new RazorCategory + { + Id = 1, CategoryName = "B", Description = "D", + Picture = new byte[] { 1 } + }; + c.CategoryName.Should().Be("B"); + } + + [Fact] + public void OrderDetail_AllProperties() + { + var o = new RazorOrder { Id = 1 }; + var p = new RazorProduct { Id = 1 }; + var d = new RazorOrderDetail + { + OrderID = 1, Order = o, ProductID = 1, Product = p, + UnitPrice = 10m, Quantity = 5, Discount = 0.1f + }; + d.Order.Should().BeSameAs(o); + d.Product.Should().BeSameAs(p); + } + + [Fact] + public void Shipper_AllProperties() + { + var s = new RazorShipper { Id = 1, CompanyName = "S", Phone = "P" }; + s.CompanyName.Should().Be("S"); + } + + [Fact] + public void Supplier_AllProperties() + { + var s = new RazorSupplier + { + Id = 1, CompanyName = "S", ContactName = "C", ContactTitle = "T", + Address = "A", City = "Ci", Region = "R", PostalCode = "P", + Country = "Co", Phone = "Ph", Fax = "F", HomePage = "H" + }; + s.HomePage.Should().Be("H"); + } +} diff --git a/Tests/EqSamples.Tests/RazorDataFiltering/PageModelsTests.cs b/Tests/EqSamples.Tests/RazorDataFiltering/PageModelsTests.cs new file mode 100644 index 00000000..c829fe9b --- /dev/null +++ b/Tests/EqSamples.Tests/RazorDataFiltering/PageModelsTests.cs @@ -0,0 +1,54 @@ +extern alias RazorDataFilter; + +using FluentAssertions; +using Microsoft.Extensions.Logging; +using Moq; +using RazorIndexModel = RazorDataFilter::EqDemo.Pages.IndexModel; +using RazorPrivacyModel = RazorDataFilter::EqDemo.Pages.PrivacyModel; +using RazorErrorViewModel = RazorDataFilter::EqDemo.Models.ErrorViewModel; + +namespace EqSamples.Tests.RazorDataFiltering; + +public class PageModelsTests +{ + [Fact] + public void IndexModel_OnGet_DoesNotThrow() + { + var logger = new Mock>(); + var model = new RazorIndexModel(logger.Object); + + var exception = Record.Exception(() => model.OnGet()); + exception.Should().BeNull(); + } + + [Fact] + public void PrivacyModel_OnGet_DoesNotThrow() + { + var logger = new Mock>(); + var model = new RazorPrivacyModel(logger.Object); + + var exception = Record.Exception(() => model.OnGet()); + exception.Should().BeNull(); + } + + [Fact] + public void ErrorViewModel_ShowRequestId_ReturnsTrue_WhenIdSet() + { + var model = new RazorErrorViewModel { RequestId = "req-123" }; + model.ShowRequestId.Should().BeTrue(); + } + + [Fact] + public void ErrorViewModel_ShowRequestId_ReturnsFalse_WhenIdNull() + { + var model = new RazorErrorViewModel { RequestId = null }; + model.ShowRequestId.Should().BeFalse(); + } + + [Fact] + public void ErrorViewModel_ShowRequestId_ReturnsFalse_WhenIdEmpty() + { + var model = new RazorErrorViewModel { RequestId = "" }; + model.ShowRequestId.Should().BeFalse(); + } +}