Merge pull request #9227 from umbraco/netcore/feature/migrate-unit-tests

Netcore: Migrate rendering related unit tests
This commit is contained in:
Bjarke Berg
2020-10-21 10:51:12 +02:00
committed by GitHub
8 changed files with 590 additions and 654 deletions

View File

@@ -45,17 +45,18 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.ModelBinders
}
[Test]
public void Does_Not_Bind_Model_When_Source_Type_Matches_Model_Type()
public void BindModel_Returns_If_Same_Type()
{
// Arrange
var bindingContext = CreateBindingContext(typeof(ContentModel), source: new ContentModel(CreatePublishedContent()));
var content = new ContentModel(CreatePublishedContent());
var bindingContext = CreateBindingContext(typeof(ContentModel), source: content);
var binder = new ContentModelBinder();
// Act
binder.BindModelAsync(bindingContext);
// Assert
Assert.False(bindingContext.Result.IsModelSet);
Assert.AreSame(content, bindingContext.Result.Model);
}
[Test]

View File

@@ -0,0 +1,175 @@
using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Routing;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Common.ModelBinders;
using Umbraco.Web.Models;
namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.ModelBinders
{
[TestFixture]
public class RenderModelBinderTests
{
private ContentModelBinder _contentModelBinder;
[SetUp]
public void SetUp()
{
_contentModelBinder = new ContentModelBinder();
}
[Test]
[TestCase(typeof(IPublishedContent), false)]
[TestCase(typeof(ContentModel), false)]
[TestCase(typeof(MyContent), false)]
[TestCase(typeof(ContentModel<MyContent>), false)]
[TestCase(typeof(MyOtherContent), true)]
[TestCase(typeof(MyCustomContentModel), true)]
[TestCase(typeof(IContentModel), true)]
public void Returns_Binder_For_IPublishedContent_And_IRenderModel(Type testType, bool expectNull)
{
var binderProvider = new ContentModelBinderProvider();
var contextMock = new Mock<ModelBinderProviderContext>();
contextMock.Setup(x => x.Metadata).Returns(new EmptyModelMetadataProvider().GetMetadataForType(testType));
var found = binderProvider.GetBinder(contextMock.Object);
if (expectNull)
{
Assert.IsNull(found);
}
else
{
Assert.IsNotNull(found);
}
}
[Test]
public void BindModel_Null_Source_Returns_Null()
{
var bindingContext = new DefaultModelBindingContext();
_contentModelBinder.BindModelAsync(bindingContext, null, typeof(MyContent));
Assert.IsNull(bindingContext.Result.Model);
}
[Test]
public void BindModel_Returns_If_Same_Type()
{
var content = new MyContent(Mock.Of<IPublishedContent>());
var bindingContext = new DefaultModelBindingContext();
_contentModelBinder.BindModelAsync(bindingContext, content, typeof(MyContent));
Assert.AreSame(content, bindingContext.Result.Model);
}
[Test]
public void BindModel_RenderModel_To_IPublishedContent()
{
var content = new MyContent(Mock.Of<IPublishedContent>());
var renderModel = new ContentModel(content);
var bindingContext = new DefaultModelBindingContext();
_contentModelBinder.BindModelAsync(bindingContext, renderModel, typeof(IPublishedContent));
Assert.AreSame(content, bindingContext.Result.Model);
}
[Test]
public void BindModel_IPublishedContent_To_RenderModel()
{
var content = new MyContent(Mock.Of<IPublishedContent>());
var bindingContext = new DefaultModelBindingContext();
_contentModelBinder.BindModelAsync(bindingContext, content, typeof(ContentModel));
var bound = (IContentModel) bindingContext.Result.Model;
Assert.AreSame(content, bound.Content);
}
[Test]
public void BindModel_IPublishedContent_To_Generic_RenderModel()
{
var content = new MyContent(Mock.Of<IPublishedContent>());
var bindingContext = new DefaultModelBindingContext();
_contentModelBinder.BindModelAsync(bindingContext, content, typeof(ContentModel<MyContent>));
var bound = (IContentModel) bindingContext.Result.Model;
Assert.AreSame(content, bound.Content);
}
[Test]
public void No_DataToken_Returns_Null()
{
var content = new MyContent(Mock.Of<IPublishedContent>());
var bindingContext = CreateBindingContext(typeof(ContentModel), false, content);
_contentModelBinder.BindModelAsync(bindingContext);
Assert.IsNull(bindingContext.Result.Model);
}
[Test]
public void Invalid_DataToken_Model_Type_Returns_Null()
{
var bindingContext = CreateBindingContext(typeof(IPublishedContent), source: "Hello");
_contentModelBinder.BindModelAsync(bindingContext);
Assert.IsNull(bindingContext.Result.Model);
}
[Test]
public void IPublishedContent_DataToken_Model_Type_Uses_DefaultImplementation()
{
var content = new MyContent(Mock.Of<IPublishedContent>());
var bindingContext = CreateBindingContext(typeof(MyContent), source: content);
_contentModelBinder.BindModelAsync(bindingContext);
Assert.AreEqual(content, bindingContext.Result.Model);
}
private ModelBindingContext CreateBindingContext(Type modelType, bool withUmbracoDataToken = true, object source = null)
{
var httpContext = new DefaultHttpContext();
var routeData = new RouteData();
if (withUmbracoDataToken)
routeData.DataTokens.Add(Constants.Web.UmbracoDataToken, source);
var actionContext = new ActionContext(httpContext, routeData, new ActionDescriptor());
var metadataProvider = new EmptyModelMetadataProvider();
var routeValueDictionary = new RouteValueDictionary();
var valueProvider = new RouteValueProvider(BindingSource.Path, routeValueDictionary);
return new DefaultModelBindingContext
{
ActionContext = actionContext,
ModelMetadata = metadataProvider.GetMetadataForType(modelType),
ModelName = modelType.Name,
ValueProvider = valueProvider,
};
}
public class MyCustomContentModel : ContentModel
{
public MyCustomContentModel(IPublishedContent content)
: base(content)
{ }
}
public class MyOtherContent
{
}
public class MyContent : PublishedContentWrapped
{
public MyContent(IPublishedContent content) : base(content)
{
}
}
}
}

View File

@@ -0,0 +1,350 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using NUnit.Framework;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Common.AspNetCore;
using Umbraco.Web.Common.ModelBinders;
using Umbraco.Web.Models;
namespace Umbraco.Tests.UnitTests.Umbraco.Web.Common.Views
{
[TestFixture]
public class UmbracoViewPageTests
{
#region RenderModel To ...
[Test]
public void RenderModel_To_RenderModel()
{
var content = new ContentType1(null);
var model = new ContentModel(content);
var view = new RenderModelTestPage();
var viewData = GetViewDataDictionary<ContentModel>(model);
view.ViewData = viewData;
Assert.AreSame(model, view.Model);
}
[Test]
public void RenderModel_ContentType1_To_ContentType1()
{
var content = new ContentType1(null);
var view = new ContentType1TestPage();
var viewData = GetViewDataDictionary<ContentType1>(content);
view.ViewData = viewData;
Assert.IsInstanceOf<ContentType1>(view.Model);
}
[Test]
public void RenderModel_ContentType2_To_ContentType1()
{
var content = new ContentType2(null);
var view = new ContentType1TestPage();
var viewData = GetViewDataDictionary<ContentType1>(content);
view.ViewData = viewData;
Assert.IsInstanceOf<ContentType1>(view.Model);
}
[Test]
public void RenderModel_ContentType1_To_ContentType2()
{
var content = new ContentType1(null);
var model = new ContentModel(content);
var view = new ContentType2TestPage();
var viewData = GetViewDataDictionary(model);
Assert.ThrowsAsync<ModelBindingException>(async () => await view.SetViewDataAsyncX(viewData));
}
[Test]
public void RenderModel_ContentType1_To_RenderModelOf_ContentType1()
{
var content = new ContentType1(null);
var model = new ContentModel<ContentType1>(content);
var view = new RenderModelOfContentType1TestPage();
var viewData = GetViewDataDictionary<ContentModel<ContentType1>>(model);
view.ViewData = viewData;
Assert.IsInstanceOf<ContentModel<ContentType1>>(view.Model);
Assert.IsInstanceOf<ContentType1>(view.Model.Content);
}
[Test]
public void RenderModel_ContentType2_To_RenderModelOf_ContentType1()
{
var content = new ContentType2(null);
var model = new ContentModel<ContentType1>(content);
var view = new RenderModelOfContentType1TestPage();
var viewData = GetViewDataDictionary<ContentModel<ContentType1>>(model);
view.ViewData = viewData;
Assert.IsInstanceOf<ContentModel<ContentType1>>(view.Model);
Assert.IsInstanceOf<ContentType2>(view.Model.Content);
}
[Test]
public void RenderModel_ContentType1_To_RenderModelOf_ContentType2()
{
var content = new ContentType1(null);
var model = new ContentModel(content);
var view = new RenderModelOfContentType2TestPage();
var viewData = GetViewDataDictionary(model);
Assert.ThrowsAsync<ModelBindingException>(async () => await view.SetViewDataAsyncX(viewData));
}
#endregion
#region RenderModelOf To ...
[Test]
public void RenderModelOf_ContentType1_To_RenderModel()
{
var content = new ContentType1(null);
var model = new ContentModel<ContentType1>(content);
var view = new RenderModelTestPage();
var viewData = GetViewDataDictionary<ContentModel>(model);
view.ViewData = viewData;
Assert.AreSame(model, view.Model);
}
[Test]
public async Task RenderModelOf_ContentType1_To_ContentType1()
{
var content = new ContentType1(null);
var model = new ContentModel<ContentType1>(content);
var view = new ContentType1TestPage();
var viewData = GetViewDataDictionary<ContentModel<ContentType1>>(model);
await view.SetViewDataAsyncX(viewData);
Assert.IsInstanceOf<ContentType1>(view.Model);
}
[Test]
public async Task RenderModelOf_ContentType2_To_ContentType1()
{
var content = new ContentType2(null);
var model = new ContentModel<ContentType2>(content);
var view = new ContentType1TestPage();
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
{
Model = model
};
await view.SetViewDataAsyncX(viewData);
Assert.IsInstanceOf<ContentType1>(view.Model);
}
[Test]
public async Task RenderModelOf_ContentType1_To_ContentType2()
{
var content = new ContentType1(null);
var model = new ContentModel<ContentType1>(content);
var view = new ContentType2TestPage();
var viewData = GetViewDataDictionary(model);
Assert.ThrowsAsync<ModelBindingException>(async () => await view.SetViewDataAsyncX(viewData));
}
[Test]
public void RenderModelOf_ContentType1_To_RenderModelOf_ContentType1()
{
var content = new ContentType1(null);
var model = new ContentModel<ContentType1>(content);
var view = new RenderModelOfContentType1TestPage();
var viewData = GetViewDataDictionary<ContentModel<ContentType1>>(model);
view.ViewData = viewData;
Assert.IsInstanceOf<ContentModel<ContentType1>>(view.Model);
Assert.IsInstanceOf<ContentType1>(view.Model.Content);
}
[Test]
public async Task RenderModelOf_ContentType2_To_RenderModelOf_ContentType1()
{
var content = new ContentType2(null);
var model = new ContentModel<ContentType1>(content);
var view = new RenderModelOfContentType1TestPage();
var viewData = GetViewDataDictionary<ContentModel<ContentType1>>(model);
await view.SetViewDataAsyncX(viewData);
Assert.IsInstanceOf<ContentModel<ContentType1>>(view.Model);
Assert.IsInstanceOf<ContentType2>(view.Model.Content);
}
[Test]
public void RenderModelOf_ContentType1_To_RenderModelOf_ContentType2()
{
var content = new ContentType1(null);
var model = new ContentModel<ContentType1>(content);
var view = new RenderModelOfContentType2TestPage();
var viewData = GetViewDataDictionary(model);
Assert.ThrowsAsync<ModelBindingException>(async () => await view.SetViewDataAsyncX(viewData));
}
#endregion
#region ContentType To ...
[Test]
public async Task ContentType1_To_RenderModel()
{
var content = new ContentType1(null);
var view = new RenderModelTestPage();
var viewData = GetViewDataDictionary<ContentType1>(content);
await view.SetViewDataAsyncX(viewData);
Assert.IsInstanceOf<ContentModel>(view.Model);
}
[Test]
public async Task ContentType1_To_RenderModelOf_ContentType1()
{
var content = new ContentType1(null);
var view = new RenderModelOfContentType1TestPage();
var viewData = GetViewDataDictionary<ContentType1>(content);
await view.SetViewDataAsyncX(viewData);
Assert.IsInstanceOf<ContentModel<ContentType1>>(view.Model);
Assert.IsInstanceOf<ContentType1>(view.Model.Content);
}
[Test]
public async Task ContentType2_To_RenderModelOf_ContentType1()
{
// Same as above but with ContentModel<ContentType2>
var content = new ContentType2(null);
var view = new RenderModelOfContentType1TestPage();
var viewData = GetViewDataDictionary<ContentType2>(content);
await view.SetViewDataAsyncX(viewData);
Assert.IsInstanceOf<ContentModel<ContentType1>>(view.Model);
Assert.IsInstanceOf<ContentType1>(view.Model.Content);
}
[Test]
public void ContentType1_To_RenderModelOf_ContentType2()
{
var content = new ContentType1(null);
var view = new RenderModelOfContentType2TestPage();
var viewData = GetViewDataDictionary(content);
Assert.ThrowsAsync<ModelBindingException>(async () => await view.SetViewDataAsyncX(viewData));
}
[Test]
public async Task ContentType1_To_ContentType1()
{
var content = new ContentType1(null);
var view = new ContentType1TestPage();
var viewData = GetViewDataDictionary<ContentType1>(content);
await view.SetViewDataAsyncX(viewData);
Assert.IsInstanceOf<ContentType1>(view.Model);
}
[Test]
public void ContentType1_To_ContentType2()
{
var content = new ContentType1(null);
var view = new ContentType2TestPage();
var viewData = GetViewDataDictionary(content);
Assert.ThrowsAsync<ModelBindingException>(async () => await view.SetViewDataAsyncX(viewData));
}
[Test]
public async Task ContentType2_To_ContentType1()
{
var content = new ContentType2(null);
var view = new ContentType1TestPage();
var viewData = GetViewDataDictionary(content);
await view.SetViewDataAsyncX(viewData);
Assert.IsInstanceOf<ContentType1>(view.Model);
}
#endregion
#region Test helpers methods
private ViewDataDictionary<T> GetViewDataDictionary<T>(object model)
{
var sourceViewDataDictionary = new ViewDataDictionary<T>(new EmptyModelMetadataProvider(), new ModelStateDictionary());
return new ViewDataDictionary<T>(sourceViewDataDictionary, model);
}
private ViewDataDictionary GetViewDataDictionary(object model)
{
var sourceViewDataDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary());
return new ViewDataDictionary(sourceViewDataDictionary)
{
Model = model
};
}
#endregion
#region Test elements
public class ContentType1 : PublishedContentWrapped
{
public ContentType1(IPublishedContent content) : base(content) {}
}
public class ContentType2 : ContentType1
{
public ContentType2(IPublishedContent content) : base(content) { }
}
public class TestPage<TModel> : UmbracoViewPage<TModel>
{
public override Task ExecuteAsync()
{
throw new NotImplementedException();
}
public async Task SetViewDataAsyncX(ViewDataDictionary viewData)
{
await SetViewDataAsync(viewData);
}
}
public class RenderModelTestPage : TestPage<ContentModel>
{ }
public class ContentType1TestPage : TestPage<ContentType1>
{ }
public class ContentType2TestPage : TestPage<ContentType2>
{ }
public class RenderModelOfContentType1TestPage : TestPage<ContentModel<ContentType1>>
{ }
public class RenderModelOfContentType2TestPage : TestPage<ContentModel<ContentType2>>
{ }
#endregion
}
}

View File

@@ -236,9 +236,7 @@
<Compile Include="Models\Collections\Item.cs" />
<Compile Include="Models\Collections\OrderItem.cs" />
<Compile Include="Models\Collections\SimpleOrder.cs" />
<Compile Include="Web\Mvc\RenderModelBinderTests.cs" />
<Compile Include="Web\Mvc\SurfaceControllerTests.cs" />
<Compile Include="Web\Mvc\UmbracoViewPageTests.cs" />
<Compile Include="Runtimes\CoreRuntimeTests.cs" />
<Compile Include="Runtimes\WebRuntimeComponentTests.cs" />
<Compile Include="Cache\ObjectAppCacheTests.cs" />

View File

@@ -1,181 +0,0 @@
using System.Collections.Generic;
using System.Globalization;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Moq;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Tests.Common;
using Umbraco.Tests.TestHelpers.Stubs;
using Umbraco.Web.Models;
using Umbraco.Web.Mvc;
using Current = Umbraco.Web.Composing.Current;
namespace Umbraco.Tests.Web.Mvc
{
[TestFixture]
public class RenderModelBinderTests
{
[SetUp]
public void SetUp()
{
Current.UmbracoContextAccessor = new TestUmbracoContextAccessor();
}
[TearDown]
public void TearDown()
{
Current.Reset();
}
[Test]
public void Returns_Binder_For_IPublishedContent_And_IRenderModel()
{
var binder = ContentModelBinder.Instance;
var found = binder.GetBinder(typeof (IPublishedContent));
Assert.IsNotNull(found);
found = binder.GetBinder(typeof(ContentModel));
Assert.IsNotNull(found);
found = binder.GetBinder(typeof(MyContent));
Assert.IsNotNull(found);
found = binder.GetBinder(typeof(ContentModel<MyContent>));
Assert.IsNotNull(found);
found = binder.GetBinder(typeof(MyOtherContent));
Assert.IsNull(found);
found = binder.GetBinder(typeof(MyCustomContentModel));
Assert.IsNull(found);
found = binder.GetBinder(typeof(IContentModel));
Assert.IsNull(found);
}
[Test]
public void BindModel_Null_Source_Returns_Null()
{
Assert.IsNull(ContentModelBinder.BindModel(null, typeof(MyContent)));
}
[Test]
public void BindModel_Returns_If_Same_Type()
{
var content = new MyContent(Mock.Of<IPublishedContent>());
var bound = ContentModelBinder.BindModel(content, typeof (IPublishedContent));
Assert.AreSame(content, bound);
}
[Test]
public void BindModel_RenderModel_To_IPublishedContent()
{
var content = new MyContent(Mock.Of<IPublishedContent>());
var renderModel = new ContentModel(content);
var bound = ContentModelBinder.BindModel(renderModel, typeof(IPublishedContent));
Assert.AreSame(content, bound);
}
[Test]
public void BindModel_IPublishedContent_To_RenderModel()
{
var content = new MyContent(Mock.Of<IPublishedContent>());
var bound = (IContentModel)ContentModelBinder.BindModel(content, typeof(ContentModel));
Assert.AreSame(content, bound.Content);
}
[Test]
public void BindModel_IPublishedContent_To_Generic_RenderModel()
{
var content = new MyContent(Mock.Of<IPublishedContent>());
var bound = (IContentModel)ContentModelBinder.BindModel(content, typeof(ContentModel<MyContent>));
Assert.AreSame(content, bound.Content);
}
[Test]
public void No_DataToken_Returns_Null()
{
var binder = ContentModelBinder.Instance;
var routeData = new RouteData();
var result = binder.BindModel(new ControllerContext(Mock.Of<HttpContextBase>(), routeData, Mock.Of<ControllerBase>()),
new ModelBindingContext());
Assert.IsNull(result);
}
[Test]
public void Invalid_DataToken_Model_Type_Returns_Null()
{
var binder = ContentModelBinder.Instance;
var routeData = new RouteData();
routeData.DataTokens[Core.Constants.Web.UmbracoDataToken] = "hello";
//the value provider is the default implementation
var valueProvider = new Mock<IValueProvider>();
//also IUnvalidatedValueProvider
var invalidatedValueProvider = valueProvider.As<IUnvalidatedValueProvider>();
invalidatedValueProvider.Setup(x => x.GetValue(It.IsAny<string>(), It.IsAny<bool>())).Returns(() =>
new ValueProviderResult(null, "", CultureInfo.CurrentCulture));
var controllerCtx = new ControllerContext(
Mock.Of<HttpContextBase>(http => http.Items == new Dictionary<object, object>()),
routeData,
Mock.Of<ControllerBase>());
var result = binder.BindModel(controllerCtx,
new ModelBindingContext
{
ValueProvider = valueProvider.Object,
ModelMetadata = new ModelMetadata(new EmptyModelMetadataProvider(), null, () => null, typeof(IPublishedContent), "content")
});
Assert.IsNull(result);
}
[Test]
public void IPublishedContent_DataToken_Model_Type_Uses_DefaultImplementation()
{
var content = new MyContent(Mock.Of<IPublishedContent>());
var binder = ContentModelBinder.Instance;
var routeData = new RouteData();
routeData.DataTokens[Core.Constants.Web.UmbracoDataToken] = content;
//the value provider is the default implementation
var valueProvider = new Mock<IValueProvider>();
//also IUnvalidatedValueProvider
var invalidatedValueProvider = valueProvider.As<IUnvalidatedValueProvider>();
invalidatedValueProvider.Setup(x => x.GetValue(It.IsAny<string>(), It.IsAny<bool>())).Returns(() =>
new ValueProviderResult(content, "content", CultureInfo.CurrentCulture));
var controllerCtx = new ControllerContext(
Mock.Of<HttpContextBase>(http => http.Items == new Dictionary<object, object>()),
routeData,
Mock.Of<ControllerBase>());
var result = binder.BindModel(controllerCtx,
new ModelBindingContext
{
ValueProvider = valueProvider.Object,
ModelMetadata = new ModelMetadata(new EmptyModelMetadataProvider(), null, () => null, typeof(IPublishedContent), "content")
});
Assert.AreEqual(content, result);
}
public class MyCustomContentModel : ContentModel
{
public MyCustomContentModel(IPublishedContent content)
: base(content)
{ }
}
public class MyOtherContent
{
}
public class MyContent : PublishedContentWrapped
{
public MyContent(IPublishedContent content) : base(content)
{
}
}
}
}

View File

@@ -1,466 +0,0 @@
using System;
using System.Globalization;
using System.Web.Mvc;
using System.Web.Routing;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Services;
using Umbraco.Tests.Common;
using Umbraco.Tests.LegacyXmlPublishedCache;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.Testing;
using Umbraco.Web;
using Umbraco.Web.Composing;
using Umbraco.Web.Models;
using Umbraco.Web.Mvc;
using Umbraco.Web.Routing;
using Umbraco.Web.Security;
namespace Umbraco.Tests.Web.Mvc
{
[TestFixture]
[UmbracoTest(WithApplication = true)]
public class UmbracoViewPageTests : UmbracoTestBase
{
private XmlPublishedSnapshotService _service;
[TearDown]
public override void TearDown()
{
if (_service == null) return;
_service.Dispose();
_service = null;
}
#region RenderModel To ...
[Test]
public void RenderModel_To_RenderModel()
{
var content = new ContentType1(null);
var model = new ContentModel(content);
var view = new RenderModelTestPage();
var viewData = new ViewDataDictionary(model);
view.ViewContext = GetViewContext();
view.SetViewDataX(viewData);
Assert.AreSame(model, view.Model);
}
[Test]
public void RenderModel_ContentType1_To_ContentType1()
{
var content = new ContentType1(null);
var model = new ContentModel(content);
var view = new ContentType1TestPage();
var viewData = new ViewDataDictionary(model);
view.ViewContext = GetViewContext();
view.SetViewDataX(viewData);
Assert.IsInstanceOf<ContentType1>(view.Model);
}
[Test]
public void RenderModel_ContentType2_To_ContentType1()
{
var content = new ContentType2(null);
var model = new ContentModel(content);
var view = new ContentType1TestPage();
var viewData = new ViewDataDictionary(model);
view.ViewContext = GetViewContext();
view.SetViewDataX(viewData);
Assert.IsInstanceOf<ContentType1>(view.Model);
}
[Test]
public void RenderModel_ContentType1_To_ContentType2()
{
var content = new ContentType1(null);
var model = new ContentModel(content);
var view = new ContentType2TestPage();
var viewData = new ViewDataDictionary(model);
view.ViewContext = GetViewContext();
Assert.Throws<ModelBindingException>(() => view.SetViewDataX(viewData));
}
[Test]
public void RenderModel_ContentType1_To_RenderModelOf_ContentType1()
{
var content = new ContentType1(null);
var model = new ContentModel(content);
var view = new RenderModelOfContentType1TestPage();
var viewData = new ViewDataDictionary(model);
view.ViewContext = GetViewContext();
view.SetViewDataX(viewData);
Assert.IsInstanceOf<ContentModel<ContentType1>>(view.Model);
Assert.IsInstanceOf<ContentType1>(view.Model.Content);
}
[Test]
public void RenderModel_ContentType2_To_RenderModelOf_ContentType1()
{
var content = new ContentType2(null);
var model = new ContentModel(content);
var view = new RenderModelOfContentType1TestPage();
var viewData = new ViewDataDictionary(model);
view.ViewContext = GetViewContext();
view.SetViewDataX(viewData);
Assert.IsInstanceOf<ContentModel<ContentType1>>(view.Model);
Assert.IsInstanceOf<ContentType2>(view.Model.Content);
}
[Test]
public void RenderModel_ContentType1_To_RenderModelOf_ContentType2()
{
var content = new ContentType1(null);
var model = new ContentModel(content);
var view = new RenderModelOfContentType2TestPage();
var viewData = new ViewDataDictionary(model);
view.ViewContext = GetViewContext();
Assert.Throws<ModelBindingException>(() => view.SetViewDataX(viewData));
}
#endregion
#region RenderModelOf To ...
[Test]
public void RenderModelOf_ContentType1_To_RenderModel()
{
var content = new ContentType1(null);
var model = new ContentModel<ContentType1>(content);
var view = new RenderModelTestPage();
var viewData = new ViewDataDictionary(model);
view.ViewContext = GetViewContext();
view.SetViewDataX(viewData);
Assert.AreSame(model, view.Model);
}
[Test]
public void RenderModelOf_ContentType1_To_ContentType1()
{
var content = new ContentType1(null);
var model = new ContentModel<ContentType1>(content);
var view = new ContentType1TestPage();
var viewData = new ViewDataDictionary(model);
view.ViewContext = GetViewContext();
view.SetViewDataX(viewData);
Assert.IsInstanceOf<ContentType1>(view.Model);
}
[Test]
public void RenderModelOf_ContentType2_To_ContentType1()
{
var content = new ContentType2(null);
var model = new ContentModel<ContentType2>(content);
var view = new ContentType1TestPage();
var viewData = new ViewDataDictionary(model);
view.ViewContext = GetViewContext();
view.SetViewDataX(viewData);
Assert.IsInstanceOf<ContentType1>(view.Model);
}
[Test]
public void RenderModelOf_ContentType1_To_ContentType2()
{
var content = new ContentType1(null);
var model = new ContentModel<ContentType1>(content);
var view = new ContentType2TestPage();
var viewData = new ViewDataDictionary(model);
view.ViewContext = GetViewContext();
Assert.Throws<ModelBindingException>(() => view.SetViewDataX(viewData));
}
[Test]
public void RenderModelOf_ContentType1_To_RenderModelOf_ContentType1()
{
var content = new ContentType1(null);
var model = new ContentModel<ContentType1>(content);
var view = new RenderModelOfContentType1TestPage();
var viewData = new ViewDataDictionary(model);
view.ViewContext = GetViewContext();
view.SetViewDataX(viewData);
Assert.IsInstanceOf<ContentModel<ContentType1>>(view.Model);
Assert.IsInstanceOf<ContentType1>(view.Model.Content);
}
[Test]
public void RenderModelOf_ContentType2_To_RenderModelOf_ContentType1()
{
var content = new ContentType2(null);
var model = new ContentModel<ContentType2>(content);
var view = new RenderModelOfContentType1TestPage();
var viewData = new ViewDataDictionary(model);
view.ViewContext = GetViewContext();
view.SetViewDataX(viewData);
Assert.IsInstanceOf<ContentModel<ContentType1>>(view.Model);
Assert.IsInstanceOf<ContentType2>(view.Model.Content);
}
[Test]
public void RenderModelOf_ContentType1_To_RenderModelOf_ContentType2()
{
var content = new ContentType1(null);
var model = new ContentModel<ContentType1>(content);
var view = new RenderModelOfContentType2TestPage();
var viewData = new ViewDataDictionary(model);
view.ViewContext = GetViewContext();
Assert.Throws<ModelBindingException>(() => view.SetViewDataX(viewData));
}
#endregion
#region ContentType To ...
[Test]
public void ContentType1_To_RenderModel()
{
var content = new ContentType1(null);
var view = new RenderModelTestPage();
var viewData = new ViewDataDictionary(content);
view.ViewContext = GetViewContext();
view.SetViewDataX(viewData);
Assert.IsInstanceOf<ContentModel>(view.Model);
}
[Test]
public void ContentType1_To_RenderModelOf_ContentType1()
{
var content = new ContentType1(null);
var view = new RenderModelOfContentType1TestPage();
var viewData = new ViewDataDictionary(content);
view.ViewContext = GetViewContext();
view.SetViewDataX(viewData);
Assert.IsInstanceOf<ContentModel<ContentType1>>(view.Model);
Assert.IsInstanceOf<ContentType1>(view.Model.Content);
}
[Test]
public void ContentType2_To_RenderModelOf_ContentType1()
{
var content = new ContentType2(null);
var view = new RenderModelOfContentType1TestPage();
var viewData = new ViewDataDictionary(content);
view.ViewContext = GetViewContext();
view.SetViewDataX(viewData);
Assert.IsInstanceOf<ContentModel<ContentType1>>(view.Model);
Assert.IsInstanceOf<ContentType1>(view.Model.Content);
}
[Test]
public void ContentType1_To_RenderModelOf_ContentType2()
{
var content = new ContentType1(null);
var view = new RenderModelOfContentType2TestPage();
var viewData = new ViewDataDictionary(content);
view.ViewContext = GetViewContext();
Assert.Throws<ModelBindingException>(() =>view.SetViewDataX(viewData));
}
[Test]
public void ContentType1_To_ContentType1()
{
var content = new ContentType1(null);
var view = new ContentType1TestPage();
var viewData = new ViewDataDictionary(content);
view.ViewContext = GetViewContext();
view.SetViewDataX(viewData);
Assert.IsInstanceOf<ContentType1>(view.Model);
}
[Test]
public void ContentType1_To_ContentType2()
{
var content = new ContentType1(null);
var view = new ContentType2TestPage();
var viewData = new ViewDataDictionary(content);
view.ViewContext = GetViewContext();
Assert.Throws<ModelBindingException>(() => view.SetViewDataX(viewData));
}
[Test]
public void ContentType2_To_ContentType1()
{
var content = new ContentType2(null);
var view = new ContentType1TestPage();
var viewData = new ViewDataDictionary(content);
view.ViewContext = GetViewContext();
view.SetViewDataX(viewData);
Assert.IsInstanceOf<ContentType1>(view.Model);
}
#endregion
#region Test elements
public class TestPage<TModel> : UmbracoViewPage<TModel>
{
public override void Execute()
{
throw new NotImplementedException();
}
public void SetViewDataX(ViewDataDictionary viewData)
{
SetViewData(viewData);
}
}
public class RenderModelTestPage : TestPage<ContentModel>
{ }
public class RenderModelOfContentType1TestPage : TestPage<ContentModel<ContentType1>>
{ }
public class RenderModelOfContentType2TestPage : TestPage<ContentModel<ContentType2>>
{ }
public class ContentType1TestPage : TestPage<ContentType1>
{ }
public class ContentType2TestPage : TestPage<ContentType2>
{ }
public class ContentType1 : PublishedContentWrapped
{
public ContentType1(IPublishedContent content) : base(content) {}
}
public class ContentType2 : ContentType1
{
public ContentType2(IPublishedContent content) : base(content) { }
}
#endregion
#region Test helpers
ServiceContext GetServiceContext()
{
return TestObjects.GetServiceContextMock();
}
ViewContext GetViewContext()
{
var umbracoContext = GetUmbracoContext("/dang", 0);
var webRoutingSettings = new WebRoutingSettings();
var publishedRouter = BaseWebTest.CreatePublishedRouter(webRoutingSettings);
var frequest = publishedRouter.CreateRequest(umbracoContext, new Uri("http://localhost/dang"));
frequest.Culture = CultureInfo.InvariantCulture;
umbracoContext.PublishedRequest = frequest;
var context = new ViewContext();
context.RouteData = new RouteData();
context.RouteData.DataTokens.Add(Core.Constants.Web.UmbracoContextDataToken, umbracoContext);
return context;
}
protected IUmbracoContext GetUmbracoContext(string url, int templateId, RouteData routeData = null, bool setSingleton = false)
{
var svcCtx = GetServiceContext();
var databaseFactory = TestObjects.GetDatabaseFactoryMock();
//var appCtx = new ApplicationContext(
// new DatabaseContext(databaseFactory, logger, Mock.Of<IRuntimeState>(), Mock.Of<IMigrationEntryService>()),
// svcCtx,
// CacheHelper.CreateDisabledCacheHelper(),
// new ProfilingLogger(logger, Mock.Of<IProfiler>())) { /*IsReady = true*/ };
var cache = NoAppCache.Instance;
//var provider = new ScopeUnitOfWorkProvider(databaseFactory, new RepositoryFactory(Mock.Of<IServiceContainer>()));
var scopeProvider = TestObjects.GetScopeProvider(NullLoggerFactory.Instance);
var factory = Mock.Of<IPublishedContentTypeFactory>();
var umbracoContextAccessor = Mock.Of<IUmbracoContextAccessor>();
_service = new XmlPublishedSnapshotService(svcCtx, factory, scopeProvider, cache,
null, null,
umbracoContextAccessor, null, null, null,
new TestDefaultCultureAccessor(),
Current.LoggerFactory, TestObjects.GetGlobalSettings(),
TestHelper.GetHostingEnvironment(),
TestHelper.GetHostingEnvironmentLifetime(),
ShortStringHelper,
new SiteDomainHelper(),
Factory.GetInstance<IEntityXmlSerializer>(),
null, true, false
); // no events
var http = GetHttpContextFactory(url, routeData).HttpContext;
var httpContextAccessor = TestHelper.GetHttpContextAccessor(http);
var globalSettings = TestObjects.GetGlobalSettings();
var ctx = new UmbracoContext(
httpContextAccessor,
_service,
Mock.Of<IBackofficeSecurity>(),
globalSettings,
HostingEnvironment,
new TestVariationContextAccessor(),
UriUtility,
new AspNetCookieManager(httpContextAccessor));
//if (setSingleton)
//{
// UmbracoContext.Current = ctx;
//}
return ctx;
}
protected FakeHttpContextFactory GetHttpContextFactory(string url, RouteData routeData = null)
{
var factory = routeData != null
? new FakeHttpContextFactory(url, routeData)
: new FakeHttpContextFactory(url);
return factory;
}
#endregion
}
}

View File

@@ -1,7 +1,10 @@
using System;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Umbraco.Core;
@@ -11,6 +14,7 @@ using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Strings;
using Umbraco.Web.Common.ModelBinders;
namespace Umbraco.Web.Common.AspNetCore
{
@@ -29,6 +33,7 @@ namespace Umbraco.Web.Common.AspNetCore
private ContentSettings ContentSettings => Context.RequestServices.GetRequiredService<IOptions<ContentSettings>>().Value;
private IProfilerHtml ProfilerHtml => Context.RequestServices.GetRequiredService<IProfilerHtml>();
private IIOHelper IOHelper => Context.RequestServices.GetRequiredService<IIOHelper>();
private ContentModelBinder ContentModelBinder => new ContentModelBinder();
protected IUmbracoContext UmbracoContext => _umbracoContext ??= UmbracoContextAccessor.UmbracoContext;
@@ -85,5 +90,58 @@ namespace Umbraco.Web.Common.AspNetCore
base.WriteLiteral(value);
}
// maps model
protected async Task SetViewDataAsync(ViewDataDictionary viewData)
{
// capture the model before we tinker with the viewData
var viewDataModel = viewData.Model;
// map the view data (may change its type, may set model to null)
viewData = MapViewDataDictionary(viewData, typeof (TModel));
// bind the model
var bindingContext = new DefaultModelBindingContext();
await ContentModelBinder.BindModelAsync(bindingContext, viewDataModel, typeof (TModel));
viewData.Model = bindingContext.Result.Model;
// set the view data
ViewData = (ViewDataDictionary<TModel>) viewData;
}
// viewData is the ViewDataDictionary (maybe <TModel>) that we have
// modelType is the type of the model that we need to bind to
//
// figure out whether viewData can accept modelType else replace it
//
private static ViewDataDictionary MapViewDataDictionary(ViewDataDictionary viewData, Type modelType)
{
var viewDataType = viewData.GetType();
if (viewDataType.IsGenericType)
{
// ensure it is the proper generic type
var def = viewDataType.GetGenericTypeDefinition();
if (def != typeof(ViewDataDictionary<>))
throw new Exception("Could not map viewData of type \"" + viewDataType.FullName + "\".");
// get the viewData model type and compare with the actual view model type:
// viewData is ViewDataDictionary<viewDataModelType> and we will want to assign an
// object of type modelType to the Model property of type viewDataModelType, we
// need to check whether that is possible
var viewDataModelType = viewDataType.GenericTypeArguments[0];
if (viewDataModelType.IsAssignableFrom(modelType))
return viewData;
}
// if not possible or it is not generic then we need to create a new ViewDataDictionary
var nViewDataType = typeof(ViewDataDictionary<>).MakeGenericType(modelType);
var tViewData = new ViewDataDictionary(viewData) { Model = null }; // temp view data to copy values
var nViewData = (ViewDataDictionary)Activator.CreateInstance(nViewDataType, tViewData);
return nViewData;
}
}
}

View File

@@ -27,7 +27,7 @@ namespace Umbraco.Web.Common.ModelBinders
// No need for type checks to ensure we have the appropriate binder, as in .NET Core this is handled in the provider,
// in this case ContentModelBinderProvider.
// Being defensice though.... if for any reason the model is not either IContentModel or IPublishedContent,
// Being defensive though.... if for any reason the model is not either IContentModel or IPublishedContent,
// then we return since those are the only types this binder is dealing with.
if (source is IContentModel == false && source is IPublishedContent == false)
{
@@ -36,7 +36,7 @@ namespace Umbraco.Web.Common.ModelBinders
BindModelAsync(bindingContext, source, bindingContext.ModelType);
return Task.CompletedTask;
}
}
// source is the model that we have
// modelType is the type of the model that we need to bind to
@@ -58,6 +58,7 @@ namespace Umbraco.Web.Common.ModelBinders
var sourceType = source.GetType();
if (sourceType.Inherits(modelType)) // includes ==
{
bindingContext.Result = ModelBindingResult.Success(source);
return Task.CompletedTask;
}