diff --git a/AutoCrudAdmin.Demo.sln b/AutoCrudAdmin.Demo.sln index ce72b94..6085da8 100644 --- a/AutoCrudAdmin.Demo.sln +++ b/AutoCrudAdmin.Demo.sln @@ -18,6 +18,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Analyzers", "Analyzers", "{ Analyzers\stylecop.json = Analyzers\stylecop.json EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{8D4B258F-4B65-42AC-9A42-0F2254F12CCC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoCrudAdmin.Tests", "tests\AutoCrudAdmin.Tests\AutoCrudAdmin.Tests.csproj", "{1FB1ED95-D654-4BA1-B73E-630714A99665}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoCrudAdmin.Demo.SqlServer.Tests", "tests\AutoCrudAdmin.Demo.SqlServer.Tests\AutoCrudAdmin.Demo.SqlServer.Tests.csproj", "{4526F658-4DE7-4B43-9461-6B43E8A6ADF3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -44,11 +50,21 @@ Global {24C3C7CC-79CF-4498-A7F8-B4B4C4E0F4C9}.Debug|Any CPU.Build.0 = Debug|Any CPU {24C3C7CC-79CF-4498-A7F8-B4B4C4E0F4C9}.Release|Any CPU.ActiveCfg = Release|Any CPU {24C3C7CC-79CF-4498-A7F8-B4B4C4E0F4C9}.Release|Any CPU.Build.0 = Release|Any CPU + {1FB1ED95-D654-4BA1-B73E-630714A99665}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1FB1ED95-D654-4BA1-B73E-630714A99665}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1FB1ED95-D654-4BA1-B73E-630714A99665}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1FB1ED95-D654-4BA1-B73E-630714A99665}.Release|Any CPU.Build.0 = Release|Any CPU + {4526F658-4DE7-4B43-9461-6B43E8A6ADF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4526F658-4DE7-4B43-9461-6B43E8A6ADF3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4526F658-4DE7-4B43-9461-6B43E8A6ADF3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4526F658-4DE7-4B43-9461-6B43E8A6ADF3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {32BFD1FE-2923-468D-93C0-7FED0FCC2F77} = {54C80D9E-2664-431C-A8AC-0D490C119760} {F9DC587B-E2AF-48D8-8A26-AACBC2F268D8} = {54C80D9E-2664-431C-A8AC-0D490C119760} {4A584F16-FABE-4D30-AC34-958D04E5CDDE} = {54C80D9E-2664-431C-A8AC-0D490C119760} {24C3C7CC-79CF-4498-A7F8-B4B4C4E0F4C9} = {54C80D9E-2664-431C-A8AC-0D490C119760} + {1FB1ED95-D654-4BA1-B73E-630714A99665} = {8D4B258F-4B65-42AC-9A42-0F2254F12CCC} + {4526F658-4DE7-4B43-9461-6B43E8A6ADF3} = {8D4B258F-4B65-42AC-9A42-0F2254F12CCC} EndGlobalSection EndGlobal diff --git a/src/AutoCrudAdmin/AutoCrudAdmin.csproj b/src/AutoCrudAdmin/AutoCrudAdmin.csproj index 1a03b3f..c0c96d1 100644 --- a/src/AutoCrudAdmin/AutoCrudAdmin.csproj +++ b/src/AutoCrudAdmin/AutoCrudAdmin.csproj @@ -1,75 +1,79 @@  - - net6.0 - Library - AutoCrudAdmin - 1.1.26 - Doncho Minkov - Minkov - true - true - README.md - https://github.com/Minkov/AutoCrudAdmin - git - + + net6.0 + Library + AutoCrudAdmin + 1.1.26 + Doncho Minkov + Minkov + true + true + README.md + https://github.com/Minkov/AutoCrudAdmin + git + - - - - + + + + - - - - - + + + + + - - <_ContentIncludedByDefault Remove="Pages\Admin\Index.cshtml"/> - <_ContentIncludedByDefault Remove="Views\ProjectsAdmin\Index.cshtml"/> - <_ContentIncludedByDefault Remove="wwwroot\css\mvc-grid.css"/> - <_ContentIncludedByDefault Remove="wwwroot\css\site.css"/> - <_ContentIncludedByDefault Remove="wwwroot\favicon.ico"/> - <_ContentIncludedByDefault Remove="wwwroot\js\mvc-grid.js"/> - <_ContentIncludedByDefault Remove="wwwroot\js\site.js"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\css\bootstrap-grid.css"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\css\bootstrap-grid.css.map"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\css\bootstrap-grid.min.css"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\css\bootstrap-grid.min.css.map"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\css\bootstrap-reboot.css"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\css\bootstrap-reboot.css.map"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\css\bootstrap-reboot.min.css"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\css\bootstrap-reboot.min.css.map"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\css\bootstrap.css"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\css\bootstrap.css.map"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\css\bootstrap.min.css"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\css\bootstrap.min.css.map"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\js\bootstrap.bundle.js"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\js\bootstrap.bundle.js.map"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\js\bootstrap.bundle.min.js"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\js\bootstrap.bundle.min.js.map"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\js\bootstrap.js"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\js\bootstrap.js.map"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\js\bootstrap.min.js"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\js\bootstrap.min.js.map"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\LICENSE"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\jquery-validation-unobtrusive\jquery.validate.unobtrusive.js"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\jquery-validation-unobtrusive\jquery.validate.unobtrusive.min.js"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\jquery-validation-unobtrusive\LICENSE.txt"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\jquery-validation\dist\additional-methods.js"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\jquery-validation\dist\additional-methods.min.js"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\jquery-validation\dist\jquery.validate.js"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\jquery-validation\dist\jquery.validate.min.js"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\jquery-validation\LICENSE.md"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\jquery\dist\jquery.js"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\jquery\dist\jquery.min.js"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\jquery\dist\jquery.min.map"/> - <_ContentIncludedByDefault Remove="wwwroot\lib\jquery\LICENSE.txt"/> - + + + - - - + + <_ContentIncludedByDefault Remove="Pages\Admin\Index.cshtml"/> + <_ContentIncludedByDefault Remove="Views\ProjectsAdmin\Index.cshtml"/> + <_ContentIncludedByDefault Remove="wwwroot\css\mvc-grid.css"/> + <_ContentIncludedByDefault Remove="wwwroot\css\site.css"/> + <_ContentIncludedByDefault Remove="wwwroot\favicon.ico"/> + <_ContentIncludedByDefault Remove="wwwroot\js\mvc-grid.js"/> + <_ContentIncludedByDefault Remove="wwwroot\js\site.js"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\css\bootstrap-grid.css"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\css\bootstrap-grid.css.map"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\css\bootstrap-grid.min.css"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\css\bootstrap-grid.min.css.map"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\css\bootstrap-reboot.css"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\css\bootstrap-reboot.css.map"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\css\bootstrap-reboot.min.css"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\css\bootstrap-reboot.min.css.map"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\css\bootstrap.css"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\css\bootstrap.css.map"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\css\bootstrap.min.css"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\css\bootstrap.min.css.map"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\js\bootstrap.bundle.js"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\js\bootstrap.bundle.js.map"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\js\bootstrap.bundle.min.js"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\js\bootstrap.bundle.min.js.map"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\js\bootstrap.js"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\js\bootstrap.js.map"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\js\bootstrap.min.js"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\dist\js\bootstrap.min.js.map"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\bootstrap\LICENSE"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\jquery-validation-unobtrusive\jquery.validate.unobtrusive.js"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\jquery-validation-unobtrusive\jquery.validate.unobtrusive.min.js"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\jquery-validation-unobtrusive\LICENSE.txt"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\jquery-validation\dist\additional-methods.js"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\jquery-validation\dist\additional-methods.min.js"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\jquery-validation\dist\jquery.validate.js"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\jquery-validation\dist\jquery.validate.min.js"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\jquery-validation\LICENSE.md"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\jquery\dist\jquery.js"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\jquery\dist\jquery.min.js"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\jquery\dist\jquery.min.map"/> + <_ContentIncludedByDefault Remove="wwwroot\lib\jquery\LICENSE.txt"/> + + + + + diff --git a/src/AutoCrudAdmin/Helpers/ReflectionHelper.cs b/src/AutoCrudAdmin/Helpers/ReflectionHelper.cs index 00ce5c9..e55cdc7 100644 --- a/src/AutoCrudAdmin/Helpers/ReflectionHelper.cs +++ b/src/AutoCrudAdmin/Helpers/ReflectionHelper.cs @@ -58,19 +58,19 @@ private static IEnumerable GetDbSetProperties() .ToList(); var entityTypes = dbSetTypes - .Select(dbSet => dbSet.PropertyType.GenericTypeArguments.FirstOrDefault()) + .Select(dbSet => dbSet.PropertyType.GenericTypeArguments.First()) .Distinct() .ToHashSet(); var uniqueEntityTypes = entityTypes .Where(parent => - parent?.IsGenericParameter == true - && entityTypes.All(child => child?.IsSubclassOfAnyType(parent) != true)) + !parent.IsGenericParameter + && !entityTypes.Any(child => child.IsSubclassOfAnyType(parent))) .ToHashSet(); return dbSetTypes .DistinctBy(x => x.PropertyType.GenericTypeArguments.FirstOrDefault()) - .Where(x => uniqueEntityTypes.Contains(x.PropertyType.GenericTypeArguments.FirstOrDefault())) + .Where(x => uniqueEntityTypes.Contains(x.PropertyType.GenericTypeArguments.First())) .OrderBy(x => x.Name) .ToList(); } diff --git a/src/AutoCrudAdmin/Views/Shared/MvcGrid/_Grid.cshtml b/src/AutoCrudAdmin/Views/Shared/MvcGrid/_Grid.cshtml index d27f3af..7949761 100644 --- a/src/AutoCrudAdmin/Views/Shared/MvcGrid/_Grid.cshtml +++ b/src/AutoCrudAdmin/Views/Shared/MvcGrid/_Grid.cshtml @@ -10,14 +10,14 @@ }
- + @foreach (var column in Model.Columns) { var applied = (column.Filter.First ?? column.Filter.Second) == null ? "" : " applied"; - + @if (column.Filter.IsEnabled == true && !String.IsNullOrEmpty(column.Filter.Name) && Model.FilterMode != GridFilterMode.Row) { if (Model.FilterMode == GridFilterMode.Header) @@ -138,7 +138,7 @@ @foreach (var row in rows) { - + @foreach (var column in Model.Columns) { var classes = (column.IsHidden ? column.CssClasses + " mvc-grid-hidden" : column.CssClasses).Trim(); diff --git a/tests/AutoCrudAdmin.Demo.SqlServer.Tests/AutoCrudAdmin.Demo.SqlServer.Tests.csproj b/tests/AutoCrudAdmin.Demo.SqlServer.Tests/AutoCrudAdmin.Demo.SqlServer.Tests.csproj new file mode 100644 index 0000000..2d4ea74 --- /dev/null +++ b/tests/AutoCrudAdmin.Demo.SqlServer.Tests/AutoCrudAdmin.Demo.SqlServer.Tests.csproj @@ -0,0 +1,30 @@ + + + + net6.0 + enable + SA1600 + + + + + Never + + + + + + + + + + + + + + + + + + + diff --git a/tests/AutoCrudAdmin.Demo.SqlServer.Tests/Controllers/ProjectsControllerTests.cs b/tests/AutoCrudAdmin.Demo.SqlServer.Tests/Controllers/ProjectsControllerTests.cs new file mode 100644 index 0000000..aa02c1a --- /dev/null +++ b/tests/AutoCrudAdmin.Demo.SqlServer.Tests/Controllers/ProjectsControllerTests.cs @@ -0,0 +1,65 @@ +namespace AutoCrudAdmin.Demo.SqlServer.Tests.Controllers; + +using System; +using System.Collections.Generic; +using System.Globalization; +using FluentAssertions; +using Models.Models; +using MyTested.AspNetCore.Mvc; +using SqlServer.Controllers; +using ViewModels; +using Xunit; + +public class ProjectsControllerTests +{ + [Fact] + public void IndexShouldReturnDefaultViewWithCorrectModel() + => MyController + .Instance() + .Calling(c => c.Index()) + .ShouldReturn() + .View("../AutoCrudAdmin/Index"); + + [Fact] + public void GetCreate_ReturnsViewResult() + => MyController + .Instance() + .Calling(c => c.Create( + new Dictionary(), + null)) + .ShouldReturn() + .View("../AutoCrudAdmin/EntityForm"); + + [Theory] + [InlineData("Test Project")] + public void PostCreate_SavesAndRedirects(string name) + => MyPipeline + .Configuration() + .ShouldMap(request => request + .WithMethod(HttpMethod.Post) + .WithLocation("/Projects/PostCreate") + .WithAntiForgeryToken() + .WithFormFields(new Dictionary + { + { nameof(Project.Name), name }, + { nameof(Project.OpenDate), DateTime.Now.ToString(CultureInfo.CurrentCulture) }, + { nameof(Project.DueDate), DateTime.Now.AddDays(1).ToString(CultureInfo.CurrentCulture) }, + })) + .To(c => c.PostCreate( + new Dictionary + { + { nameof(Project.Name), name }, + { nameof(Project.OpenDate), DateTime.Now.ToString(CultureInfo.CurrentCulture) }, + { nameof(Project.DueDate), DateTime.Now.AddDays(1).ToString(CultureInfo.CurrentCulture) }, + }, + new FormFilesContainer())) + .Which() + .ShouldHave() + .Data(data => data + .WithSet(set => set + .Should() + .ContainSingle(p => p.Name == name))) + .AndAlso() + .ShouldReturn() + .RedirectToAction("Index"); +} \ No newline at end of file diff --git a/tests/AutoCrudAdmin.Demo.SqlServer.Tests/Controllers/TasksControllerTests.cs b/tests/AutoCrudAdmin.Demo.SqlServer.Tests/Controllers/TasksControllerTests.cs new file mode 100644 index 0000000..b6964af --- /dev/null +++ b/tests/AutoCrudAdmin.Demo.SqlServer.Tests/Controllers/TasksControllerTests.cs @@ -0,0 +1,29 @@ +namespace AutoCrudAdmin.Demo.SqlServer.Tests.Controllers; + +using System.Collections.Generic; +using MyTested.AspNetCore.Mvc; +using SqlServer.Controllers; +using ViewModels.Pages; +using Xunit; + +public class TasksControllerTests +{ + [Fact] + public void IndexShouldReturnDefaultViewWithCorrectModel() + => MyController + .Instance() + .Calling(c => c.Index()) + .ShouldReturn() + .View(view => view + .WithModelOfType()); + + [Fact] + public void GetCreate_ReturnsViewResult() + => MyController + .Instance() + .Calling(c => c.Create( + new Dictionary(), + null)) + .ShouldReturn() + .View("../AutoCrudAdmin/EntityForm"); +} \ No newline at end of file diff --git a/tests/AutoCrudAdmin.Demo.SqlServer.Tests/Data/ProjectTestData.cs b/tests/AutoCrudAdmin.Demo.SqlServer.Tests/Data/ProjectTestData.cs new file mode 100644 index 0000000..a5b084b --- /dev/null +++ b/tests/AutoCrudAdmin.Demo.SqlServer.Tests/Data/ProjectTestData.cs @@ -0,0 +1,27 @@ +namespace AutoCrudAdmin.Demo.SqlServer.Tests.Data; + +using System; +using System.Collections.Generic; +using System.Linq; +using Bogus; +using Models.Models; + +public static class ProjectTestData +{ + public static Project GetProject(int id) + => new Faker() + .CustomInstantiator(_ => new Project + { + Id = id, + Name = $"Project {id}", + OpenDate = DateTime.Now, + DueDate = DateTime.Now.AddDays(1), + }) + .Generate(); + + public static List GetProjects(int total) + => Enumerable + .Range(1, total) + .Select(GetProject) + .ToList(); +} \ No newline at end of file diff --git a/tests/AutoCrudAdmin.Demo.SqlServer.Tests/Data/TaskTestData.cs b/tests/AutoCrudAdmin.Demo.SqlServer.Tests/Data/TaskTestData.cs new file mode 100644 index 0000000..22c64ef --- /dev/null +++ b/tests/AutoCrudAdmin.Demo.SqlServer.Tests/Data/TaskTestData.cs @@ -0,0 +1,30 @@ +namespace AutoCrudAdmin.Demo.SqlServer.Tests.Data; + +using System; +using System.Collections.Generic; +using System.Linq; +using Bogus; +using Models.Models; + +public static class TaskTestData +{ + public static Task GetTask(int id, int projectId) + => new Faker() + .CustomInstantiator(f => new Task + { + Id = id, + Name = $"Task {id}", + OpenDate = DateTime.Now, + DueDate = DateTime.Now.AddDays(1), + LabelType = f.PickRandom(), + ExecutionType = f.PickRandom(), + ProjectId = projectId, + }) + .Generate(); + + public static List GetTasks(int total, int totalProjects) + => Enumerable + .Range(1, total) + .Select(i => GetTask(i, new Faker().Random.Number(1, totalProjects))) + .ToList(); +} \ No newline at end of file diff --git a/tests/AutoCrudAdmin.Demo.SqlServer.Tests/TestStartup.cs b/tests/AutoCrudAdmin.Demo.SqlServer.Tests/TestStartup.cs new file mode 100644 index 0000000..611f248 --- /dev/null +++ b/tests/AutoCrudAdmin.Demo.SqlServer.Tests/TestStartup.cs @@ -0,0 +1,5 @@ +namespace AutoCrudAdmin.Demo.SqlServer.Tests; + +public class TestStartup : Startup +{ +} \ No newline at end of file diff --git a/tests/AutoCrudAdmin.Demo.SqlServer.Tests/testsettings.json b/tests/AutoCrudAdmin.Demo.SqlServer.Tests/testsettings.json new file mode 100644 index 0000000..8593c62 --- /dev/null +++ b/tests/AutoCrudAdmin.Demo.SqlServer.Tests/testsettings.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/tests/AutoCrudAdmin.Tests/AutoCrudAdmin.Tests.csproj b/tests/AutoCrudAdmin.Tests/AutoCrudAdmin.Tests.csproj new file mode 100644 index 0000000..3d6cc4b --- /dev/null +++ b/tests/AutoCrudAdmin.Tests/AutoCrudAdmin.Tests.csproj @@ -0,0 +1,23 @@ + + + + net6.0 + enable + SA1600 + + + + + + + + + + + + + + + + + diff --git a/tests/AutoCrudAdmin.Tests/Extensions/DbContextExtensionsTests.cs b/tests/AutoCrudAdmin.Tests/Extensions/DbContextExtensionsTests.cs new file mode 100644 index 0000000..62fc316 --- /dev/null +++ b/tests/AutoCrudAdmin.Tests/Extensions/DbContextExtensionsTests.cs @@ -0,0 +1,26 @@ +namespace AutoCrudAdmin.Tests.Extensions; + +using System.Linq; +using AutoCrudAdmin.Extensions; +using Demo.Models.Models; +using FluentAssertions; +using Infrastructure; +using Xunit; + +public class DbContextExtensionsTests : TestsWithData +{ + [Fact] + public void Set_ReturnsQueryableOfGivenType() + { + // Arrange + var entityType = typeof(Project); + + // Act + var result = this.Data.Set(entityType); + + // Assert + result.Should().NotBeNull(); + result.Should().BeAssignableTo>(); + result.ElementType.Should().Be(entityType); + } +} \ No newline at end of file diff --git a/tests/AutoCrudAdmin.Tests/Extensions/StringExtensionsTests.cs b/tests/AutoCrudAdmin.Tests/Extensions/StringExtensionsTests.cs new file mode 100644 index 0000000..6948ef9 --- /dev/null +++ b/tests/AutoCrudAdmin.Tests/Extensions/StringExtensionsTests.cs @@ -0,0 +1,66 @@ +namespace AutoCrudAdmin.Tests.Extensions; + +using AutoCrudAdmin.Extensions; +using FluentAssertions; +using Xunit; + +public class StringExtensionsTests +{ + [Theory] + [InlineData("PascalCase", "pascal-case")] + [InlineData("camelCase", "camel-case")] + public void ToHyphenSeparatedWords_ReturnsExpected(string input, string expected) + { + // Act + var result = input.ToHyphenSeparatedWords(); + + // Assert + result.Should().Be(expected); + } + + [Theory] + [InlineData("PascalCase", "Pascal Case")] + public void ToSpaceSeparatedWords_ReturnsExpected(string input, string expected) + { + // Act + var result = input.ToSpaceSeparatedWords(); + + // Assert + result.Should().Be(expected); + } + + [Theory] + [InlineData("TestController", "Test")] + [InlineData("ProductsController", "Products")] + [InlineData("AdminController", "Admin")] + public void ToControllerBaseUri_RemovesControllerSuffix(string input, string expected) + { + // Act + var result = input.ToControllerBaseUri(); + + // Assert + result.Should().Be(expected); + } + + [Theory] + [InlineData("This is a very long string", 5)] + public void ToEllipsis_ShortensString(string input, int maxLength) + { + // Act + var result = input.ToEllipsis(maxLength); + + // Assert + result.Should().Be("Thi..."); + } + + [Theory] + [InlineData("Short", 10)] + public void ToEllipsis_ReturnsOriginalIfShorter(string input, int maxLength) + { + // Act + var result = input.ToEllipsis(maxLength); + + // Assert + result.Should().Be("Short"); + } +} \ No newline at end of file diff --git a/tests/AutoCrudAdmin.Tests/Extensions/TypeExtensionsTests.cs b/tests/AutoCrudAdmin.Tests/Extensions/TypeExtensionsTests.cs new file mode 100644 index 0000000..21db01a --- /dev/null +++ b/tests/AutoCrudAdmin.Tests/Extensions/TypeExtensionsTests.cs @@ -0,0 +1,176 @@ +namespace AutoCrudAdmin.Tests.Extensions; + +using System.Collections.Generic; +using AutoCrudAdmin.Extensions; +using Demo.Models.Models; +using FluentAssertions; +using Infrastructure; +using Xunit; + +public class TypeExtensionsTests : TestsWithData +{ + [Fact] + public void GetPrimaryKeyPropertyInfos_ReturnsExpected() + { + // Arrange + var type = typeof(Project); + + // Act + var result = type.GetPrimaryKeyPropertyInfos(); + + // Assert + result.Should().Contain(p => p.Name == nameof(Project.Id)); + } + + [Theory] + [InlineData(1)] + public void GetPrimaryKeyValue_ReturnsExpected(int id) + { + // Arrange + var entity = new Project { Id = id }; + + // Act + var result = typeof(Project).GetPrimaryKeyValue(entity); + + // Assert + result.Should().AllSatisfy(item => + { + item.Key.Should().Be(Constants.Entity.SinglePrimaryKeyName); + item.Value.Should().Be(id); + }); + } + + [Fact] + public void IsSubclassOfRawGeneric_ShouldDetectsSubclass() + { + // Arrange + var subtype = typeof(TestSubEntity); + var baseType = typeof(TestBaseEntity<>); + + // Act + var result = subtype.IsSubclassOfRawGeneric(baseType); + + // Assert + result.Should().BeTrue(); + } + + [Fact] + public void IsSubclassOfRawGeneric_ShouldReturnFalseForSameType() + { + // Arrange + var type = typeof(TestBaseEntity<>); + + // Act + var result = type.IsSubclassOfRawGeneric(type); + + // Assert + result.Should().BeFalse(); + } + + [Fact] + public void IsSubclassOfAnyType_DetectsSubclasses() + { + // Arrange + var subclass = typeof(TestSubEntity); + var baseClass = typeof(TestBaseEntity); + var genericBaseClass = typeof(TestBaseEntity<>); + + // Act + var result1 = subclass.IsSubclassOfAnyType(baseClass); + var result2 = subclass.IsSubclassOfAnyType(genericBaseClass); + + // Assert + result1.Should().BeTrue(); // Subclass of direct base class + result2.Should().BeTrue(); // Subclass of generic base class + } + + [Fact] + public void IsSubclassOfAnyType_ReturnsFalseWhenNoRelation() + { + // Arrange + var type1 = typeof(TestBaseEntity); + var type2 = typeof(Project); + + // Act + var result = type1.IsSubclassOfAnyType(type2); + + // Assert + Assert.False(result); + } + + [Fact] + public void IsNavigationProperty_DetectsNavigationTypes() + { + // Arrange + var navigationType = typeof(ICollection); + var nonNavigationType = typeof(int); + + // Act + var result1 = navigationType.IsNavigationProperty(); + var result2 = nonNavigationType.IsNavigationProperty(); + + // Assert + result1.Should().BeTrue(); + result2.Should().BeFalse(); + } + + [Fact] + public void IsNavigationProperty_HandlesString() + { + // Arrange + + // Act + var result = typeof(string).IsNavigationProperty(); + + // Assert + result.Should().BeFalse(); + } + + [Fact] + public void UnProxy_ReturnsSameTypeIfNotProxy() + { + // Arrange + var type = typeof(Project); + + // Act + var result = type.UnProxy(); + + // Assert + result.Should().BeSameAs(type); + } + + [Fact] + public void IsEnumerableExceptString_DetectsEnumerableTypes() + { + // Arrange + var enumerableType = typeof(List); + + // Act + var result = enumerableType.IsEnumerableExceptString(); + + // Assert + result.Should().BeTrue(); + } + + [Fact] + public void IsEnumerableExceptString_ExcludesString() + { + // Act + var result = typeof(string).IsEnumerableExceptString(); + + // Assert + result.Should().BeFalse(); + } + + private class TestBaseEntity + { + } + + private class TestBaseEntity : TestBaseEntity + { + } + + private class TestSubEntity : TestBaseEntity + { + } +} \ No newline at end of file diff --git a/tests/AutoCrudAdmin.Tests/Helpers/ExpressionsBuilderTests.cs b/tests/AutoCrudAdmin.Tests/Helpers/ExpressionsBuilderTests.cs new file mode 100644 index 0000000..683c82d --- /dev/null +++ b/tests/AutoCrudAdmin.Tests/Helpers/ExpressionsBuilderTests.cs @@ -0,0 +1,72 @@ +namespace AutoCrudAdmin.Tests.Helpers; + +using System; +using System.Collections.Generic; +using AutoCrudAdmin.Helpers; +using Demo.Models.Models; +using FluentAssertions; +using Xunit; + +public class ExpressionsBuilderTests +{ + [Fact] + public void ForByEntityPrimaryKey_BuildsPredicate() + { + // Arrange + var dict = new Dictionary + { + [nameof(Task.Id)] = "1", + }; + + // Act + var result = ExpressionsBuilder.ForByEntityPrimaryKey(dict); + + // Assert + result.Should().NotBeNull(); + result.Type.Should().Be(typeof(Func)); + } + + [Fact] + public void ForGetProperty_BuildsPredicate() + { + // Arrange + var property = typeof(Task).GetProperty(nameof(Task.Name)) !; + + // Act + var result = ExpressionsBuilder.ForGetProperty(property); + + // Assert + result.Should().NotBeNull(); + result.Type.Should().Be(typeof(Func)); + } + + [Fact] + public void ForCreateInstance_ReturnsFactoryMethod() + { + // Act + var result = ExpressionsBuilder.ForCreateInstance(); + + // Assert + result.Should().NotBeNull(); + result.Should().BeOfType>(); + result().Should().BeOfType(); + } + + [Theory] + [InlineData(1)] + public void ForGetPropertyValue_ReturnsValueGetter(int id) + { + // Arrange + var property = typeof(Task).GetProperty(nameof(Task.Id)) !; + + var entity = new Task { Id = id }; + + // Act + var result = ExpressionsBuilder.ForGetPropertyValue(property); + + // Assert + result.Should().NotBeNull(); + result.Should().BeOfType>(); + result(entity).Should().Be(id); + } +} \ No newline at end of file diff --git a/tests/AutoCrudAdmin.Tests/Helpers/NavHelperTests.cs b/tests/AutoCrudAdmin.Tests/Helpers/NavHelperTests.cs new file mode 100644 index 0000000..2befa38 --- /dev/null +++ b/tests/AutoCrudAdmin.Tests/Helpers/NavHelperTests.cs @@ -0,0 +1,36 @@ +namespace AutoCrudAdmin.Tests.Helpers; + +using System.Linq; +using AutoCrudAdmin.Helpers; +using Demo.SqlServer; +using FluentAssertions; +using Xunit; + +public class NavHelperTests +{ + [Fact] + public void GetNavItems_ReturnsDbSetPropertyNames() + { + // Arrange + var dbSetPropertiesNames = ReflectionHelper + .DbSetProperties + .Select(p => p.Name) + .ToList(); + + var expectedDbProperties = new[] + { + nameof(TaskSystemDbContext.Employees), + nameof(TaskSystemDbContext.EmployeeTasks), + nameof(TaskSystemDbContext.Projects), + nameof(TaskSystemDbContext.Tasks), + }; + + // Act + var result = NavHelper.GetNavItems().ToList(); + + // Assert + result.Should().NotBeEmpty(); + result.Should().BeEquivalentTo(dbSetPropertiesNames); + result.Should().BeEquivalentTo(expectedDbProperties); + } +} \ No newline at end of file diff --git a/tests/AutoCrudAdmin.Tests/Helpers/ReflectionHelperTests.cs b/tests/AutoCrudAdmin.Tests/Helpers/ReflectionHelperTests.cs new file mode 100644 index 0000000..a472b51 --- /dev/null +++ b/tests/AutoCrudAdmin.Tests/Helpers/ReflectionHelperTests.cs @@ -0,0 +1,38 @@ +namespace AutoCrudAdmin.Tests.Helpers; + +using System.Linq; +using AutoCrudAdmin.Helpers; +using Demo.SqlServer; +using FluentAssertions; +using Xunit; + +public class ReflectionHelperTests +{ + [Fact] + public void DbContexts_ShouldReturnAllDbContextTypes() + { + // Arrange + var dbContexts = ReflectionHelper.DbContexts; + + // Assert + dbContexts.Should().ContainSingle(t => t == typeof(TaskSystemDbContext)); + } + + [Fact] + public void DbSetProperties_ShouldReturnAllDbSetProperties() + { + // Arrange + var dbSetProperties = ReflectionHelper.DbSetProperties; + + var expectedDbProperties = new[] + { + nameof(TaskSystemDbContext.Tasks), + nameof(TaskSystemDbContext.Employees), + nameof(TaskSystemDbContext.Projects), + nameof(TaskSystemDbContext.EmployeeTasks), + }; + + // Assert + dbSetProperties.Select(p => p.Name).Should().BeEquivalentTo(expectedDbProperties); + } +} \ No newline at end of file diff --git a/tests/AutoCrudAdmin.Tests/Helpers/UrlsHelperTests.cs b/tests/AutoCrudAdmin.Tests/Helpers/UrlsHelperTests.cs new file mode 100644 index 0000000..ca7531f --- /dev/null +++ b/tests/AutoCrudAdmin.Tests/Helpers/UrlsHelperTests.cs @@ -0,0 +1,21 @@ +namespace AutoCrudAdmin.Tests.Helpers; + +using AutoCrudAdmin.Helpers; +using FluentAssertions; +using Xunit; + +public class UrlsHelperTests +{ + [Theory] + [InlineData("Column1", "Equals", "Column1-equals")] + [InlineData("ColumnWithCamelCase", "NotEquals", "ColumnWithCamelCase-not-equals")] + [InlineData("Column_With_Underscores", "Contains", "Column_With_Underscores-contains")] + public void GetQueryParamForColumnAndFilter_ReturnsExpected(string columnName, string filterName, string expected) + { + // Act + var result = UrlsHelper.GetQueryParamForColumnAndFilter(columnName, filterName); + + // Assert + result.Should().Be(expected); + } +} \ No newline at end of file diff --git a/tests/AutoCrudAdmin.Tests/Infrastructure/TestsWithData.cs b/tests/AutoCrudAdmin.Tests/Infrastructure/TestsWithData.cs new file mode 100644 index 0000000..728fc60 --- /dev/null +++ b/tests/AutoCrudAdmin.Tests/Infrastructure/TestsWithData.cs @@ -0,0 +1,19 @@ +namespace AutoCrudAdmin.Tests.Infrastructure; + +using System; +using Demo.SqlServer; +using Microsoft.EntityFrameworkCore; + +public abstract class TestsWithData +{ + protected TestsWithData() + { + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase(Guid.NewGuid().ToString()) + .Options; + + this.Data = new TaskSystemDbContext(options); + } + + protected TaskSystemDbContext Data { get; } +} \ No newline at end of file