Merge branch 'feature/unit-tests' into 'dev'
Resolve "Unit tests" Closes #14 See merge request leon.hoppe/hopframe!18
This commit was merged in pull request #56.
This commit is contained in:
39
.gitlab-ci.yml
Normal file
39
.gitlab-ci.yml
Normal 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
|
||||
161
.idea/.idea.HopFrame/.idea/workspace.xml
generated
161
.idea/.idea.HopFrame/.idea/workspace.xml
generated
@@ -9,17 +9,33 @@
|
||||
<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.Tests.Web/Components/Dialogs/HopFrameEditorTests.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/tests/HopFrame.Tests.Web/Components/Layout/HopFrameLayoutTests.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/tests/HopFrame.Tests.Web/Components/Layout/HopFrameNavigationTests.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/tests/HopFrame.Tests.Web/Components/Layout/HopFrameSideMenuTests.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/tests/HopFrame.Tests.Web/Components/Pages/HopFrameHomeTests.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/tests/HopFrame.Tests.Web/Components/Pages/HopFrameTablePageTests.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/tests/HopFrame.Tests.Web/Helpers/EnumerableExtensions.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/tests/HopFrame.Tests.Web/HopFrame.Tests.Web.csproj" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/tests/HopFrame.Tests.Web/Models/MyDbContext.cs" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/tests/HopFrame.Tests.Web/Models/MyTable.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$/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$/HopFrame.sln" beforeDir="false" afterPath="$PROJECT_DIR$/HopFrame.sln" 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" />
|
||||
<change beforePath="$PROJECT_DIR$/tests/HopFrame.Core.Tests/Config/DbContextConfiguratorTests.cs" beforeDir="false" afterPath="$PROJECT_DIR$/tests/HopFrame.Tests.Core/Config/DbContextConfiguratorTests.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/tests/HopFrame.Core.Tests/Config/HopFrameConfiguratorTests.cs" beforeDir="false" afterPath="$PROJECT_DIR$/tests/HopFrame.Tests.Core/Config/HopFrameConfiguratorTests.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/tests/HopFrame.Core.Tests/Config/PropertyConfiguratorTests.cs" beforeDir="false" afterPath="$PROJECT_DIR$/tests/HopFrame.Tests.Core/Config/PropertyConfiguratorTests.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/tests/HopFrame.Core.Tests/Config/TableConfiguratorTests.cs" beforeDir="false" afterPath="$PROJECT_DIR$/tests/HopFrame.Tests.Core/Config/TableConfiguratorTests.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/tests/HopFrame.Core.Tests/HopFrame.Core.Tests.csproj" beforeDir="false" afterPath="$PROJECT_DIR$/tests/HopFrame.Tests.Core/HopFrame.Tests.Core.csproj" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/tests/HopFrame.Core.Tests/Models/MockDbContext.cs" beforeDir="false" afterPath="$PROJECT_DIR$/tests/HopFrame.Tests.Core/Models/MockDbContext.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/tests/HopFrame.Core.Tests/Models/MockModel.cs" beforeDir="false" afterPath="$PROJECT_DIR$/tests/HopFrame.Tests.Core/Models/MockModel.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/tests/HopFrame.Core.Tests/Models/MockModel2.cs" beforeDir="false" afterPath="$PROJECT_DIR$/tests/HopFrame.Tests.Core/Models/MockModel2.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/tests/HopFrame.Core.Tests/Models/QueryProvider.cs" beforeDir="false" afterPath="$PROJECT_DIR$/tests/HopFrame.Tests.Core/Models/QueryProvider.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/tests/HopFrame.Core.Tests/Services/ContextExplorerTests.cs" beforeDir="false" afterPath="$PROJECT_DIR$/tests/HopFrame.Tests.Core/Services/ContextExplorerTests.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/tests/HopFrame.Core.Tests/Services/DefaultAuthHandlerTests.cs" beforeDir="false" afterPath="$PROJECT_DIR$/tests/HopFrame.Tests.Core/Services/DefaultAuthHandlerTests.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/tests/HopFrame.Core.Tests/Services/DisplayPropertyTests.cs" beforeDir="false" afterPath="$PROJECT_DIR$/tests/HopFrame.Tests.Core/Services/DisplayPropertyTests.cs" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/tests/HopFrame.Core.Tests/Services/TableManagerTests.cs" beforeDir="false" afterPath="$PROJECT_DIR$/tests/HopFrame.Tests.Core/Services/TableManagerTests.cs" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
@@ -39,7 +55,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 +83,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">{
|
||||
@@ -92,24 +102,26 @@
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
".NET Launch Settings Profile.HopFrame.Testing.executor": "Run",
|
||||
".NET Launch Settings Profile.HopFrame.Testing: https.executor": "Run",
|
||||
".NET Project.HopFrame.Testing.executor": "Run",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.git.unshallow": "true",
|
||||
"git-widget-placeholder": "!17 on feature/documentation",
|
||||
"list.type.of.created.stylesheet": "CSS",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.detected.package.tslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"node.js.selected.package.tslint": "(autodetect)",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"settings.editor.selected.configurable": "preferences.environmentSetup",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
<component name="PropertiesComponent">{
|
||||
"keyToString": {
|
||||
".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",
|
||||
"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",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"node.js.selected.package.tslint": "(autodetect)",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"settings.editor.selected.configurable": "preferences.environmentSetup",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
}
|
||||
}]]></component>
|
||||
}</component>
|
||||
<component name="RunManager" selected=".NET Launch Settings Profile.HopFrame.Testing: https">
|
||||
<configuration name="HopFrame.Testing: http" type="LaunchSettings" factoryName=".NET Launch Settings Profile">
|
||||
<option name="LAUNCH_PROFILE_PROJECT_FILE_PATH" value="$PROJECT_DIR$/testing/HopFrame.Testing/HopFrame.Testing.csproj" />
|
||||
@@ -166,7 +178,10 @@
|
||||
<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="4612000" />
|
||||
<workItem from="1737281957060" duration="3232000" />
|
||||
<workItem from="1737293153907" duration="5484000" />
|
||||
</task>
|
||||
<task id="LOCAL-00001" summary="Added basic configuration">
|
||||
<option name="closed" value="true" />
|
||||
@@ -288,12 +303,77 @@
|
||||
<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>
|
||||
<task id="LOCAL-00017" summary="Created tests for the core module">
|
||||
<option name="closed" value="true" />
|
||||
<created>1737212497960</created>
|
||||
<option name="number" value="00017" />
|
||||
<option name="presentableId" value="LOCAL-00017" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1737212497960</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00018" summary="Added more tests">
|
||||
<option name="closed" value="true" />
|
||||
<created>1737285123218</created>
|
||||
<option name="number" value="00018" />
|
||||
<option name="presentableId" value="LOCAL-00018" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1737285123218</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="19" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="3" />
|
||||
</component>
|
||||
<component name="UnitTestsCoverage.Settings">
|
||||
<option name="coveragePercentColumnWidth" value="131" />
|
||||
<option name="sortOrder" value="DESCENDING" />
|
||||
<option name="sortedColumn" value="1" />
|
||||
<option name="symbolColumnWidth" value="457" />
|
||||
<coverage-tree-state>
|
||||
<expand>
|
||||
<path>
|
||||
<item name="rootNode" type="c53c71d1:RiderDotCoverCoverageTreeModel$RootNode" />
|
||||
<item name="Total 61% 571/1454" type="8b8fad3a:RiderDotCoverCoverageTreeNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="rootNode" type="c53c71d1:RiderDotCoverCoverageTreeModel$RootNode" />
|
||||
<item name="Total 61% 571/1454" type="8b8fad3a:RiderDotCoverCoverageTreeNode" />
|
||||
<item name="Core 46% 401/743" type="8b8fad3a:RiderDotCoverCoverageTreeNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="rootNode" type="c53c71d1:RiderDotCoverCoverageTreeModel$RootNode" />
|
||||
<item name="Total 61% 571/1454" type="8b8fad3a:RiderDotCoverCoverageTreeNode" />
|
||||
<item name="Core 46% 401/743" type="8b8fad3a:RiderDotCoverCoverageTreeNode" />
|
||||
<item name="HopFrame.Core 93% 25/367" type="8b8fad3a:RiderDotCoverCoverageTreeNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="rootNode" type="c53c71d1:RiderDotCoverCoverageTreeModel$RootNode" />
|
||||
<item name="Total 61% 571/1454" type="8b8fad3a:RiderDotCoverCoverageTreeNode" />
|
||||
<item name="Core 46% 401/743" type="8b8fad3a:RiderDotCoverCoverageTreeNode" />
|
||||
<item name="HopFrame.Core 93% 25/367" type="8b8fad3a:RiderDotCoverCoverageTreeNode" />
|
||||
<item name="HopFrame.Core 93% 25/367" type="8b8fad3a:RiderDotCoverCoverageTreeNode" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="rootNode" type="c53c71d1:RiderDotCoverCoverageTreeModel$RootNode" />
|
||||
<item name="Total 61% 571/1454" type="8b8fad3a:RiderDotCoverCoverageTreeNode" />
|
||||
<item name="Core 46% 401/743" type="8b8fad3a:RiderDotCoverCoverageTreeNode" />
|
||||
<item name="HopFrame.Core 93% 25/367" type="8b8fad3a:RiderDotCoverCoverageTreeNode" />
|
||||
<item name="HopFrame.Core 93% 25/367" type="8b8fad3a:RiderDotCoverCoverageTreeNode" />
|
||||
<item name="Services.Implementations 96% 5/136" type="8b8fad3a:RiderDotCoverCoverageTreeNode" />
|
||||
</path>
|
||||
</expand>
|
||||
<select />
|
||||
</coverage-tree-state>
|
||||
</component>
|
||||
<component name="UnityCheckinConfiguration" checkUnsavedScenes="true" />
|
||||
<component name="UnityProjectConfiguration" hasMinimizedUI="false" />
|
||||
<component name="VcsManagerConfiguration">
|
||||
@@ -313,6 +393,9 @@
|
||||
<MESSAGE value="Added n -> 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" />
|
||||
<MESSAGE value="Created tests for the core module" />
|
||||
<MESSAGE value="Added more tests" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="Added more tests" />
|
||||
</component>
|
||||
</project>
|
||||
16
HopFrame.sln
16
HopFrame.sln
@@ -10,6 +10,12 @@ 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.Tests.Core", "tests\HopFrame.Tests.Core\HopFrame.Tests.Core.csproj", "{2E2D29E0-53FA-462D-B4D2-4678CD106E29}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HopFrame.Tests.Web", "tests\HopFrame.Tests.Web\HopFrame.Tests.Web.csproj", "{7AB4F4FF-E938-4A40-A7EB-7B2063262896}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -19,6 +25,8 @@ 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}
|
||||
{7AB4F4FF-E938-4A40-A7EB-7B2063262896} = {141928CB-5977-4285-A986-5BD785F2883C}
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{4BFE21C2-EAAC-4662-8B97-500836651B2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
@@ -33,5 +41,13 @@ 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
|
||||
{7AB4F4FF-E938-4A40-A7EB-7B2063262896}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7AB4F4FF-E938-4A40-A7EB-7B2063262896}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7AB4F4FF-E938-4A40-A7EB-7B2063262896}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7AB4F4FF-E938-4A40-A7EB-7B2063262896}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using HopFrame.Core.Services;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace HopFrame.Core.Config;
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Collections;
|
||||
using System.Linq.Expressions;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace HopFrame.Core.Config;
|
||||
@@ -21,9 +20,9 @@ public class PropertyConfig(PropertyInfo info, TableConfig table, int nthPropert
|
||||
public bool DisplayValue { get; set; } = true;
|
||||
public bool TextArea { get; set; }
|
||||
public int TextAreaRows { get; set; } = 16;
|
||||
public bool IsRelation { get; set; }
|
||||
public bool IsRequired { get; set; }
|
||||
public bool IsEnumerable { get; set; }
|
||||
public bool IsRelation { get; internal set; }
|
||||
public bool IsRequired { get; internal set; }
|
||||
public bool IsEnumerable { get; internal set; }
|
||||
public bool IsListingProperty { get; set; }
|
||||
public int Order { get; set; } = nthProperty;
|
||||
}
|
||||
@@ -99,10 +99,11 @@ public class TableConfigurator<TModel>(TableConfig config) {
|
||||
/// <returns>The configurator for the virtual property</returns>
|
||||
/// <seealso cref="PropertyConfigurator{TProp}"/>
|
||||
public PropertyConfigurator<string> AddVirtualProperty(string name, Func<TModel, IServiceProvider, string> template) {
|
||||
var prop = new PropertyConfig(InnerConfig.Properties.First().Info, InnerConfig, InnerConfig.Properties.Count);
|
||||
prop.Name = name;
|
||||
prop.IsListingProperty = true;
|
||||
prop.Formatter = (obj, provider) => template.Invoke((TModel)obj, provider);
|
||||
var prop = new PropertyConfig(InnerConfig.Properties.First().Info, InnerConfig, InnerConfig.Properties.Count) {
|
||||
Name = name,
|
||||
IsListingProperty = true,
|
||||
Formatter = (obj, provider) => template.Invoke((TModel)obj, provider)
|
||||
};
|
||||
InnerConfig.Properties.Add(prop);
|
||||
return new PropertyConfigurator<string>(prop);
|
||||
}
|
||||
@@ -10,4 +10,10 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
|
||||
<_Parameter1>HopFrame.Tests.Core</_Parameter1>
|
||||
</AssemblyAttribute>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -9,7 +9,7 @@ internal sealed class TableManager<TModel>(DbContext context, TableConfig config
|
||||
|
||||
public IQueryable<object> LoadPage(int page, int perPage = 20) {
|
||||
var table = context.Set<TModel>();
|
||||
var data = IncludeForgeinKeys(table);
|
||||
var data = IncludeForeignKeys(table);
|
||||
return data
|
||||
.Skip(page * perPage)
|
||||
.Take(perPage);
|
||||
@@ -17,7 +17,7 @@ internal sealed class TableManager<TModel>(DbContext context, TableConfig config
|
||||
|
||||
public Task<(IEnumerable<object>, int)> Search(string searchTerm, int page = 0, int perPage = 20) {
|
||||
var table = context.Set<TModel>();
|
||||
var all = IncludeForgeinKeys(table)
|
||||
var all = IncludeForeignKeys(table)
|
||||
.AsEnumerable()
|
||||
.Where(item => ItemSearched(item, searchTerm))
|
||||
.ToList();
|
||||
@@ -101,6 +101,8 @@ internal sealed class TableManager<TModel>(DbContext context, TableConfig config
|
||||
}
|
||||
|
||||
var innerConfig = explorer.GetTable(propValue.GetType());
|
||||
if (innerConfig is null) return propValue.ToString()!;
|
||||
|
||||
var innerProp = innerConfig!.Properties
|
||||
.SingleOrDefault(p => p.Info == prop.DisplayedProperty && !p.IsListingProperty);
|
||||
|
||||
@@ -108,14 +110,10 @@ internal sealed class TableManager<TModel>(DbContext context, TableConfig config
|
||||
return DisplayProperty(propValue, innerProp);
|
||||
}
|
||||
|
||||
private IQueryable<TModel> IncludeForgeinKeys(IQueryable<TModel> query) {
|
||||
var pendingQuery = query;
|
||||
|
||||
foreach (var property in config.Properties.Where(prop => prop.IsRelation)) {
|
||||
pendingQuery = pendingQuery.Include(property.Info.Name);
|
||||
}
|
||||
|
||||
return pendingQuery;
|
||||
private IQueryable<TModel> IncludeForeignKeys(IQueryable<TModel> query) {
|
||||
return config.Properties
|
||||
.Where(prop => prop.IsRelation)
|
||||
.Aggregate(query, (current, property) => current.Include(property.Info.Name));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,6 +11,10 @@
|
||||
<SupportedPlatform Include="browser"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="9.0.0"/>
|
||||
<PackageReference Include="Microsoft.FluentUI.AspNetCore.Components" Version="4.11.2" />
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using HopFrame.Core;
|
||||
using HopFrame.Core.Config;
|
||||
using HopFrame.Web.Components.Pages;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.FluentUI.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
|
||||
namespace HopFrame.Web;
|
||||
|
||||
@@ -33,5 +35,12 @@ public static class ServiceCollectionExtensions {
|
||||
services.AddFluentUIComponents(fluentUiLibraryConfiguration);
|
||||
return services;
|
||||
}
|
||||
|
||||
public static RazorComponentsEndpointConventionBuilder MapHopFramePages(this RazorComponentsEndpointConventionBuilder builder) {
|
||||
builder
|
||||
.AddInteractiveServerRenderMode()
|
||||
.AddAdditionalAssemblies(typeof(HopFrameHome).Assembly);
|
||||
return builder;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -94,6 +94,6 @@ app.UseAntiforgery();
|
||||
app.MapStaticAssets();
|
||||
app.MapRazorComponents<App>()
|
||||
.AddInteractiveServerRenderMode()
|
||||
.AddAdditionalAssemblies(typeof(HopFrameHome).Assembly);
|
||||
.MapHopFramePages();
|
||||
|
||||
app.Run();
|
||||
@@ -0,0 +1,34 @@
|
||||
using HopFrame.Core.Config;
|
||||
using HopFrame.Tests.Core.Models;
|
||||
using Moq;
|
||||
|
||||
namespace HopFrame.Tests.Core.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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
using HopFrame.Core.Config;
|
||||
using HopFrame.Tests.Core.Models;
|
||||
|
||||
namespace HopFrame.Tests.Core.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 AddDbContext_WithConfigurator_AddsDbContextToInnerConfig() {
|
||||
// Arrange
|
||||
var config = new HopFrameConfig();
|
||||
var configurator = new HopFrameConfigurator(config);
|
||||
|
||||
// Act
|
||||
object dbContextConfigurator = null!;
|
||||
configurator.AddDbContext<MockDbContext>(context => {
|
||||
dbContextConfigurator = context;
|
||||
});
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
225
tests/HopFrame.Tests.Core/Config/PropertyConfiguratorTests.cs
Normal file
225
tests/HopFrame.Tests.Core/Config/PropertyConfiguratorTests.cs
Normal file
@@ -0,0 +1,225 @@
|
||||
using System.Linq.Expressions;
|
||||
using HopFrame.Core.Config;
|
||||
using HopFrame.Tests.Core.Models;
|
||||
|
||||
namespace HopFrame.Tests.Core.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);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_SetsTableProperty() {
|
||||
// Arrange
|
||||
var tableConfig = new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "MockModels", 0);
|
||||
|
||||
// Act
|
||||
var propertyConfig = new PropertyConfig(typeof(MockModel).GetProperty("Id")!, tableConfig, 0);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(propertyConfig.Table);
|
||||
Assert.Equal(tableConfig, propertyConfig.Table);
|
||||
}
|
||||
}
|
||||
211
tests/HopFrame.Tests.Core/Config/TableConfiguratorTests.cs
Normal file
211
tests/HopFrame.Tests.Core/Config/TableConfiguratorTests.cs
Normal file
@@ -0,0 +1,211 @@
|
||||
using System.Linq.Expressions;
|
||||
using HopFrame.Core.Config;
|
||||
using HopFrame.Tests.Core.Models;
|
||||
|
||||
namespace HopFrame.Tests.Core.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);
|
||||
}
|
||||
|
||||
public void Property_WithConfigurator_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
|
||||
object propertyConfigurator = null!;
|
||||
configurator.Property(propertyExpression, c => {
|
||||
propertyConfigurator = c;
|
||||
});
|
||||
|
||||
// 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 AddVirtualProperty_WithConfigurator_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
|
||||
object propertyConfigurator = null!;
|
||||
configurator.AddVirtualProperty("VirtualName", template, c => {
|
||||
propertyConfigurator = c;
|
||||
});
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WithKeyProperty_DisablesEdit() {
|
||||
// Act
|
||||
var tableConfig = new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel2), "Models2", 0);
|
||||
var prop = tableConfig.Properties.SingleOrDefault(prop => prop.Info.Name == nameof(MockModel2.Id));
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(prop);
|
||||
Assert.False(prop.Editable);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WithGeneratedProperty_DisablesEditAndCreate() {
|
||||
// Act
|
||||
var tableConfig = new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel2), "Models2", 0);
|
||||
var prop = tableConfig.Properties.SingleOrDefault(prop => prop.Info.Name == nameof(MockModel2.Number));
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(prop);
|
||||
Assert.False(prop.Editable);
|
||||
Assert.False(prop.Creatable);
|
||||
}
|
||||
}
|
||||
27
tests/HopFrame.Tests.Core/HopFrame.Tests.Core.csproj
Normal file
27
tests/HopFrame.Tests.Core/HopFrame.Tests.Core.csproj
Normal 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>
|
||||
13
tests/HopFrame.Tests.Core/Models/MockDbContext.cs
Normal file
13
tests/HopFrame.Tests.Core/Models/MockDbContext.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace HopFrame.Tests.Core.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));
|
||||
}
|
||||
}
|
||||
12
tests/HopFrame.Tests.Core/Models/MockModel.cs
Normal file
12
tests/HopFrame.Tests.Core/Models/MockModel.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace HopFrame.Tests.Core.Models;
|
||||
|
||||
// A mock model for testing purposes
|
||||
public class MockModel {
|
||||
public int Id { get; set; }
|
||||
public string? Name { get; set; }
|
||||
|
||||
[ForeignKey("other")]
|
||||
public List<MockModel2> Model2 { get; set; }
|
||||
}
|
||||
12
tests/HopFrame.Tests.Core/Models/MockModel2.cs
Normal file
12
tests/HopFrame.Tests.Core/Models/MockModel2.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace HopFrame.Tests.Core.Models;
|
||||
|
||||
public class MockModel2 {
|
||||
[Key]
|
||||
public required string Id { get; set; }
|
||||
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public int Number { get; set; }
|
||||
}
|
||||
129
tests/HopFrame.Tests.Core/Models/QueryProvider.cs
Normal file
129
tests/HopFrame.Tests.Core/Models/QueryProvider.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
using System.Linq.Expressions;
|
||||
using Microsoft.EntityFrameworkCore.Query;
|
||||
|
||||
namespace HopFrame.Tests.Core.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());
|
||||
}
|
||||
}*/
|
||||
221
tests/HopFrame.Tests.Core/Services/ContextExplorerTests.cs
Normal file
221
tests/HopFrame.Tests.Core/Services/ContextExplorerTests.cs
Normal file
@@ -0,0 +1,221 @@
|
||||
using HopFrame.Core.Config;
|
||||
using HopFrame.Core.Services.Implementations;
|
||||
using HopFrame.Tests.Core.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Moq;
|
||||
|
||||
namespace HopFrame.Tests.Core.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_ByDisplayName_ReturnsNullIfTableNotFound() {
|
||||
// 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("InvalidTable");
|
||||
|
||||
// Assert
|
||||
Assert.Null(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 GetTable_ByType_ReturnsNullIfTableNotFound() {
|
||||
// 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(ContextExplorerTests));
|
||||
|
||||
// Assert
|
||||
Assert.Null(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 GetTableManager_ReturnsNullIfTableNotFound() {
|
||||
// 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("InvalidTable");
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SeedTableData_SetsTablePropertiesCorrectly() {
|
||||
// Arrange
|
||||
var config = new HopFrameConfig();
|
||||
var contextConfig = new DbContextConfig(typeof(MockDbContext));
|
||||
var tableConfig = contextConfig.Tables[0];
|
||||
var tableConfig2 = contextConfig.Tables[1];
|
||||
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");
|
||||
contextExplorer.GetTable("Models2");
|
||||
|
||||
// Assert
|
||||
var relationProp = tableConfig.Properties.SingleOrDefault(prop => prop.Info.Name == nameof(MockModel.Model2));
|
||||
var keyProp = tableConfig2.Properties.SingleOrDefault(prop => prop.Info.Name == nameof(MockModel2.Id));
|
||||
Assert.NotNull(relationProp);
|
||||
Assert.NotNull(keyProp);
|
||||
Assert.True(relationProp.IsRelation);
|
||||
Assert.True(relationProp.IsEnumerable);
|
||||
Assert.True(keyProp.IsRequired);
|
||||
Assert.False(keyProp.IsRelation);
|
||||
Assert.False(keyProp.IsEnumerable);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using HopFrame.Core.Services.Implementations;
|
||||
|
||||
namespace HopFrame.Tests.Core.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);
|
||||
}
|
||||
}
|
||||
199
tests/HopFrame.Tests.Core/Services/DisplayPropertyTests.cs
Normal file
199
tests/HopFrame.Tests.Core/Services/DisplayPropertyTests.cs
Normal file
@@ -0,0 +1,199 @@
|
||||
using HopFrame.Core.Config;
|
||||
using HopFrame.Core.Services;
|
||||
using HopFrame.Core.Services.Implementations;
|
||||
using HopFrame.Tests.Core.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Moq;
|
||||
|
||||
namespace HopFrame.Tests.Core.Services;
|
||||
|
||||
public class DisplayPropertyTests {
|
||||
private readonly Mock<IServiceProvider> _providerMock;
|
||||
private readonly Mock<IContextExplorer> _explorerMock;
|
||||
private readonly TableConfig _config;
|
||||
private readonly TableManager<object> _tableManager;
|
||||
|
||||
public DisplayPropertyTests() {
|
||||
var contextMock = new Mock<DbContext>();
|
||||
_providerMock = new Mock<IServiceProvider>();
|
||||
_explorerMock = new Mock<IContextExplorer>();
|
||||
_config = new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "Models", 0);
|
||||
_tableManager =
|
||||
new TableManager<object>(contextMock.Object, _config, _explorerMock.Object, _providerMock.Object);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DisplayProperty_ReturnsEmptyString_WhenItemIsNull() {
|
||||
// Arrange
|
||||
var prop = new PropertyConfig(typeof(string).GetProperty("Length")!, _config, 0);
|
||||
|
||||
// Act
|
||||
var result = _tableManager.DisplayProperty(null, prop);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(string.Empty, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DisplayProperty_UsesFormatter_WhenListingProperty() {
|
||||
// Arrange
|
||||
var item = "test";
|
||||
var prop = new PropertyConfig(typeof(string).GetProperty("Length")!, _config, 0) {
|
||||
IsListingProperty = true,
|
||||
Formatter = (obj, provider) => ((string)obj).ToUpper()
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _tableManager.DisplayProperty(item, prop);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("TEST", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DisplayProperty_UsesValueFormatter_WhenNotListingProperty() {
|
||||
// Arrange
|
||||
var item = "test";
|
||||
var prop = new PropertyConfig(typeof(string).GetProperty("Length")!, _config, 0) {
|
||||
Formatter = (obj, provider) => ((int)obj).ToString("D4")
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _tableManager.DisplayProperty(item, prop);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("0004", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DisplayProperty_ReturnsValueAsString_WhenNoFormatter() {
|
||||
// Arrange
|
||||
var item = "test";
|
||||
var prop = new PropertyConfig(typeof(string).GetProperty("Length")!, _config, 0);
|
||||
|
||||
// Act
|
||||
var result = _tableManager.DisplayProperty(item, prop);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("4", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DisplayProperty_ReturnsEnumerableCount_WhenEnumerableProperty() {
|
||||
// Arrange
|
||||
var item = new { List = new List<int> { 1, 2, 3 } };
|
||||
var prop = new PropertyConfig(item.GetType().GetProperty("List")!, _config, 0) {
|
||||
IsEnumerable = true
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _tableManager.DisplayProperty(item, prop);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("3", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DisplayProperty_UsesDisplayedProperty_WhenNoDirectFormatter() {
|
||||
// Arrange
|
||||
var item = new { Inner = new { Key = 42 } };
|
||||
var innerPropInfo = item.Inner.GetType().GetProperty("Key");
|
||||
var innerPropConfig = new PropertyConfig(innerPropInfo!, _config, 0);
|
||||
var propInfo = item.GetType().GetProperty("Inner");
|
||||
var prop = new PropertyConfig(propInfo!, _config, 0) {
|
||||
DisplayedProperty = innerPropInfo
|
||||
};
|
||||
|
||||
_explorerMock
|
||||
.Setup(e => e.GetTable(item.Inner.GetType()))
|
||||
.Returns(new TableConfig(new DbContextConfig(typeof(MockDbContext)), typeof(MockModel), "Models", 0) {
|
||||
Properties = { innerPropConfig }
|
||||
});
|
||||
|
||||
// Act
|
||||
var result = _tableManager.DisplayProperty(item, prop);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("42", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DisplayProperty_ReturnsEmptyString_WhenPropValueIsNull() {
|
||||
// Arrange
|
||||
var item = new { Name = (string?)null };
|
||||
var prop = new PropertyConfig(item.GetType().GetProperty("Name")!, _config, 0);
|
||||
|
||||
// Act
|
||||
var result = _tableManager.DisplayProperty(item, prop);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(string.Empty, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DisplayProperty_UsesEnumerableFormatter_WhenEnumerableAndValueProvided() {
|
||||
// Arrange
|
||||
var item = new { List = new List<int> { 1, 2, 3 } };
|
||||
var prop = new PropertyConfig(item.GetType().GetProperty("List")!, _config, 0) {
|
||||
IsEnumerable = true,
|
||||
EnumerableFormatter = (obj, provider) => string.Join(",", ((IEnumerable<int>)obj))
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = _tableManager.DisplayProperty(item, prop, item.List);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("1,2,3", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DisplayProperty_ReturnsEmptyString_WhenDisplayedPropertyAndInnerConfigIsNull() {
|
||||
// Arrange
|
||||
var item = new { Inner = new { Key = 42 } };
|
||||
var innerPropInfo = item.Inner.GetType().GetProperty("Key");
|
||||
var propInfo = item.GetType().GetProperty("Inner");
|
||||
var prop = new PropertyConfig(propInfo!, _config, 0) {
|
||||
DisplayedProperty = innerPropInfo
|
||||
};
|
||||
|
||||
_explorerMock
|
||||
.Setup(e => e.GetTable(item.Inner.GetType()))
|
||||
.Returns((TableConfig?)null);
|
||||
|
||||
// Act
|
||||
var result = _tableManager.DisplayProperty(item, prop);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("{ Key = 42 }", result); // Returns the value as string if inner config is null
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DisplayProperty_ReturnsKeyValue_WhenDisplayedPropertyIsNull() {
|
||||
// Arrange
|
||||
var item = new { Inner = new { Key = 42 } };
|
||||
var propInfo = item.GetType().GetProperty("Inner");
|
||||
var prop = new PropertyConfig(propInfo!, _config, 0);
|
||||
|
||||
var keyProperty = item.Inner.GetType().GetProperty("Key");
|
||||
|
||||
// Act
|
||||
var result = _tableManager.DisplayProperty(item, prop);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("{ Key = 42 }", result); // Returns key value as string if DisplayedProperty is null
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DisplayProperty_ReturnsToStringValue_WhenNoKeyOrDisplayedProperty() {
|
||||
// Arrange
|
||||
var item = new { Inner = new { Name = "Test" } };
|
||||
var propInfo = item.GetType().GetProperty("Inner");
|
||||
var prop = new PropertyConfig(propInfo!, _config, 0);
|
||||
|
||||
// Act
|
||||
var result = _tableManager.DisplayProperty(item, prop);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("{ Name = Test }", result); // Returns ToString value of inner property
|
||||
}
|
||||
}
|
||||
192
tests/HopFrame.Tests.Core/Services/TableManagerTests.cs
Normal file
192
tests/HopFrame.Tests.Core/Services/TableManagerTests.cs
Normal file
@@ -0,0 +1,192 @@
|
||||
// ReSharper disable GenericEnumeratorNotDisposed
|
||||
|
||||
using HopFrame.Core.Config;
|
||||
using HopFrame.Core.Services;
|
||||
using HopFrame.Core.Services.Implementations;
|
||||
using HopFrame.Tests.Core.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Moq;
|
||||
|
||||
namespace HopFrame.Tests.Core.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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using Bunit;
|
||||
using HopFrame.Core.Config;
|
||||
using HopFrame.Core.Services;
|
||||
using HopFrame.Tests.Web.Models;
|
||||
using HopFrame.Web;
|
||||
using HopFrame.Web.Components.Dialogs;
|
||||
using HopFrame.Web.Models;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.FluentUI.AspNetCore.Components;
|
||||
using Moq;
|
||||
|
||||
namespace HopFrame.Tests.Web.Components.Dialogs;
|
||||
|
||||
public class HopFrameEditorTests : TestContext {
|
||||
[Fact]
|
||||
public void Renders_Properties_Correctly() {
|
||||
// Arrange
|
||||
var contextExplorerMock = new Mock<IContextExplorer>();
|
||||
var authHandlerMock = new Mock<IHopFrameAuthHandler>();
|
||||
var dialogServiceMock = new Mock<IDialogService>();
|
||||
var toastServiceMock = new Mock<IToastService>();
|
||||
var serviceProviderMock = new Mock<IServiceProvider>();
|
||||
var contextConfig = new DbContextConfig(typeof(MyDbContext));
|
||||
var tableConfig = new TableConfig(contextConfig, typeof(MyTable), "Table1", 0) {
|
||||
DisplayName = "Table1",
|
||||
ViewPolicy = "Policy1"
|
||||
};
|
||||
contextConfig.Tables.Add(tableConfig);
|
||||
var config = new HopFrameConfig() {
|
||||
Contexts = { contextConfig }
|
||||
};
|
||||
|
||||
contextExplorerMock.Setup(e => e.GetTable("Table1")).Returns(tableConfig);
|
||||
contextExplorerMock.Setup(e => e.GetTableManager("Table1")).Returns(Mock.Of<ITableManager>());
|
||||
authHandlerMock.Setup(h => h.IsAuthenticatedAsync(It.IsAny<string>())).ReturnsAsync(true);
|
||||
|
||||
Services.AddHopFrame(config);
|
||||
Services.AddSingleton(contextExplorerMock.Object);
|
||||
Services.AddSingleton(authHandlerMock.Object);
|
||||
Services.AddSingleton(dialogServiceMock.Object);
|
||||
Services.AddSingleton(toastServiceMock.Object);
|
||||
Services.AddSingleton(serviceProviderMock.Object);
|
||||
|
||||
JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var dialogData = new EditorDialogData(tableConfig, new MyTable());
|
||||
var dialog = new FluentDialog() {
|
||||
Instance = new DialogInstance(typeof(HopFrameEditor), new DialogParameters(), dialogData)
|
||||
};
|
||||
|
||||
// Act
|
||||
var cut = RenderComponent<HopFrameEditor>(parameters => parameters
|
||||
.Add(p => p.Content, dialogData)
|
||||
.Add(p => p.Dialog, dialog));
|
||||
|
||||
// Assert
|
||||
var dialogBody = cut.FindComponent<FluentDialogBody>();
|
||||
Assert.NotNull(dialogBody);
|
||||
|
||||
var textFields = cut.FindComponents<FluentNumberField<double>>();
|
||||
Assert.Single(textFields);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
using Bunit;
|
||||
using Bunit.TestDoubles;
|
||||
using HopFrame.Core.Config;
|
||||
using HopFrame.Core.Services;
|
||||
using HopFrame.Web;
|
||||
using HopFrame.Web.Components.Layout;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.FluentUI.AspNetCore.Components;
|
||||
using Moq;
|
||||
|
||||
namespace HopFrame.Tests.Web.Components.Layout;
|
||||
|
||||
public class HopFrameLayoutTests : TestContext {
|
||||
[Fact]
|
||||
public void Renders_HopFrameLayout_Components() {
|
||||
// Arrange
|
||||
var authHandlerMock = new Mock<IHopFrameAuthHandler>();
|
||||
var config = new HopFrameConfig {
|
||||
DisplayUserInfo = true,
|
||||
BasePolicy = "SomePolicy",
|
||||
LoginPageRewrite = "/login"
|
||||
};
|
||||
|
||||
authHandlerMock.Setup(h => h.IsAuthenticatedAsync("SomePolicy"))
|
||||
.ReturnsAsync(true);
|
||||
|
||||
Services.AddSingleton(authHandlerMock.Object);
|
||||
Services.AddHopFrame(config);
|
||||
|
||||
JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
// Act
|
||||
var cut = RenderComponent<HopFrameLayout>();
|
||||
|
||||
// Assert
|
||||
var header = cut.FindComponent<FluentHeader>();
|
||||
Assert.NotNull(header);
|
||||
|
||||
var navigation = cut.FindComponent<HopFrameNavigation>();
|
||||
Assert.NotNull(navigation);
|
||||
|
||||
var sideMenu = cut.FindComponent<HopFrameSideMenu>();
|
||||
Assert.NotNull(sideMenu);
|
||||
|
||||
var footer = cut.FindComponent<FluentFooter>();
|
||||
Assert.NotNull(footer);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Redirects_To_Login_When_Not_Authorized() {
|
||||
// Arrange
|
||||
var authHandlerMock = new Mock<IHopFrameAuthHandler>();
|
||||
var navMock = new FakeNavigationManager(this);
|
||||
var config = new HopFrameConfig {
|
||||
DisplayUserInfo = true,
|
||||
BasePolicy = "SomePolicy",
|
||||
LoginPageRewrite = "/login"
|
||||
};
|
||||
|
||||
authHandlerMock.Setup(h => h.IsAuthenticatedAsync("SomePolicy"))
|
||||
.ReturnsAsync(false);
|
||||
|
||||
Services.AddSingleton(navMock);
|
||||
Services.AddHopFrame(config);
|
||||
Services.AddSingleton(authHandlerMock.Object);
|
||||
|
||||
JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
// Act
|
||||
var cut = RenderComponent<HopFrameLayout>();
|
||||
|
||||
// Assert
|
||||
Assert.Equal("http://localhost/login?redirect=/", navMock.Uri);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using Bunit;
|
||||
using HopFrame.Core.Config;
|
||||
using HopFrame.Core.Services;
|
||||
using HopFrame.Web;
|
||||
using HopFrame.Web.Components.Layout;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.FluentUI.AspNetCore.Components;
|
||||
using Moq;
|
||||
|
||||
namespace HopFrame.Tests.Web.Components.Layout;
|
||||
|
||||
public class HopFrameNavigationTests : TestContext {
|
||||
[Fact]
|
||||
public void Renders_HopFrameNavigation_Components() {
|
||||
// Arrange
|
||||
var authHandlerMock = new Mock<IHopFrameAuthHandler>();
|
||||
var config = new HopFrameConfig {
|
||||
DisplayUserInfo = true
|
||||
};
|
||||
|
||||
authHandlerMock.Setup(h => h.GetCurrentUserDisplayNameAsync())
|
||||
.ReturnsAsync("John Doe");
|
||||
|
||||
Services.AddSingleton(authHandlerMock.Object);
|
||||
Services.AddHopFrame(config);
|
||||
|
||||
JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
// Act
|
||||
var cut = RenderComponent<HopFrameNavigation>();
|
||||
|
||||
// Assert
|
||||
var header = cut.FindComponent<FluentHeader>();
|
||||
Assert.NotNull(header);
|
||||
|
||||
var persona = cut.FindComponent<FluentPersona>();
|
||||
Assert.NotNull(persona);
|
||||
Assert.Equal("John Doe", persona.Instance.Name);
|
||||
Assert.Equal("JD", persona.Instance.Initials);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Renders_HopFrameNavigation_WithoutPersona() {
|
||||
// Arrange
|
||||
var authHandlerMock = new Mock<IHopFrameAuthHandler>();
|
||||
var config = new HopFrameConfig {
|
||||
DisplayUserInfo = false
|
||||
};
|
||||
|
||||
authHandlerMock.Setup(h => h.GetCurrentUserDisplayNameAsync())
|
||||
.ReturnsAsync("John Doe");
|
||||
|
||||
Services.AddSingleton(authHandlerMock.Object);
|
||||
Services.AddHopFrame(config);
|
||||
|
||||
JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
// Act
|
||||
var cut = RenderComponent<HopFrameNavigation>();
|
||||
|
||||
// Assert
|
||||
var header = cut.FindComponent<FluentHeader>();
|
||||
Assert.NotNull(header);
|
||||
Assert.False(cut.HasComponent<FluentPersona>());
|
||||
|
||||
authHandlerMock.Verify(h => h.GetCurrentUserDisplayNameAsync(), Times.Never);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using HopFrame.Core.Config;
|
||||
using HopFrame.Core.Services;
|
||||
using Moq;
|
||||
using Bunit;
|
||||
using HopFrame.Tests.Web.Models;
|
||||
using HopFrame.Web;
|
||||
using HopFrame.Web.Components.Layout;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.FluentUI.AspNetCore.Components;
|
||||
|
||||
namespace HopFrame.Tests.Web.Components.Layout;
|
||||
|
||||
public class HopFrameSideMenuTests : TestContext {
|
||||
|
||||
[Fact]
|
||||
public void Renders_FluentAppBar_Components() {
|
||||
// Arrange
|
||||
var contextExplorerMock = new Mock<IContextExplorer>();
|
||||
var authHandlerMock = new Mock<IHopFrameAuthHandler>();
|
||||
var contextConfig = new DbContextConfig(typeof(MyDbContext));
|
||||
var tableConfigs = new List<TableConfig> {
|
||||
new (contextConfig, typeof(MyTable), "Table1", 0),
|
||||
new (contextConfig, typeof(MyTable2), "Table2", 1)
|
||||
};
|
||||
var config = new HopFrameConfig {
|
||||
Contexts = { contextConfig }
|
||||
};
|
||||
|
||||
contextExplorerMock.Setup(e => e.GetTables()).Returns(tableConfigs);
|
||||
authHandlerMock.Setup(h => h.IsAuthenticatedAsync(null))
|
||||
.ReturnsAsync(true);
|
||||
|
||||
Services.AddSingleton(contextExplorerMock.Object);
|
||||
Services.AddSingleton(authHandlerMock.Object);
|
||||
Services.AddHopFrame(config);
|
||||
|
||||
JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
// Act
|
||||
var cut = RenderComponent<HopFrameSideMenu>();
|
||||
|
||||
// Assert
|
||||
var items = cut.FindComponents<FluentAppBarItem>();
|
||||
Assert.Equal(tableConfigs.Count + 1, items.Count);
|
||||
Assert.Contains(items, item => item.Instance.Text.Equals("Table1"));
|
||||
Assert.Contains(items, item => item.Instance.Text.Equals("Table2"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
using Bunit;
|
||||
using HopFrame.Core.Config;
|
||||
using HopFrame.Core.Services;
|
||||
using HopFrame.Tests.Web.Models;
|
||||
using HopFrame.Web;
|
||||
using HopFrame.Web.Components.Pages;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.FluentUI.AspNetCore.Components;
|
||||
using Moq;
|
||||
|
||||
namespace HopFrame.Tests.Web.Components.Pages;
|
||||
|
||||
public class HopFrameHomeTests : TestContext {
|
||||
[Fact]
|
||||
public void Renders_Table_Cards_Correctly() {
|
||||
// Arrange
|
||||
var contextExplorerMock = new Mock<IContextExplorer>();
|
||||
var authHandlerMock = new Mock<IHopFrameAuthHandler>();
|
||||
var contextConfig = new DbContextConfig(typeof(MyDbContext));
|
||||
var tableConfigs = new List<TableConfig> {
|
||||
new TableConfig(contextConfig, typeof(MyTable), "Table1", 0) {
|
||||
DisplayName = "Table1",
|
||||
ViewPolicy = "Policy1",
|
||||
Description = "Description1"
|
||||
},
|
||||
new TableConfig(contextConfig, typeof(MyTable2), "Table2", 1) {
|
||||
DisplayName = "Table2",
|
||||
ViewPolicy = "Policy2",
|
||||
Description = "Description2"
|
||||
}
|
||||
};
|
||||
contextConfig.Tables.AddRange(tableConfigs);
|
||||
var config = new HopFrameConfig() {
|
||||
Contexts = { contextConfig }
|
||||
};
|
||||
|
||||
contextExplorerMock.Setup(e => e.GetTables()).Returns(tableConfigs);
|
||||
authHandlerMock.Setup(h => h.IsAuthenticatedAsync(It.IsAny<string>()))
|
||||
.ReturnsAsync(true);
|
||||
|
||||
Services.AddHopFrame(config);
|
||||
Services.AddSingleton(contextExplorerMock.Object);
|
||||
Services.AddSingleton(authHandlerMock.Object);
|
||||
|
||||
// Act
|
||||
var cut = RenderComponent<HopFrameHome>();
|
||||
|
||||
// Assert
|
||||
var cards = cut.FindComponents<FluentCard>();
|
||||
Assert.Equal(2, cards.Count);
|
||||
|
||||
Assert.Contains(cards, card => card.Markup.Contains("Table1"));
|
||||
Assert.Contains(cards, card => card.Markup.Contains("Description1"));
|
||||
Assert.Contains(cards, card => card.Markup.Contains("Policy1"));
|
||||
Assert.Contains(cards, card => card.Markup.Contains("Open"));
|
||||
|
||||
Assert.Contains(cards, card => card.Markup.Contains("Table2"));
|
||||
Assert.Contains(cards, card => card.Markup.Contains("Description2"));
|
||||
Assert.Contains(cards, card => card.Markup.Contains("Policy2"));
|
||||
Assert.Contains(cards, card => card.Markup.Contains("Open"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
using Bunit;
|
||||
using HopFrame.Core.Config;
|
||||
using HopFrame.Core.Services;
|
||||
using HopFrame.Tests.Web.Helpers;
|
||||
using HopFrame.Tests.Web.Models;
|
||||
using HopFrame.Web;
|
||||
using HopFrame.Web.Components.Pages;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.FluentUI.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
using Moq;
|
||||
|
||||
namespace HopFrame.Tests.Web.Components.Pages;
|
||||
|
||||
public class HopFrameTablePageTests : TestContext {
|
||||
[Fact]
|
||||
public void Renders_Table_Correctly() {
|
||||
// Arrange
|
||||
var contextExplorerMock = new Mock<IContextExplorer>();
|
||||
var authHandlerMock = new Mock<IHopFrameAuthHandler>();
|
||||
var dialogServiceMock = new Mock<IDialogService>();
|
||||
var contextConfig = new DbContextConfig(typeof(MyDbContext));
|
||||
var managerMock = new Mock<ITableManager>();
|
||||
var tableConfig = new TableConfig(contextConfig, typeof(MyTable), "Table1", 0) {
|
||||
DisplayName = "Table1",
|
||||
ViewPolicy = "Policy1"
|
||||
};
|
||||
contextConfig.Tables.Add(tableConfig);
|
||||
var config = new HopFrameConfig() {
|
||||
Contexts = { contextConfig }
|
||||
};
|
||||
|
||||
contextExplorerMock.Setup(e => e.GetTable("Table1")).Returns(tableConfig);
|
||||
contextExplorerMock.Setup(e => e.GetTableManager("Table1")).Returns(managerMock.Object);
|
||||
authHandlerMock.Setup(h => h.IsAuthenticatedAsync(It.IsAny<string>())).ReturnsAsync(true);
|
||||
managerMock.Setup(m => m.LoadPage(It.IsAny<int>(), It.IsAny<int>())).Returns(Enumerable.Empty<object>().AsAsyncQueryable());
|
||||
|
||||
Services.AddHopFrame(config);
|
||||
Services.AddSingleton(contextExplorerMock.Object);
|
||||
Services.AddSingleton(authHandlerMock.Object);
|
||||
Services.AddSingleton(dialogServiceMock.Object);
|
||||
|
||||
JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
// Act
|
||||
var cut = RenderComponent<HopFrameTablePage>(parameters => parameters
|
||||
.Add(p => p.TableDisplayName, "Table1"));
|
||||
|
||||
// Assert
|
||||
var toolbar = cut.Find("fluent-toolbar");
|
||||
Assert.NotNull(toolbar);
|
||||
|
||||
var searchBox = cut.Find("fluent-search");
|
||||
Assert.NotNull(searchBox);
|
||||
|
||||
var dataGrid = cut.FindComponent<FluentDataGrid<object>>();
|
||||
Assert.NotNull(dataGrid);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Displays_Properties_Correctly() {
|
||||
// Arrange
|
||||
var contextExplorerMock = new Mock<IContextExplorer>();
|
||||
var authHandlerMock = new Mock<IHopFrameAuthHandler>();
|
||||
var dialogServiceMock = new Mock<IDialogService>();
|
||||
var contextConfig = new DbContextConfig(typeof(MyDbContext));
|
||||
var tableConfig = new TableConfig(contextConfig, typeof(MyTable), "Table1", 0) {
|
||||
DisplayName = "Table1",
|
||||
ViewPolicy = "Policy1"
|
||||
};
|
||||
|
||||
var tableManagerMock = new Mock<ITableManager>();
|
||||
var items = new List<object> { new MyTable(), new MyTable() };
|
||||
tableManagerMock.Setup(m => m.LoadPage(It.IsAny<int>(), It.IsAny<int>())).Returns(items.AsAsyncQueryable());
|
||||
|
||||
contextExplorerMock.Setup(e => e.GetTable("Table1")).Returns(tableConfig);
|
||||
contextExplorerMock.Setup(e => e.GetTableManager("Table1")).Returns(tableManagerMock.Object);
|
||||
authHandlerMock.Setup(h => h.IsAuthenticatedAsync(It.IsAny<string>())).ReturnsAsync(true);
|
||||
|
||||
Services.AddHopFrame(new HopFrameConfig());
|
||||
Services.AddSingleton(contextExplorerMock.Object);
|
||||
Services.AddSingleton(authHandlerMock.Object);
|
||||
Services.AddSingleton(dialogServiceMock.Object);
|
||||
|
||||
JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
// Act
|
||||
var cut = RenderComponent<HopFrameTablePage>(parameters => parameters
|
||||
.Add(p => p.TableDisplayName, "Table1"));
|
||||
|
||||
// Assert
|
||||
var dataGridItems = cut.FindComponents<PropertyColumn<object, string>>();
|
||||
Assert.Single(dataGridItems);
|
||||
Assert.Equal(nameof(MyTable.Id), dataGridItems[0].Instance.Title);
|
||||
}
|
||||
}
|
||||
39
tests/HopFrame.Tests.Web/Helpers/EnumerableExtensions.cs
Normal file
39
tests/HopFrame.Tests.Web/Helpers/EnumerableExtensions.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.Collections;
|
||||
using System.Linq.Expressions;
|
||||
using Microsoft.EntityFrameworkCore.Query.Internal;
|
||||
|
||||
namespace HopFrame.Tests.Web.Helpers;
|
||||
|
||||
public static class EnumerableExtensions {
|
||||
|
||||
public static AsyncQueryable AsAsyncQueryable(this IEnumerable<object> enumerable) {
|
||||
return new AsyncQueryable(enumerable);
|
||||
}
|
||||
|
||||
public class AsyncQueryable(IEnumerable<object> enumerable) : IQueryable<object>, IAsyncEnumerable<object> {
|
||||
public IEnumerator<object> GetEnumerator() {
|
||||
return enumerable.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() {
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public Type ElementType { get; } = typeof(object);
|
||||
|
||||
public Expression Expression { get; }
|
||||
|
||||
public IQueryProvider Provider { get; }
|
||||
|
||||
public IAsyncEnumerator<object> GetAsyncEnumerator(CancellationToken cancellationToken = new CancellationToken()) {
|
||||
return Enumerate().GetAsyncEnumerator(cancellationToken);
|
||||
}
|
||||
|
||||
private async IAsyncEnumerable<object> Enumerate() {
|
||||
foreach (var o in enumerable) {
|
||||
yield return o;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
29
tests/HopFrame.Tests.Web/HopFrame.Tests.Web.csproj
Normal file
29
tests/HopFrame.Tests.Web/HopFrame.Tests.Web.csproj
Normal file
@@ -0,0 +1,29 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="bunit" Version="1.38.5" />
|
||||
<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" />
|
||||
<ProjectReference Include="..\..\src\HopFrame.Web\HopFrame.Web.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
12
tests/HopFrame.Tests.Web/Models/MyDbContext.cs
Normal file
12
tests/HopFrame.Tests.Web/Models/MyDbContext.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace HopFrame.Tests.Web.Models;
|
||||
|
||||
public class MyDbContext : DbContext {
|
||||
public DbSet<MyTable> Table1 { get; set; }
|
||||
public DbSet<MyTable2> Table2 { get; set; }
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
|
||||
optionsBuilder.UseInMemoryDatabase(nameof(MyDbContext));
|
||||
}
|
||||
}
|
||||
14
tests/HopFrame.Tests.Web/Models/MyTable.cs
Normal file
14
tests/HopFrame.Tests.Web/Models/MyTable.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace HopFrame.Tests.Web.Models;
|
||||
|
||||
public class MyTable {
|
||||
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public int Id { get; set; }
|
||||
}
|
||||
|
||||
public class MyTable2 {
|
||||
[Key]
|
||||
public string Id { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user