From b992ef0ced87a22edeeeb213e35aa1e9eb613872 Mon Sep 17 00:00:00 2001 From: Jass Bagga Date: Tue, 10 Oct 2017 11:24:03 -0700 Subject: [PATCH] Add tests to ApplicationModelTest (#6932) Addresses #756 --- Mvc.sln | 2 +- .../ApplicationModelTest.cs | 30 ++++++++++++++++ .../Manage/Views/MultipleAreas/Index.cshtml | 1 + .../Products/Views/MultipleAreas/Index.cshtml | 1 + .../Services/Views/MultipleAreas/Index.cshtml | 1 + .../Controllers/ActionModelController.cs | 6 ++++ .../Controllers/ApplicationModelController.cs | 1 - .../Controllers/MultipleAreasController.cs | 16 +++++++++ .../Conventions/CloneActionAttribute.cs | 18 ++++++++++ .../Conventions/CloneActionConvention.cs | 36 +++++++++++++++++++ .../Conventions/MultipleAreasAttribute.cs | 19 ++++++++++ .../MultipleAreasControllerConvention.cs | 34 ++++++++++++++++++ .../ApplicationModelWebSite/Startup.cs | 5 +++ .../Views/ActionModel/Help.cshtml | 1 + .../Views/ActionModel/MoreHelp.cshtml | 1 + 15 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 test/WebSites/ApplicationModelWebSite/Areas/Manage/Views/MultipleAreas/Index.cshtml create mode 100644 test/WebSites/ApplicationModelWebSite/Areas/Products/Views/MultipleAreas/Index.cshtml create mode 100644 test/WebSites/ApplicationModelWebSite/Areas/Services/Views/MultipleAreas/Index.cshtml create mode 100644 test/WebSites/ApplicationModelWebSite/Controllers/MultipleAreasController.cs create mode 100644 test/WebSites/ApplicationModelWebSite/Conventions/CloneActionAttribute.cs create mode 100644 test/WebSites/ApplicationModelWebSite/Conventions/CloneActionConvention.cs create mode 100644 test/WebSites/ApplicationModelWebSite/Conventions/MultipleAreasAttribute.cs create mode 100644 test/WebSites/ApplicationModelWebSite/Conventions/MultipleAreasControllerConvention.cs create mode 100644 test/WebSites/ApplicationModelWebSite/Views/ActionModel/Help.cshtml create mode 100644 test/WebSites/ApplicationModelWebSite/Views/ActionModel/MoreHelp.cshtml diff --git a/Mvc.sln b/Mvc.sln index 0a6d8bc906..b2bf771f05 100644 --- a/Mvc.sln +++ b/Mvc.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26730.10 +VisualStudioVersion = 15.0.26831.3000 MinimumVisualStudioVersion = 15.0.26730.03 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}" EndProject diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ApplicationModelTest.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ApplicationModelTest.cs index 3d2419419c..490f2d1a06 100644 --- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ApplicationModelTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/ApplicationModelTest.cs @@ -166,5 +166,35 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests // Assert Assert.Equal("/Home/CannotBeRouted", response.Headers.Location.ToString()); } + + [Theory] + [InlineData("Products", "Products View")] + [InlineData("Services", "Services View")] + [InlineData("Manage", "Manage View")] + public async Task ApplicationModel_CanDuplicateController_InMultipleAreas(string areaName, string expectedContent) + { + // Arrange & Act + var response = await Client.GetAsync(areaName + "/MultipleAreas/Index"); + var content = await response.Content.ReadAsStringAsync(); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Contains(expectedContent, content); + } + + [Theory] + [InlineData("Help", "This is the help page")] + [InlineData("MoreHelp", "This is the more help page")] + public async Task ControllerModel_CanDuplicateActions_RoutesToDifferentNames(string actionName, string expectedContent) + { + // Arrange & Act + var response = await Client.GetAsync("ActionModel/" + actionName); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + + var body = await response.Content.ReadAsStringAsync(); + Assert.Contains(expectedContent, body); + } } } \ No newline at end of file diff --git a/test/WebSites/ApplicationModelWebSite/Areas/Manage/Views/MultipleAreas/Index.cshtml b/test/WebSites/ApplicationModelWebSite/Areas/Manage/Views/MultipleAreas/Index.cshtml new file mode 100644 index 0000000000..7614945d2d --- /dev/null +++ b/test/WebSites/ApplicationModelWebSite/Areas/Manage/Views/MultipleAreas/Index.cshtml @@ -0,0 +1 @@ +Manage View \ No newline at end of file diff --git a/test/WebSites/ApplicationModelWebSite/Areas/Products/Views/MultipleAreas/Index.cshtml b/test/WebSites/ApplicationModelWebSite/Areas/Products/Views/MultipleAreas/Index.cshtml new file mode 100644 index 0000000000..b66a5db5c5 --- /dev/null +++ b/test/WebSites/ApplicationModelWebSite/Areas/Products/Views/MultipleAreas/Index.cshtml @@ -0,0 +1 @@ +Products View \ No newline at end of file diff --git a/test/WebSites/ApplicationModelWebSite/Areas/Services/Views/MultipleAreas/Index.cshtml b/test/WebSites/ApplicationModelWebSite/Areas/Services/Views/MultipleAreas/Index.cshtml new file mode 100644 index 0000000000..cab53fe767 --- /dev/null +++ b/test/WebSites/ApplicationModelWebSite/Areas/Services/Views/MultipleAreas/Index.cshtml @@ -0,0 +1 @@ +Services View diff --git a/test/WebSites/ApplicationModelWebSite/Controllers/ActionModelController.cs b/test/WebSites/ApplicationModelWebSite/Controllers/ActionModelController.cs index d68ad4db03..11d885a739 100644 --- a/test/WebSites/ApplicationModelWebSite/Controllers/ActionModelController.cs +++ b/test/WebSites/ApplicationModelWebSite/Controllers/ActionModelController.cs @@ -17,6 +17,12 @@ namespace ApplicationModelWebSite return ControllerContext.ActionDescriptor.ActionName; } + [CloneAction("MoreHelp")] + public IActionResult Help() + { + return View(); + } + private class ActionName2Attribute : Attribute, IActionModelConvention { private readonly string _actionName; diff --git a/test/WebSites/ApplicationModelWebSite/Controllers/ApplicationModelController.cs b/test/WebSites/ApplicationModelWebSite/Controllers/ApplicationModelController.cs index a57701f5c5..d9333559d3 100644 --- a/test/WebSites/ApplicationModelWebSite/Controllers/ApplicationModelController.cs +++ b/test/WebSites/ApplicationModelWebSite/Controllers/ApplicationModelController.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Controllers; namespace ApplicationModelWebSite { diff --git a/test/WebSites/ApplicationModelWebSite/Controllers/MultipleAreasController.cs b/test/WebSites/ApplicationModelWebSite/Controllers/MultipleAreasController.cs new file mode 100644 index 0000000000..d80475284b --- /dev/null +++ b/test/WebSites/ApplicationModelWebSite/Controllers/MultipleAreasController.cs @@ -0,0 +1,16 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Mvc; + +namespace ApplicationModelWebSite.Controllers +{ + [MultipleAreas("Products", "Services", "Manage")] + public class MultipleAreasController : Controller + { + public IActionResult Index() + { + return View(); + } + } +} diff --git a/test/WebSites/ApplicationModelWebSite/Conventions/CloneActionAttribute.cs b/test/WebSites/ApplicationModelWebSite/Conventions/CloneActionAttribute.cs new file mode 100644 index 0000000000..b5a80c8e85 --- /dev/null +++ b/test/WebSites/ApplicationModelWebSite/Conventions/CloneActionAttribute.cs @@ -0,0 +1,18 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; + +namespace ApplicationModelWebSite +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public class CloneActionAttribute : Attribute + { + public CloneActionAttribute(string newActionName) + { + ActionName = newActionName; + } + + public string ActionName { get; private set; } + } +} diff --git a/test/WebSites/ApplicationModelWebSite/Conventions/CloneActionConvention.cs b/test/WebSites/ApplicationModelWebSite/Conventions/CloneActionConvention.cs new file mode 100644 index 0000000000..6ce7e65908 --- /dev/null +++ b/test/WebSites/ApplicationModelWebSite/Conventions/CloneActionConvention.cs @@ -0,0 +1,36 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Mvc.ApplicationModels; + +namespace ApplicationModelWebSite +{ + public class CloneActionConvention : IControllerModelConvention + { + public void Apply(ControllerModel controller) + { + var actionModels = new List(); + foreach (var action in controller.Actions) + { + var actionName = action.Attributes.OfType()?.FirstOrDefault()?.ActionName; + + if (!string.IsNullOrEmpty(actionName)) + { + var actionCopy = new ActionModel(action) + { + ActionName = actionName + }; + + actionModels.Add(actionCopy); + } + } + + foreach (var model in actionModels) + { + controller.Actions.Add(model); + } + } + } +} \ No newline at end of file diff --git a/test/WebSites/ApplicationModelWebSite/Conventions/MultipleAreasAttribute.cs b/test/WebSites/ApplicationModelWebSite/Conventions/MultipleAreasAttribute.cs new file mode 100644 index 0000000000..181bf5e309 --- /dev/null +++ b/test/WebSites/ApplicationModelWebSite/Conventions/MultipleAreasAttribute.cs @@ -0,0 +1,19 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Linq; + +namespace ApplicationModelWebSite +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class MultipleAreasAttribute : Attribute + { + public MultipleAreasAttribute(string area1, string area2, params string[] areaNames) + { + AreaNames = new string[] { area1, area2 }.Concat(areaNames).ToArray(); + } + + public string[] AreaNames { get; } + } +} diff --git a/test/WebSites/ApplicationModelWebSite/Conventions/MultipleAreasControllerConvention.cs b/test/WebSites/ApplicationModelWebSite/Conventions/MultipleAreasControllerConvention.cs new file mode 100644 index 0000000000..9342bb8bc3 --- /dev/null +++ b/test/WebSites/ApplicationModelWebSite/Conventions/MultipleAreasControllerConvention.cs @@ -0,0 +1,34 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Microsoft.AspNetCore.Mvc.ApplicationModels; + +namespace ApplicationModelWebSite +{ + public class MultipleAreasControllerConvention : IApplicationModelConvention + { + public void Apply(ApplicationModel application) + { + var controllerModels = new List(); + foreach (var controller in application.Controllers) + { + var areaNames = controller.ControllerType.GetCustomAttributes()?.FirstOrDefault()?.AreaNames; + controller.RouteValues.Add("area", areaNames?[0]); + for (var i = 1; i < areaNames?.Length; i++) + { + var controllerCopy = new ControllerModel(controller); + controllerCopy.RouteValues["area"] = areaNames[i]; + controllerModels.Add(controllerCopy); + } + } + + foreach (var model in controllerModels) + { + application.Controllers.Add(model); + } + } + } +} diff --git a/test/WebSites/ApplicationModelWebSite/Startup.cs b/test/WebSites/ApplicationModelWebSite/Startup.cs index 22a314cc26..d750fcf946 100644 --- a/test/WebSites/ApplicationModelWebSite/Startup.cs +++ b/test/WebSites/ApplicationModelWebSite/Startup.cs @@ -18,6 +18,8 @@ namespace ApplicationModelWebSite options.Conventions.Add(new ApplicationDescription("Common Application Description")); options.Conventions.Add(new ControllerLicenseConvention()); options.Conventions.Add(new FromHeaderConvention()); + options.Conventions.Add(new MultipleAreasControllerConvention()); + options.Conventions.Add(new CloneActionConvention()); }); } @@ -25,6 +27,9 @@ namespace ApplicationModelWebSite { app.UseMvc(routes => { + routes.MapRoute(name: "areaRoute", + template: "{area:exists}/{controller=Home}/{action=Index}"); + routes.MapRoute( name: "default", template: "{controller}/{action}/{id?}"); diff --git a/test/WebSites/ApplicationModelWebSite/Views/ActionModel/Help.cshtml b/test/WebSites/ApplicationModelWebSite/Views/ActionModel/Help.cshtml new file mode 100644 index 0000000000..28718982b2 --- /dev/null +++ b/test/WebSites/ApplicationModelWebSite/Views/ActionModel/Help.cshtml @@ -0,0 +1 @@ +This is the help page diff --git a/test/WebSites/ApplicationModelWebSite/Views/ActionModel/MoreHelp.cshtml b/test/WebSites/ApplicationModelWebSite/Views/ActionModel/MoreHelp.cshtml new file mode 100644 index 0000000000..1ebee20c3f --- /dev/null +++ b/test/WebSites/ApplicationModelWebSite/Views/ActionModel/MoreHelp.cshtml @@ -0,0 +1 @@ +This is the more help page