diff --git a/src/Umbraco.Tests/DocumentLookups/BaseTest.cs b/src/Umbraco.Tests/DocumentLookups/BaseRoutingTest.cs similarity index 76% rename from src/Umbraco.Tests/DocumentLookups/BaseTest.cs rename to src/Umbraco.Tests/DocumentLookups/BaseRoutingTest.cs index f6b959b095..e43d502660 100644 --- a/src/Umbraco.Tests/DocumentLookups/BaseTest.cs +++ b/src/Umbraco.Tests/DocumentLookups/BaseRoutingTest.cs @@ -1,5 +1,6 @@ using System.Configuration; using System.Linq; +using System.Web.Routing; using System.Xml; using NUnit.Framework; using Umbraco.Core; @@ -15,7 +16,7 @@ using umbraco.cms.businesslogic.template; namespace Umbraco.Tests.DocumentLookups { [TestFixture, RequiresSTA] - public abstract class BaseTest + public abstract class BaseRoutingTest { [SetUp] public virtual void Initialize() @@ -23,6 +24,7 @@ namespace Umbraco.Tests.DocumentLookups TestHelper.SetupLog4NetForTests(); TestHelper.InitializeDatabase(); Resolution.Freeze(); + ApplicationContext = new ApplicationContext() { IsReady = true }; } [TearDown] @@ -36,9 +38,12 @@ namespace Umbraco.Tests.DocumentLookups Cache.ClearAllCache(); } - protected FakeHttpContextFactory GetHttpContextFactory(string url) + protected FakeHttpContextFactory GetHttpContextFactory(string url, RouteData routeData = null) { - var factory = new FakeHttpContextFactory(url); + var factory = routeData != null + ? new FakeHttpContextFactory(url, routeData) + : new FakeHttpContextFactory(url); + //set the state helper StateHelper.HttpContext = factory.HttpContext; @@ -46,19 +51,21 @@ namespace Umbraco.Tests.DocumentLookups return factory; } - private UmbracoContext GetUmbracoContext(string url, Template template) + protected ApplicationContext ApplicationContext { get; private set; } + + private UmbracoContext GetUmbracoContext(string url, Template template, RouteData routeData = null) { var ctx = new UmbracoContext( - GetHttpContextFactory(url).HttpContext, - new ApplicationContext(), + GetHttpContextFactory(url, routeData).HttpContext, + ApplicationContext, new FakeRoutesCache()); SetupUmbracoContextForTest(ctx, template); return ctx; } - protected RoutingContext GetRoutingContext(string url, Template template) + protected RoutingContext GetRoutingContext(string url, Template template, RouteData routeData = null) { - var umbracoContext = GetUmbracoContext(url, template); + var umbracoContext = GetUmbracoContext(url, template, routeData); var contentStore = new XmlContentStore(); var niceUrls = new NiceUrlProvider(contentStore, umbracoContext); var routingRequest = new RoutingContext( @@ -70,23 +77,14 @@ namespace Umbraco.Tests.DocumentLookups return routingRequest; } - /// - /// Initlializes the UmbracoContext with specific XML - /// - /// - /// - protected void SetupUmbracoContextForTest(UmbracoContext umbracoContext, Template template) + protected virtual string GetXmlContent(Template template) { - umbracoContext.GetXmlDelegate = () => - { - var xDoc = new XmlDocument(); - - //create a custom xml structure to return - - xDoc.LoadXml(@" + - + + ]> @@ -106,8 +104,24 @@ namespace Umbraco.Tests.DocumentLookups - -"); + +"; + } + + /// + /// Initlializes the UmbracoContext with specific XML + /// + /// + /// + protected void SetupUmbracoContextForTest(UmbracoContext umbracoContext, Template template) + { + umbracoContext.GetXmlDelegate = () => + { + var xDoc = new XmlDocument(); + + //create a custom xml structure to return + + xDoc.LoadXml(GetXmlContent(template)); //return the custom x doc return xDoc; }; diff --git a/src/Umbraco.Tests/DocumentLookups/LookupByAliasTests.cs b/src/Umbraco.Tests/DocumentLookups/LookupByAliasTests.cs index bd59149efc..fd331be25a 100644 --- a/src/Umbraco.Tests/DocumentLookups/LookupByAliasTests.cs +++ b/src/Umbraco.Tests/DocumentLookups/LookupByAliasTests.cs @@ -7,7 +7,7 @@ using umbraco.cms.businesslogic.template; namespace Umbraco.Tests.DocumentLookups { [TestFixture] - public class LookupByAliasTests : BaseTest + public class LookupByAliasTests : BaseRoutingTest { [TestCase("/this/is/my/alias", 1046)] [TestCase("/anotheralias", 1046)] diff --git a/src/Umbraco.Tests/DocumentLookups/LookupByNiceUrlTests.cs b/src/Umbraco.Tests/DocumentLookups/LookupByNiceUrlTests.cs index 2ca7856754..7633b9d13e 100644 --- a/src/Umbraco.Tests/DocumentLookups/LookupByNiceUrlTests.cs +++ b/src/Umbraco.Tests/DocumentLookups/LookupByNiceUrlTests.cs @@ -8,7 +8,7 @@ using umbraco.cms.businesslogic.template; namespace Umbraco.Tests.DocumentLookups { [TestFixture] - public class LookupByNiceUrlTests : BaseTest + public class LookupByNiceUrlTests : BaseRoutingTest { [TestCase("/")] diff --git a/src/Umbraco.Tests/DocumentLookups/RenderRouteHandlerTests.cs b/src/Umbraco.Tests/DocumentLookups/RenderRouteHandlerTests.cs new file mode 100644 index 0000000000..0681556b3c --- /dev/null +++ b/src/Umbraco.Tests/DocumentLookups/RenderRouteHandlerTests.cs @@ -0,0 +1,94 @@ +using System.Linq; +using System.Web.Mvc; +using System.Web.Routing; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Tests.Stubs; +using Umbraco.Tests.TestHelpers; +using Umbraco.Web; +using Umbraco.Web.Models; +using Umbraco.Web.Mvc; +using Umbraco.Web.Routing; +using umbraco.BusinessLogic; +using umbraco.cms.businesslogic.template; + +namespace Umbraco.Tests.DocumentLookups +{ + [TestFixture] + public class RenderRouteHandlerTests : BaseRoutingTest + { + + public override void Initialize() + { + base.Initialize(); + var webBoot = new WebBootManager(new UmbracoApplication()); + webBoot.CreateRoutes(); + } + + public override void TearDown() + { + base.TearDown(); + RouteTable.Routes.Clear(); + } + + //test all template name styles to match the ActionName + [TestCase("home-page")] + [TestCase("Home-Page")] + [TestCase("HomePage")] + [TestCase("homePage")] + public void Umbraco_Route_User_Defined_Controller_Action(string templateName) + { + var template = Template.MakeNew(templateName, new User(0)); + var route = RouteTable.Routes["Umbraco_default"]; + var routeData = new RouteData() {Route = route}; + var routingContext = GetRoutingContext("~/dummy-page", template, routeData); + var docRequest = new DocumentRequest(routingContext.UmbracoContext.UmbracoUrl, routingContext) + { + Node = routingContext.ContentStore.GetDocumentById(routingContext.UmbracoContext, 1172), + Template = template + }; + + var handler = new RenderRouteHandler(new TestControllerFactory()); + + handler.GetHandlerForRoute(routingContext.UmbracoContext.HttpContext.Request.RequestContext, docRequest); + Assert.AreEqual("CustomDocument", routeData.Values["controller"].ToString()); + Assert.AreEqual("HomePage", routeData.Values["action"].ToString()); + } + + + #region Internal classes + + ///// + ///// Used to test a user route (non-umbraco) + ///// + //private class CustomUserController : Controller + //{ + + // public ActionResult Index() + // { + // return View(); + // } + + // public ActionResult Test(int id) + // { + // return View(); + // } + + //} + + /// + /// Used to test a user route umbraco route + /// + public class CustomDocumentController : RenderMvcController + { + + public ActionResult HomePage(RenderModel model) + { + return View(); + } + + } + + #endregion + } +} diff --git a/src/Umbraco.Tests/DocumentLookups/RouteTestExtensions.cs b/src/Umbraco.Tests/DocumentLookups/RouteTestExtensions.cs new file mode 100644 index 0000000000..404e9ea4b2 --- /dev/null +++ b/src/Umbraco.Tests/DocumentLookups/RouteTestExtensions.cs @@ -0,0 +1,57 @@ +using System.Web; +using System.Web.Routing; +using Rhino.Mocks; +using Umbraco.Tests.TestHelpers; + +namespace Umbraco.Tests.DocumentLookups +{ + public static class RouteTestExtensions + { + + /// + /// Return the route data for the url based on a mocked context + /// + /// + /// + /// + public static RouteData GetDataForRoute(this RouteCollection routes, string requestUrl) + { + var context = new FakeHttpContextFactory(requestUrl); + return routes.GetDataForRoute(context.HttpContext); + } + + /// + /// Get the route data based on the url and http context + /// + /// + /// + /// + public static RouteData GetDataForRoute(this RouteCollection routes, HttpContextBase httpContext) + { + var data = routes.GetRouteData(httpContext); + + //set the route data on the request context + httpContext.Request.RequestContext.Stub(x => x.RouteData).Return(data); + + return data; + } + + /// + /// Checks if the URL will be ignored in the RouteTable + /// + /// + /// + /// + /// MVCContrib has a similar one but is faulty: + /// http://mvccontrib.codeplex.com/workitem/7173 + /// + public static bool ShouldIgnoreRoute(this string url) + { + var http = new FakeHttpContextFactory(url); + var r = RouteTable.Routes.GetRouteData(http.HttpContext); + if (r == null) return false; + return (r.RouteHandler is StopRoutingHandler); + } + + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/Stubs/TestControllerFactory.cs b/src/Umbraco.Tests/Stubs/TestControllerFactory.cs new file mode 100644 index 0000000000..98bedaa078 --- /dev/null +++ b/src/Umbraco.Tests/Stubs/TestControllerFactory.cs @@ -0,0 +1,39 @@ +using System; +using System.Linq; +using System.Reflection; +using System.Web.Mvc; +using System.Web.Routing; +using Umbraco.Core; + +namespace Umbraco.Tests.Stubs +{ + /// + /// Used in place of the UmbracoControllerFactory which relies on BuildManager which throws exceptions in a unit test context + /// + internal class TestControllerFactory : IControllerFactory + { + + public IController CreateController(RequestContext requestContext, string controllerName) + { + var types = TypeFinder.FindClassesOfType(new[] { Assembly.GetExecutingAssembly() }); + + var controllerTypes = types.Where(x => x.Name.Equals(controllerName + "Controller", StringComparison.InvariantCultureIgnoreCase)); + var t = controllerTypes.SingleOrDefault(); + + if (t == null) + return null; + + return Activator.CreateInstance(t) as IController; + } + + public System.Web.SessionState.SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName) + { + throw new NotImplementedException(); + } + + public void ReleaseController(IController controller) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index e8b99d7221..51599750d7 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -60,9 +60,12 @@ - + + + + diff --git a/src/Umbraco.Web/Routing/DocumentRequest.cs b/src/Umbraco.Web/Routing/DocumentRequest.cs index 916f657cbe..8b125b9c2e 100644 --- a/src/Umbraco.Web/Routing/DocumentRequest.cs +++ b/src/Umbraco.Web/Routing/DocumentRequest.cs @@ -78,19 +78,7 @@ namespace Umbraco.Web.Routing // to allow for fallbacks when doing dictionnary lookup and such? public IDocument Node - { - //get - //{ - // if (!HasNode) - // return null; - // if (_node == null) - // { - // //TODO: See the note below, if we don't allow for a get/set INode then how would someone implement - // // their own INode? it would not be possible since we're instantiating a specific Node object here. - // _node = new Node(XmlNode); - // } - // return _node; - //} + { get { return _node; } set { @@ -100,27 +88,6 @@ namespace Umbraco.Web.Routing } } - ////TODO: Should we remove this somehow in place of an INode getter/setter? we are really bound to the xml structure here - ///// - ///// Gets or sets the document request's document xml node. - ///// - //internal XmlNode XmlNode - //{ - // get - // { - // return _xmlNode; - // } - // set - // { - // _xmlNode = value; - // this.Template = null; - // if (_xmlNode != null) - // _nodeId = int.Parse(RoutingContext.ContentStore.GetNodeProperty(_xmlNode, "@id")); - // else - // _nodeId = 0; - // } - //} - /// /// Gets or sets the document request's template. /// diff --git a/src/Umbraco.Web/WebBootManager.cs b/src/Umbraco.Web/WebBootManager.cs index 57a9308f5d..56a36232c9 100644 --- a/src/Umbraco.Web/WebBootManager.cs +++ b/src/Umbraco.Web/WebBootManager.cs @@ -51,12 +51,7 @@ namespace Umbraco.Web ModelBinders.Binders.Add(new KeyValuePair(typeof(RenderModel), new RenderModelBinder())); //set routes - var route = RouteTable.Routes.MapRoute( - "Umbraco_default", - "Umbraco/RenderMvc/{action}/{id}", - new { controller = "RenderMvc", action = "Index", id = UrlParameter.Optional } - ); - route.RouteHandler = new RenderRouteHandler(ControllerBuilder.Current.GetControllerFactory()); + CreateRoutes(); //find and initialize the application startup handlers, we need to initialize this resolver here because //it is a special resolver where they need to be instantiated first before any other resolvers in order to bind to @@ -107,6 +102,20 @@ namespace Umbraco.Web return this; } + /// + /// Creates the routes + /// + protected internal void CreateRoutes() + { + //set routes + var route = RouteTable.Routes.MapRoute( + "Umbraco_default", + "Umbraco/RenderMvc/{action}/{id}", + new { controller = "RenderMvc", action = "Index", id = UrlParameter.Optional } + ); + route.RouteHandler = new RenderRouteHandler(ControllerBuilder.Current.GetControllerFactory()); + } + /// /// Initializes all web based and core resolves ///