Created tests for the core module

This commit is contained in:
2025-01-18 16:01:35 +01:00
parent a5062ec581
commit afe8a41f6c
20 changed files with 1097 additions and 26 deletions

39
.gitlab-ci.yml Normal file
View File

@@ -0,0 +1,39 @@
image: mcr.microsoft.com/dotnet/sdk:9.0
stages:
- build
- test
- publish
before_script:
- echo "Setting up environment"
- 'dotnet --version'
build:
stage: build
script:
- dotnet restore
- dotnet build --configuration Release --no-restore
artifacts:
paths:
- "**/bin/Release"
expire_in: 10 minutes
test:
stage: test
script:
- dotnet test --verbosity normal
dependencies:
- build
publish:
stage: publish
script:
- export VERSION=$(echo $CI_COMMIT_TAG | sed 's/^v//')
- dotnet pack -c Release -o . /p:Version=$VERSION
- for nupkg in *.nupkg; do dotnet nuget push $nupkg -k ${NUGET_API_KEY} -s https://api.nuget.org/v3/index.json; done
only:
- tags
dependencies:
- build
- test

View File

@@ -9,17 +9,25 @@
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="0648788e-7696-4e60-bf12-5d5601f33d8c" name="Changes" comment="Addressed all build warnings">
<list default="true" id="0648788e-7696-4e60-bf12-5d5601f33d8c" name="Changes" comment="">
<change afterPath="$PROJECT_DIR$/tests/HopFrame.Core.Tests/Config/DbContextConfiguratorTests.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/tests/HopFrame.Core.Tests/Config/HopFrameConfiguratorTests.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/tests/HopFrame.Core.Tests/Config/PropertyConfiguratorTests.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/tests/HopFrame.Core.Tests/Config/TableConfiguratorTests.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/tests/HopFrame.Core.Tests/HopFrame.Core.Tests.csproj" afterDir="false" />
<change afterPath="$PROJECT_DIR$/tests/HopFrame.Core.Tests/Models/MockDbContext.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/tests/HopFrame.Core.Tests/Models/MockModel.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/tests/HopFrame.Core.Tests/Models/MockModel2.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/tests/HopFrame.Core.Tests/Models/QueryProvider.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/tests/HopFrame.Core.Tests/Services/ContextExplorerTests.cs" afterDir="false" />
<change afterPath="$PROJECT_DIR$/tests/HopFrame.Core.Tests/Services/TableManagerTests.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/.idea.HopFrame/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.HopFrame/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/HopFrame.Core/Config/DbContextConfig.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Core/Config/DbContextConfigurator.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/HopFrame.sln" beforeDir="false" afterPath="$PROJECT_DIR$/HopFrame.sln" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/HopFrame.Core/Config/DbContextConfigurator.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Core/Config/DbContextConfig.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/HopFrame.Core/Config/HopFrameConfig.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Core/Config/HopFrameConfig.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/HopFrame.Core/Config/PropertyConfig.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Core/Config/PropertyConfigurator.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/HopFrame.Core/Config/TableConfig.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Core/Config/TableConfigurator.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/HopFrame.Core/ServiceCollectionExtensions.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Core/ServiceCollectionExtensions.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/HopFrame.Core/Services/IHopFrameAuthHandler.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Core/Services/IHopFrameAuthHandler.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/HopFrame.Web/Components/Dialogs/HopFrameEditor.razor" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Web/Components/Dialogs/HopFrameEditor.razor" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/HopFrame.Web/ServiceCollectionExtensions.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Web/ServiceCollectionExtensions.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/testing/HopFrame.Testing/Program.cs" beforeDir="false" afterPath="$PROJECT_DIR$/testing/HopFrame.Testing/Program.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/HopFrame.Core/Config/PropertyConfigurator.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Core/Config/PropertyConfig.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/HopFrame.Core/Config/TableConfigurator.cs" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Core/Config/TableConfig.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/HopFrame.Core/HopFrame.Core.csproj" beforeDir="false" afterPath="$PROJECT_DIR$/src/HopFrame.Core/HopFrame.Core.csproj" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -39,7 +47,7 @@
<component name="Git.Settings">
<option name="RECENT_BRANCH_BY_REPOSITORY">
<map>
<entry key="$PROJECT_DIR$" value="feature/setup" />
<entry key="$PROJECT_DIR$" value="feature/documentation" />
</map>
</option>
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
@@ -67,18 +75,12 @@
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/87c584767b46b5fd42769be76547105558e6690f785614efddca134b2d682/Type.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/adcd2c45092dd8e4fc412325c8adb75d6e7d8b3e90a9523f167583fb9c60/ServiceCollectionExtensions.cs" root0="SKIP_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/b3ccb66df3646cb51df73ad51716136ebd2eefb4edb1308dd52a7e999582d59e/IBindableColumn.cs" root0="SKIP_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/bfff78ecaa39c818519fc918bb2d4bbdca6ad93d7170f5cf325f67ccd0b97d43/BooleanAsserts.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/d858ddb35a8e36df5573b7612542f9ad50f426b8ab43818587d1ac65fab14829/DatabaseGeneratedAttribute.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/ece8533187fe96ce67b3ef1c9cc3502ef8da5510aadb132a9b21c5605d7c2119/PropertyColumn.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/ee4d234452e240d83e3de396c2e85cbf9ac9fb9add618b955eea196c81aaf8/IDialogContentComponent.cs" root0="SKIP_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/ff37d54b3bf4d2756237fb789635831532603376e940f63d634b869d26d74c/Regular16.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="mock://C:/Users/leon/Documents/Projekte/HopFrame/src/HopFrame.Core/Config/PropertyConfig.cs" root0="SKIP_HIGHLIGHTING" />
<setting file="mock://C:/Users/leon/Documents/Projekte/HopFrame/src/HopFrame.Core/Config/TableConfig.cs" root0="SKIP_HIGHLIGHTING" />
<setting file="mock://C:/Users/leon/Documents/Projekte/HopFrame/src/HopFrame.Core/Services/Implementations/ContextExplorer.cs" root0="SKIP_HIGHLIGHTING" />
<setting file="mock://C:/Users/leon/Documents/Projekte/HopFrame/src/HopFrame.Core/Services/Implementations/TableManager.cs" root0="SKIP_HIGHLIGHTING" />
<setting file="mock://C:/Users/leon/Documents/Projekte/HopFrame/src/HopFrame.Web/Components/Dialogs/HopFrameEditor.razor" root0="SKIP_HIGHLIGHTING" root1="FORCE_HIGHLIGHTING" root2="FORCE_HIGHLIGHTING" />
<setting file="mock://C:/Users/leon/Documents/Projekte/HopFrame/src/HopFrame.Web/Components/Pages/HopFrameTablePage.razor" root0="SKIP_HIGHLIGHTING" root1="FORCE_HIGHLIGHTING" root2="FORCE_HIGHLIGHTING" />
<setting file="mock://C:/Users/leon/Documents/Projekte/HopFrame/src/HopFrame.Web/Components/Pages/HopFrameTablePage.razor" root0="SKIP_HIGHLIGHTING" root1="FORCE_HIGHLIGHTING" root2="FORCE_HIGHLIGHTING" />
<setting file="mock://C:/Users/leon/Documents/Projekte/HopFrame/testing/HopFrame.Testing/Program.cs" root0="SKIP_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/src/HopFrame.Core/Config/DbContextConfig.cs" root0="FORCE_HIGHLIGHTING" />
</component>
<component name="MetaFilesCheckinStateConfiguration" checkMetaFiles="true" />
<component name="ProjectColorInfo">{
@@ -97,9 +99,11 @@
".NET Launch Settings Profile.HopFrame.Testing.executor": "Run",
".NET Launch Settings Profile.HopFrame.Testing: https.executor": "Run",
".NET Project.HopFrame.Testing.executor": "Run",
"72b118b0-a6fc-4561-acdf-74f0b454dbb8.executor": "Debug",
"RunOnceActivity.ShowReadmeOnStart": "true",
"RunOnceActivity.git.unshallow": "true",
"git-widget-placeholder": "!17 on feature/documentation",
"dcdf1689-dc07-47e4-8824-2e60a4fbf301.executor": "Debug",
"git-widget-placeholder": "!18 on feature/unit-tests",
"list.type.of.created.stylesheet": "CSS",
"node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true",
@@ -166,7 +170,8 @@
<workItem from="1737021098746" duration="21112000" />
<workItem from="1737047730756" duration="7678000" />
<workItem from="1737120164342" duration="9351000" />
<workItem from="1737199714142" duration="7872000" />
<workItem from="1737199714142" duration="8344000" />
<workItem from="1737208313207" duration="3856000" />
</task>
<task id="LOCAL-00001" summary="Added basic configuration">
<option name="closed" value="true" />
@@ -288,7 +293,15 @@
<option name="project" value="LOCAL" />
<updated>1737203441319</updated>
</task>
<option name="localTasksCounter" value="16" />
<task id="LOCAL-00016" summary="Added documentation for the configurators and service extensions methods">
<option name="closed" value="true" />
<created>1737208088933</created>
<option name="number" value="00016" />
<option name="presentableId" value="LOCAL-00016" />
<option name="project" value="LOCAL" />
<updated>1737208088933</updated>
</task>
<option name="localTasksCounter" value="17" />
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
@@ -313,6 +326,7 @@
<MESSAGE value="Added n -&gt; m relation support" />
<MESSAGE value="Added text area support and DI support for modifier functions" />
<MESSAGE value="Addressed all build warnings" />
<option name="LAST_COMMIT_MESSAGE" value="Addressed all build warnings" />
<MESSAGE value="Added documentation for the configurators and service extensions methods" />
<option name="LAST_COMMIT_MESSAGE" value="Added documentation for the configurators and service extensions methods" />
</component>
</project>

View File

@@ -10,6 +10,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Testing", "Testing", "{9EB7
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HopFrame.Testing", "testing\HopFrame.Testing\HopFrame.Testing.csproj", "{58490069-51DF-454C-8B54-7FB7D4BDFF81}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{141928CB-5977-4285-A986-5BD785F2883C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HopFrame.Core.Tests", "tests\HopFrame.Core.Tests\HopFrame.Core.Tests.csproj", "{2E2D29E0-53FA-462D-B4D2-4678CD106E29}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -19,6 +23,7 @@ Global
{4BFE21C2-EAAC-4662-8B97-500836651B2A} = {7E4AAFB3-9762-4F42-86DF-5A3194FDC243}
{8E59F398-184A-47C9-AAA2-3E0FFD775ABF} = {7E4AAFB3-9762-4F42-86DF-5A3194FDC243}
{58490069-51DF-454C-8B54-7FB7D4BDFF81} = {9EB7FDBD-49C2-4872-9666-6F7AEBA541B2}
{2E2D29E0-53FA-462D-B4D2-4678CD106E29} = {141928CB-5977-4285-A986-5BD785F2883C}
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4BFE21C2-EAAC-4662-8B97-500836651B2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
@@ -33,5 +38,9 @@ Global
{58490069-51DF-454C-8B54-7FB7D4BDFF81}.Debug|Any CPU.Build.0 = Debug|Any CPU
{58490069-51DF-454C-8B54-7FB7D4BDFF81}.Release|Any CPU.ActiveCfg = Release|Any CPU
{58490069-51DF-454C-8B54-7FB7D4BDFF81}.Release|Any CPU.Build.0 = Release|Any CPU
{2E2D29E0-53FA-462D-B4D2-4678CD106E29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2E2D29E0-53FA-462D-B4D2-4678CD106E29}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2E2D29E0-53FA-462D-B4D2-4678CD106E29}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2E2D29E0-53FA-462D-B4D2-4678CD106E29}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@@ -1,5 +1,4 @@
using HopFrame.Core.Services;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace HopFrame.Core.Config;

View File

@@ -1,5 +1,4 @@
using System.Collections;
using System.Linq.Expressions;
using System.Linq.Expressions;
using System.Reflection;
namespace HopFrame.Core.Config;

View File

@@ -10,4 +10,10 @@
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
</ItemGroup>
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>HopFrame.Core.Tests</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,34 @@
using HopFrame.Core.Config;
using HopFrame.Core.Tests.Models;
using Moq;
namespace HopFrame.Core.Tests.Config;
public class DbContextConfiguratorTests {
[Fact]
public void Table_WithConfigurator_InvokesConfigurator() {
// Arrange
var dbContextConfig = new DbContextConfig(typeof(MockDbContext));
var configurator = new DbContextConfigurator<MockDbContext>(dbContextConfig);
var mockConfigurator = new Mock<Action<TableConfigurator<MockModel>>>();
// Act
configurator.Table<MockModel>(mockConfigurator.Object);
// Assert
mockConfigurator.Verify(c => c.Invoke(It.IsAny<TableConfigurator<MockModel>>()), Times.Once);
}
[Fact]
public void Table_ReturnsCorrectTableConfigurator() {
// Arrange
var dbContextConfig = new DbContextConfig(typeof(MockDbContext));
var configurator = new DbContextConfigurator<MockDbContext>(dbContextConfig);
// Act
var tableConfigurator = configurator.Table<MockModel>();
// Assert
Assert.IsType<TableConfigurator<MockModel>>(tableConfigurator);
}
}

View File

@@ -0,0 +1,62 @@
using HopFrame.Core.Config;
using HopFrame.Core.Tests.Models;
namespace HopFrame.Core.Tests.Config;
public class HopFrameConfiguratorTests {
[Fact]
public void AddDbContext_AddsDbContextToInnerConfig() {
// Arrange
var config = new HopFrameConfig();
var configurator = new HopFrameConfigurator(config);
// Act
var dbContextConfigurator = configurator.AddDbContext<MockDbContext>();
// Assert
Assert.Single(config.Contexts);
Assert.IsType<DbContextConfig>(config.Contexts[0]);
Assert.IsType<DbContextConfigurator<MockDbContext>>(dbContextConfigurator);
}
[Fact]
public void DisplayUserInfo_SetsDisplayUserInfoProperty() {
// Arrange
var config = new HopFrameConfig();
var configurator = new HopFrameConfigurator(config);
// Act
configurator.DisplayUserInfo(false);
// Assert
Assert.False(config.DisplayUserInfo);
}
[Fact]
public void SetBasePolicy_SetsBasePolicyProperty() {
// Arrange
var config = new HopFrameConfig();
var configurator = new HopFrameConfigurator(config);
var basePolicy = "Admin";
// Act
configurator.SetBasePolicy(basePolicy);
// Assert
Assert.Equal(basePolicy, config.BasePolicy);
}
[Fact]
public void SetLoginPage_SetsLoginPageRewriteProperty() {
// Arrange
var config = new HopFrameConfig();
var configurator = new HopFrameConfigurator(config);
var loginPageUrl = "/login";
// Act
configurator.SetLoginPage(loginPageUrl);
// Assert
Assert.Equal(loginPageUrl, config.LoginPageRewrite);
}
}

View File

@@ -0,0 +1,212 @@
using System.Linq.Expressions;
using HopFrame.Core.Config;
using HopFrame.Core.Tests.Models;
namespace HopFrame.Core.Tests.Config;
public class PropertyConfiguratorTests {
[Fact]
public void SetDisplayName_SetsNameProperty() {
// Arrange
var propertyConfig = new PropertyConfig(typeof(MockModel).GetProperty("Id")!,
new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "MockModels", 0), 0);
var configurator = new PropertyConfigurator<int>(propertyConfig);
var displayName = "ID";
// Act
configurator.SetDisplayName(displayName);
// Assert
Assert.Equal(displayName, propertyConfig.Name);
}
[Fact]
public void List_SetsListAndSearchableProperties() {
// Arrange
var propertyConfig = new PropertyConfig(typeof(MockModel).GetProperty("Id")!,
new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "MockModels", 0), 0);
var configurator = new PropertyConfigurator<int>(propertyConfig);
// Act
configurator.List(true);
// Assert
Assert.True(propertyConfig.List);
Assert.False(propertyConfig.Searchable);
}
[Fact]
public void IsSortable_SetsSortableProperty() {
// Arrange
var propertyConfig = new PropertyConfig(typeof(MockModel).GetProperty("Id")!,
new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "MockModels", 0), 0);
var configurator = new PropertyConfigurator<int>(propertyConfig);
// Act
configurator.IsSortable(true);
// Assert
Assert.True(propertyConfig.Sortable);
}
[Fact]
public void IsSearchable_SetsSearchableProperty() {
// Arrange
var propertyConfig = new PropertyConfig(typeof(MockModel).GetProperty("Id")!,
new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "MockModels", 0), 0);
var configurator = new PropertyConfigurator<int>(propertyConfig);
// Act
configurator.IsSearchable(true);
// Assert
Assert.True(propertyConfig.Searchable);
}
[Fact]
public void SetDisplayedProperty_SetsDisplayedProperty() {
// Arrange
var propertyConfig = new PropertyConfig(typeof(MockModel).GetProperty("Id")!,
new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "MockModels", 0), 0);
var configurator = new PropertyConfigurator<MockModel>(propertyConfig);
Expression<Func<MockModel, int>> propertyExpression = model => model.Id;
// Act
configurator.SetDisplayedProperty(propertyExpression);
// Assert
Assert.NotNull(propertyConfig.DisplayedProperty);
Assert.Equal("Id", propertyConfig.DisplayedProperty?.Name);
}
[Fact]
public void Format_SetsFormatter() {
// Arrange
var propertyConfig = new PropertyConfig(typeof(MockModel).GetProperty("Id")!,
new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "MockModels", 0), 0);
var configurator = new PropertyConfigurator<int>(propertyConfig);
Func<int, IServiceProvider, string> formatter = (val, _) => val.ToString();
// Act
configurator.Format(formatter);
// Assert
Assert.NotNull(propertyConfig.Formatter);
}
[Fact]
public void SetParser_SetsParser() {
// Arrange
var propertyConfig = new PropertyConfig(typeof(MockModel).GetProperty("Id")!,
new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "MockModels", 0), 0);
var configurator = new PropertyConfigurator<int>(propertyConfig);
Func<string, IServiceProvider, int> parser = (str, _) => int.Parse(str);
// Act
configurator.SetParser(parser);
// Assert
Assert.NotNull(propertyConfig.Parser);
}
[Fact]
public void SetEditable_SetsEditableProperty() {
// Arrange
var propertyConfig = new PropertyConfig(typeof(MockModel).GetProperty("Id")!,
new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "MockModels", 0), 0);
var configurator = new PropertyConfigurator<int>(propertyConfig);
// Act
configurator.SetEditable(true);
// Assert
Assert.True(propertyConfig.Editable);
}
[Fact]
public void SetCreatable_SetsCreatableProperty() {
// Arrange
var propertyConfig = new PropertyConfig(typeof(MockModel).GetProperty("Id")!,
new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "MockModels", 0), 0);
var configurator = new PropertyConfigurator<int>(propertyConfig);
// Act
configurator.SetCreatable(true);
// Assert
Assert.True(propertyConfig.Creatable);
}
[Fact]
public void DisplayValue_SetsDisplayValueProperty() {
// Arrange
var propertyConfig = new PropertyConfig(typeof(MockModel).GetProperty("Id")!,
new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "MockModels", 0), 0);
var configurator = new PropertyConfigurator<int>(propertyConfig);
// Act
configurator.DisplayValue(true);
// Assert
Assert.True(propertyConfig.DisplayValue);
}
[Fact]
public void IsTextArea_SetsTextAreaProperty() {
// Arrange
var propertyConfig = new PropertyConfig(typeof(MockModel).GetProperty("Id")!,
new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "MockModels", 0), 0);
var configurator = new PropertyConfigurator<int>(propertyConfig);
// Act
configurator.IsTextArea(true);
// Assert
Assert.True(propertyConfig.TextArea);
}
[Fact]
public void SetTextAreaRows_SetsTextAreaRowsProperty() {
// Arrange
var propertyConfig = new PropertyConfig(typeof(MockModel).GetProperty("Id")!,
new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "MockModels", 0), 0);
var configurator = new PropertyConfigurator<int>(propertyConfig);
var rows = 10;
// Act
configurator.SetTextAreaRows(rows);
// Assert
Assert.Equal(rows, propertyConfig.TextAreaRows);
}
[Fact]
public void SetValidator_SetsValidator() {
// Arrange
var propertyConfig = new PropertyConfig(typeof(MockModel).GetProperty("Id")!,
new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "MockModels", 0), 0);
var configurator = new PropertyConfigurator<int>(propertyConfig);
Func<int, IServiceProvider, IEnumerable<string>> validator = (_, _) => new List<string>();
// Act
configurator.SetValidator(validator);
// Assert
Assert.NotNull(propertyConfig.Validator);
}
[Fact]
public void SetOrderIndex_SetsOrderProperty() {
// Arrange
var propertyConfig = new PropertyConfig(typeof(MockModel).GetProperty("Id")!,
new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "MockModels", 0), 0);
var configurator = new PropertyConfigurator<int>(propertyConfig);
var orderIndex = 1;
// Act
configurator.SetOrderIndex(orderIndex);
// Assert
Assert.Equal(orderIndex, propertyConfig.Order);
}
}

View File

@@ -0,0 +1,151 @@
using System.Linq.Expressions;
using HopFrame.Core.Config;
using HopFrame.Core.Tests.Models;
namespace HopFrame.Core.Tests.Config;
public class TableConfiguratorTests {
[Fact]
public void Ignore_SetsIgnoredProperty() {
// Arrange
var tableConfig =
new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "MockModels", 0);
var configurator = new TableConfigurator<MockModel>(tableConfig);
// Act
configurator.Ignore(true);
// Assert
Assert.True(tableConfig.Ignored);
}
[Fact]
public void Property_ReturnsCorrectPropertyConfigurator() {
// Arrange
var tableConfig = new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "MockModels", 0);
var configurator = new TableConfigurator<MockModel>(tableConfig);
Expression<Func<MockModel, int>> propertyExpression = model => model.Id;
// Act
var propertyConfigurator = configurator.Property(propertyExpression);
// Assert
Assert.IsType<PropertyConfigurator<int>>(propertyConfigurator);
}
[Fact]
public void AddVirtualProperty_AddsVirtualPropertyToConfig() {
// Arrange
var tableConfig = new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "MockModels", 0);
var configurator = new TableConfigurator<MockModel>(tableConfig);
Func<MockModel, IServiceProvider, string> template = (model, _) => model.Name!;
// Act
var propertyConfigurator = configurator.AddVirtualProperty("VirtualName", template);
// Assert
var virtualProperty = tableConfig.Properties.SingleOrDefault(p => p.Name == "VirtualName");
Assert.NotNull(virtualProperty);
Assert.NotNull(propertyConfigurator);
Assert.True(virtualProperty.IsListingProperty);
Assert.Equal("VirtualName", virtualProperty.Name);
}
[Fact]
public void SetDisplayName_SetsDisplayNameProperty() {
// Arrange
var tableConfig = new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "MockModels", 0);
var configurator = new TableConfigurator<MockModel>(tableConfig);
var displayName = "Mock Model Display Name";
// Act
configurator.SetDisplayName(displayName);
// Assert
Assert.Equal(displayName, tableConfig.DisplayName);
}
[Fact]
public void SetDescription_SetsDescriptionProperty() {
// Arrange
var tableConfig = new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "MockModels", 0);
var configurator = new TableConfigurator<MockModel>(tableConfig);
var description = "Mock Model Description";
// Act
configurator.SetDescription(description);
// Assert
Assert.Equal(description, tableConfig.Description);
}
[Fact]
public void SetOrderIndex_SetsOrderIndexProperty() {
// Arrange
var tableConfig = new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "MockModels", 0);
var configurator = new TableConfigurator<MockModel>(tableConfig);
var orderIndex = 1;
// Act
configurator.SetOrderIndex(orderIndex);
// Assert
Assert.Equal(orderIndex, tableConfig.Order);
}
[Fact]
public void SetViewPolicy_SetsViewPolicyProperty() {
// Arrange
var tableConfig = new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "MockModels", 0);
var configurator = new TableConfigurator<MockModel>(tableConfig);
var policy = "ViewPolicy";
// Act
configurator.SetViewPolicy(policy);
// Assert
Assert.Equal(policy, tableConfig.ViewPolicy);
}
[Fact]
public void SetUpdatePolicy_SetsUpdatePolicyProperty() {
// Arrange
var tableConfig = new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "MockModels", 0);
var configurator = new TableConfigurator<MockModel>(tableConfig);
var policy = "UpdatePolicy";
// Act
configurator.SetUpdatePolicy(policy);
// Assert
Assert.Equal(policy, tableConfig.UpdatePolicy);
}
[Fact]
public void SetCreatePolicy_SetsCreatePolicyProperty() {
// Arrange
var tableConfig = new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "MockModels", 0);
var configurator = new TableConfigurator<MockModel>(tableConfig);
var policy = "CreatePolicy";
// Act
configurator.SetCreatePolicy(policy);
// Assert
Assert.Equal(policy, tableConfig.CreatePolicy);
}
[Fact]
public void SetDeletePolicy_SetsDeletePolicyProperty() {
// Arrange
var tableConfig = new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "MockModels", 0);
var configurator = new TableConfigurator<MockModel>(tableConfig);
var policy = "DeletePolicy";
// Act
configurator.SetDeletePolicy(policy);
// Assert
Assert.Equal(policy, tableConfig.DeletePolicy);
}
}

View File

@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.2"/>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="9.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1"/>
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="xunit" Version="2.9.2"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2"/>
</ItemGroup>
<ItemGroup>
<Using Include="Xunit"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\HopFrame.Core\HopFrame.Core.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,13 @@
using Microsoft.EntityFrameworkCore;
namespace HopFrame.Core.Tests.Models;
// A mock DbContext for testing purposes
public class MockDbContext : DbContext {
public DbSet<MockModel> Models { get; set; }
public DbSet<MockModel2> Models2 { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
optionsBuilder.UseInMemoryDatabase(nameof(MockDbContext));
}
}

View File

@@ -0,0 +1,7 @@
namespace HopFrame.Core.Tests.Models;
// A mock model for testing purposes
public class MockModel {
public int Id { get; set; }
public string? Name { get; set; }
}

View File

@@ -0,0 +1,5 @@
namespace HopFrame.Core.Tests.Models;
public class MockModel2 {
public string Id { get; set; }
}

View File

@@ -0,0 +1,129 @@
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore.Query;
namespace HopFrame.Core.Tests.Models;
// A mock implementation for async query provider
internal class TestAsyncQueryProvider<TEntity> : IAsyncQueryProvider {
private readonly IQueryProvider _inner;
internal TestAsyncQueryProvider(IQueryProvider inner) {
_inner = inner;
}
public IQueryable CreateQuery(Expression expression) {
return new TestAsyncEnumerable<TEntity>(expression);
}
public IQueryable<TElement> CreateQuery<TElement>(Expression expression) {
return new TestAsyncEnumerable<TElement>(expression);
}
public object Execute(Expression expression) {
return _inner.Execute(expression);
}
public TResult Execute<TResult>(Expression expression) {
return _inner.Execute<TResult>(expression);
}
public TResult ExecuteAsync<TResult>(Expression expression,
CancellationToken cancellationToken = new CancellationToken()) {
return _inner.Execute<TResult>(expression);
}
public IAsyncEnumerable<TResult> ExecuteAsync<TResult>(Expression expression) {
return new TestAsyncEnumerable<TResult>(expression);
}
}
internal class TestAsyncEnumerable<T> : EnumerableQuery<T>, IAsyncEnumerable<T>, IQueryable<T> {
public TestAsyncEnumerable(IEnumerable<T> enumerable) : base(enumerable) { }
public TestAsyncEnumerable(Expression expression) : base(expression) { }
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default) {
return new TestAsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
}
IQueryProvider IQueryable.Provider => new TestAsyncQueryProvider<T>(this);
}
internal class TestAsyncEnumerator<T> : IAsyncEnumerator<T> {
private readonly IEnumerator<T> _inner;
public TestAsyncEnumerator(IEnumerator<T> inner) {
_inner = inner ?? throw new ArgumentNullException(nameof(inner));
}
public T Current => _inner.Current;
public ValueTask DisposeAsync() {
_inner.Dispose();
return new ValueTask();
}
public ValueTask<bool> MoveNextAsync() {
return new ValueTask<bool>(_inner.MoveNext());
}
}
/*// A mock implementation for async query provider
internal class TestAsyncQueryProvider<TEntity> : IAsyncQueryProvider {
private readonly IQueryProvider _inner;
internal TestAsyncQueryProvider(IQueryProvider inner) {
_inner = inner;
}
public IQueryable CreateQuery(Expression expression) {
return new TestAsyncEnumerable<TEntity>(expression);
}
public IQueryable<TElement> CreateQuery<TElement>(Expression expression) {
return new TestAsyncEnumerable<TElement>(expression);
}
public object? Execute(Expression expression) {
return _inner.Execute(expression);
}
public TResult Execute<TResult>(Expression expression) {
return _inner.Execute<TResult>(expression);
}
public TResult ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken) {
return _inner.Execute<TResult>(expression);
}
public IAsyncEnumerable<TResult> ExecuteAsync<TResult>(Expression expression) {
return new TestAsyncEnumerable<TResult>(expression);
}
}
internal class TestAsyncEnumerable<T> : EnumerableQuery<T>, IAsyncEnumerable<T>, IQueryable<T> {
public TestAsyncEnumerable(IEnumerable<T> enumerable) : base(enumerable) { }
public TestAsyncEnumerable(Expression expression) : base(expression) { }
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default) {
return new TestAsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
}
IQueryProvider IQueryable.Provider => new TestAsyncQueryProvider<T>(this);
}
internal class TestAsyncEnumerator<T>(IEnumerator<T> inner) : IAsyncEnumerator<T> {
private readonly IEnumerator<T> _inner = inner ?? throw new ArgumentNullException(nameof(inner));
public T Current => _inner.Current;
public ValueTask DisposeAsync() {
_inner.Dispose();
return new ValueTask();
}
public ValueTask<bool> MoveNextAsync() {
return new ValueTask<bool>(_inner.MoveNext());
}
}*/

View File

@@ -0,0 +1,132 @@
using HopFrame.Core.Config;
using HopFrame.Core.Services.Implementations;
using HopFrame.Core.Tests.Models;
using Microsoft.Extensions.Logging;
using Moq;
namespace HopFrame.Core.Tests.Services;
public class ContextExplorerTests {
[Fact]
public void GetTables_ReturnsNonIgnoredTables() {
// Arrange
var config = new HopFrameConfig();
var contextConfig = new DbContextConfig(typeof(MockDbContext));
var tableConfig1 = contextConfig.Tables[0];
var tableConfig2 = contextConfig.Tables[1];
config.Contexts.Add(contextConfig);
tableConfig2.Ignored = true;
var provider = new Mock<IServiceProvider>();
var contextExplorer = new ContextExplorer(config, provider.Object, new Logger<ContextExplorer>(new LoggerFactory()));
// Act
var tables = contextExplorer.GetTables().ToList();
// Assert
Assert.Single(tables);
Assert.Contains(tableConfig1, tables);
Assert.DoesNotContain(tableConfig2, tables);
}
[Fact]
public void GetTable_ByDisplayName_ReturnsCorrectTable() {
// Arrange
var config = new HopFrameConfig();
var contextConfig = new DbContextConfig(typeof(MockDbContext));
var tableConfig = contextConfig.Tables[0];
config.Contexts.Add(contextConfig);
tableConfig.DisplayName = "TestTable";
var provider = new Mock<IServiceProvider>();
provider.Setup(p => p.GetService(typeof(MockDbContext))).Returns(new MockDbContext());
var contextExplorer = new ContextExplorer(config, provider.Object, new Logger<ContextExplorer>(new LoggerFactory()));
// Act
var result = contextExplorer.GetTable("TestTable");
// Assert
Assert.NotNull(result);
Assert.Equal(tableConfig, result);
}
[Fact]
public void GetTable_ByType_ReturnsCorrectTable() {
// Arrange
var config = new HopFrameConfig();
var contextConfig = new DbContextConfig(typeof(MockDbContext));
var tableConfig = contextConfig.Tables[0];
config.Contexts.Add(contextConfig);
var provider = new Mock<IServiceProvider>();
provider.Setup(p => p.GetService(typeof(MockDbContext))).Returns(new MockDbContext());
var contextExplorer = new ContextExplorer(config, provider.Object, new Logger<ContextExplorer>(new LoggerFactory()));
// Act
var result = contextExplorer.GetTable(typeof(MockModel));
// Assert
Assert.NotNull(result);
Assert.Equal(tableConfig, result);
}
[Fact]
public void GetTableManager_ReturnsCorrectTableManager() {
// Arrange
var config = new HopFrameConfig();
var contextConfig = new DbContextConfig(typeof(MockDbContext));
var tableConfig = new TableConfig(contextConfig, typeof(MockModel), "Models", 0);
contextConfig.Tables.Add(tableConfig);
config.Contexts.Add(contextConfig);
var dbContext = new MockDbContext();
var provider = new Mock<IServiceProvider>();
provider.Setup(p => p.GetService(typeof(MockDbContext))).Returns(dbContext);
var contextExplorer = new ContextExplorer(config, provider.Object, new Logger<ContextExplorer>(new LoggerFactory()));
// Act
var tableManager = contextExplorer.GetTableManager("Models");
// Assert
Assert.NotNull(tableManager);
Assert.IsType<TableManager<MockModel>>(tableManager);
}
[Fact]
public void GetTableManager_ReturnsNullIfDbContextNotFound() {
// Arrange
var config = new HopFrameConfig();
var contextConfig = new DbContextConfig(typeof(MockDbContext));
var tableConfig = new TableConfig(contextConfig, typeof(MockModel), "MockModels", 0);
contextConfig.Tables.Add(tableConfig);
config.Contexts.Add(contextConfig);
var provider = new Mock<IServiceProvider>();
var contextExplorer = new ContextExplorer(config, provider.Object, new Logger<ContextExplorer>(new LoggerFactory()));
// Act
var tableManager = contextExplorer.GetTableManager("Models");
// Assert
Assert.Null(tableManager);
}
[Fact]
public void SeedTableData_SetsTableSeededFlag() {
// Arrange
var config = new HopFrameConfig();
var contextConfig = new DbContextConfig(typeof(MockDbContext));
var tableConfig = contextConfig.Tables[0];
config.Contexts.Add(contextConfig);
var provider = new Mock<IServiceProvider>();
provider.Setup(p => p.GetService(typeof(MockDbContext))).Returns(new MockDbContext());
var contextExplorer = new ContextExplorer(config, provider.Object, new Logger<ContextExplorer>(new LoggerFactory()));
// Act
contextExplorer.GetTable("Models");
// Assert
Assert.True(tableConfig.Seeded);
}
}

View File

@@ -0,0 +1,41 @@
using HopFrame.Core.Services.Implementations;
namespace HopFrame.Core.Tests.Services;
public class DefaultAuthHandlerTests {
[Fact]
public async Task IsAuthenticatedAsync_ReturnsTrue() {
// Arrange
var authHandler = new DefaultAuthHandler();
// Act
var result = await authHandler.IsAuthenticatedAsync(null);
// Assert
Assert.True(result);
}
[Fact]
public async Task IsAuthenticatedAsync_WithPolicy_ReturnsTrue() {
// Arrange
var authHandler = new DefaultAuthHandler();
// Act
var result = await authHandler.IsAuthenticatedAsync("TestPolicy");
// Assert
Assert.True(result);
}
[Fact]
public async Task GetCurrentUserDisplayNameAsync_ReturnsEmptyString() {
// Arrange
var authHandler = new DefaultAuthHandler();
// Act
var result = await authHandler.GetCurrentUserDisplayNameAsync();
// Assert
Assert.Equal(string.Empty, result);
}
}

View File

@@ -0,0 +1,192 @@
// ReSharper disable GenericEnumeratorNotDisposed
using HopFrame.Core.Config;
using HopFrame.Core.Services;
using HopFrame.Core.Services.Implementations;
using HopFrame.Core.Tests.Models;
using Microsoft.EntityFrameworkCore;
using Moq;
namespace HopFrame.Core.Tests.Services;
public class TableManagerTests {
private Mock<DbContext> CreateMockDbContext<TModel>(List<TModel> data) where TModel : class {
var dbContext = new Mock<DbContext>();
var dbSet = CreateMockDbSet(data);
dbContext.Setup(m => m.Set<TModel>()).Returns(dbSet.Object);
dbContext.Setup(m => m.Entry(It.IsAny<MockModel>())).Returns<MockModel>(entry => new MockDbContext().Entry(entry));
return dbContext;
}
private Mock<DbSet<TModel>> CreateMockDbSet<TModel>(List<TModel> data) where TModel : class {
var queryableData = data.AsQueryable();
var dbSet = new Mock<DbSet<TModel>>();
dbSet.As<IQueryable<TModel>>().Setup(m => m.Provider)
.Returns(new TestAsyncQueryProvider<TModel>(queryableData.Provider));
dbSet.As<IQueryable<TModel>>().Setup(m => m.Expression).Returns(queryableData.Expression);
dbSet.As<IQueryable<TModel>>().Setup(m => m.ElementType).Returns(queryableData.ElementType);
dbSet.As<IQueryable<TModel>>().Setup(m => m.GetEnumerator()).Returns(queryableData.GetEnumerator());
dbSet.As<IAsyncEnumerable<TModel>>().Setup(m => m.GetAsyncEnumerator(It.IsAny<CancellationToken>()))
.Returns(new TestAsyncEnumerator<TModel>(queryableData.GetEnumerator()));
dbSet.As<IQueryable<TModel>>().Setup(m => m.Provider)
.Returns(new TestAsyncQueryProvider<TModel>(queryableData.Provider));
dbSet.Setup(m => m.FindAsync(It.IsAny<object[]>())).ReturnsAsync((object[] ids) =>
data.FirstOrDefault(d => ids.Contains(d.GetType().GetProperty("Id")!.GetValue(d, null))));
return dbSet;
}
[Fact]
public void LoadPage_ReturnsPagedData() {
// Arrange
var data = new List<MockModel> {
new MockModel { Id = 1, Name = "Item1" },
new MockModel { Id = 2, Name = "Item2" },
new MockModel { Id = 3, Name = "Item3" }
};
var dbContext = CreateMockDbContext(data);
var config = new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "Models", 0);
var explorer = new Mock<IContextExplorer>();
var provider = new Mock<IServiceProvider>();
var manager = new TableManager<MockModel>(dbContext.Object, config, explorer.Object, provider.Object);
// Act
var result = manager.LoadPage(1, 2).ToList();
// Assert
Assert.Single(result);
Assert.Equal("Item3", ((MockModel)result[0]).Name);
}
[Fact]
public async Task Search_ReturnsMatchingData() {
// Arrange
var data = new List<MockModel> {
new MockModel { Id = 1, Name = "Item1" },
new MockModel { Id = 2, Name = "Item2" },
new MockModel { Id = 3, Name = "TestItem" }
};
var dbContext = CreateMockDbContext(data);
var config = new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "Models", 0);
config.Properties.Add(new PropertyConfig(typeof(MockModel).GetProperty("Name")!, config, 0)
{ Searchable = true });
var explorer = new Mock<IContextExplorer>();
var provider = new Mock<IServiceProvider>();
var manager = new TableManager<MockModel>(dbContext.Object, config, explorer.Object, provider.Object);
// Act
var (result, totalPages) = await manager.Search("Test", 0, 2);
// Assert
var collection = result as object[] ?? result.ToArray();
Assert.Single(collection);
Assert.Equal("TestItem", ((MockModel)collection.First()).Name);
Assert.Equal(1, totalPages);
}
[Fact]
public async Task TotalPages_ReturnsCorrectPageCount() {
// Arrange
var data = new List<MockModel> {
new MockModel { Id = 1, Name = "Item1" },
new MockModel { Id = 2, Name = "Item2" },
new MockModel { Id = 3, Name = "Item3" }
};
var dbContext = new MockDbContext();
var config = new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "Models", 0);
var explorer = new Mock<IContextExplorer>();
var provider = new Mock<IServiceProvider>();
var manager = new TableManager<MockModel>(dbContext, config, explorer.Object, provider.Object);
await dbContext.Models.AddRangeAsync(data);
await dbContext.SaveChangesAsync();
// Act
var totalPages = await manager.TotalPages(2);
// Assert
Assert.Equal(2, totalPages);
}
[Fact]
public async Task DeleteItem_RemovesItemFromDbSet() {
// Arrange
var data = new List<MockModel> {
new MockModel { Id = 1, Name = "Item1" },
new MockModel { Id = 2, Name = "Item2" }
};
var dbContext = CreateMockDbContext(data);
var config = new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "Models", 0);
var explorer = new Mock<IContextExplorer>();
var provider = new Mock<IServiceProvider>();
var manager = new TableManager<MockModel>(dbContext.Object, config, explorer.Object, provider.Object);
var item = data.First();
// Act
await manager.DeleteItem(item);
// Assert
dbContext.Verify(m => m.SaveChangesAsync(It.IsAny<CancellationToken>()), Times.Once);
dbContext.Verify(m => m.Set<MockModel>().Remove(item), Times.Once);
}
[Fact]
public async Task EditItem_SavesChanges() {
// Arrange
var data = new List<MockModel> {
new MockModel { Id = 1, Name = "Item1" }
};
var dbContext = CreateMockDbContext(data);
var config = new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "Models", 0);
var explorer = new Mock<IContextExplorer>();
var provider = new Mock<IServiceProvider>();
var manager = new TableManager<MockModel>(dbContext.Object, config, explorer.Object, provider.Object);
// Act
await manager.EditItem(data.First());
// Assert
dbContext.Verify(m => m.SaveChangesAsync(It.IsAny<CancellationToken>()), Times.Once);
}
[Fact]
public async Task AddItem_AddsItemToDbSet() {
// Arrange
var data = new List<MockModel>();
var dbContext = CreateMockDbContext(data);
var config = new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "Models", 0);
var explorer = new Mock<IContextExplorer>();
var provider = new Mock<IServiceProvider>();
var manager = new TableManager<MockModel>(dbContext.Object, config, explorer.Object, provider.Object);
var newItem = new MockModel { Id = 3, Name = "NewItem" };
// Act
await manager.AddItem(newItem);
// Assert
dbContext.Verify(m => m.SaveChangesAsync(It.IsAny<CancellationToken>()), Times.Once);
dbContext.Verify(m => m.Set<MockModel>().AddAsync(newItem, It.IsAny<CancellationToken>()), Times.Once);
}
[Fact]
public async Task RevertChanges_ReloadsItem() {
// Arrange
var data = new List<MockModel> {
new MockModel { Id = 1, Name = "Item1" }
};
var dbContext = CreateMockDbContext(data);
var config = new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "Models", 0);
var explorer = new Mock<IContextExplorer>();
var provider = new Mock<IServiceProvider>();
var manager = new TableManager<MockModel>(dbContext.Object, config, explorer.Object, provider.Object);
var item = data.First();
// Act
await manager.RevertChanges(item);
// Assert
dbContext.Verify(m => m.Entry(item), Times.Once);
}
}