Skip to content
This repository was archived by the owner on Jan 24, 2021. It is now read-only.

New route resolution engine #988

Merged
merged 15 commits into from
Feb 16, 2013
49 changes: 49 additions & 0 deletions src/Nancy.Testing/ConfigurableBootstrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ namespace Nancy.Testing
using Nancy.ErrorHandling;
using Nancy.ModelBinding;
using Nancy.Routing;
using Nancy.Routing.Trie;
using Nancy.Security;
using Nancy.TinyIoc;
using Nancy.ViewEngines;
Expand Down Expand Up @@ -1571,6 +1572,54 @@ public ConfigurableBootstrapperConfigurator StaticContentProvider<T>() where T :
return this;
}

/// <summary>
/// Configures the bootstrapper to use the provided instance of <see cref="IRouteResolverTrie "/>.
/// </summary>
/// <param name="routeResolverTrie">The <see cref="IStaticContentProvider "/> instance that should be used by the bootstrapper.</param>
/// <returns>A reference to the current <see cref="ConfigurableBootstrapperConfigurator"/>.</returns>
public ConfigurableBootstrapperConfigurator RouteResolverTrie(IRouteResolverTrie routeResolverTrie)
{
this.bootstrapper.registeredInstances.Add(
new InstanceRegistration(typeof(IRouteResolverTrie), routeResolverTrie));

return this;
}

/// <summary>
/// Configures the bootstrapper to create an <see cref="IRouteResolverTrie"/> instance of the specified type.
/// </summary>
/// <typeparam name="T">The type of the <see cref="IRouteResolverTrie"/> that the bootstrapper should use.</typeparam>
/// <returns>A reference to the current <see cref="ConfigurableBootstrapperConfigurator"/>.</returns>
public ConfigurableBootstrapperConfigurator RouteResolverTrie<T>() where T : IRouteResolverTrie
{
this.bootstrapper.configuration.RouteResolverTrie = typeof(T);
return this;
}

/// <summary>
/// Configures the bootstrapper to use the provided instance of <see cref="ITrieNodeFactory "/>.
/// </summary>
/// <param name="nodeFactory">The <see cref="ITrieNodeFactory "/> instance that should be used by the bootstrapper.</param>
/// <returns>A reference to the current <see cref="ConfigurableBootstrapperConfigurator"/>.</returns>
public ConfigurableBootstrapperConfigurator TrieNodeFactory(ITrieNodeFactory nodeFactory)
{
this.bootstrapper.registeredInstances.Add(
new InstanceRegistration(typeof(ITrieNodeFactory), nodeFactory));

return this;
}

/// <summary>
/// Configures the bootstrapper to create an <see cref="ITrieNodeFactory"/> instance of the specified type.
/// </summary>
/// <typeparam name="T">The type of the <see cref="ITrieNodeFactory"/> that the bootstrapper should use.</typeparam>
/// <returns>A reference to the current <see cref="ConfigurableBootstrapperConfigurator"/>.</returns>
public ConfigurableBootstrapperConfigurator TrieNodeFactory<T>() where T : ITrieNodeFactory
{
this.bootstrapper.configuration.TrieNodeFactory = typeof(T);
return this;
}

/// <summary>
/// Configures the bootstrapper to add an assembly ignore predicate to the list
/// </summary>
Expand Down
10 changes: 8 additions & 2 deletions src/Nancy.Tests/Fakes/FakeRouteResolver.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
namespace Nancy.Tests.Fakes
{
using Nancy.Routing;
using ResolveResult = System.Tuple<Routing.Route, DynamicDictionary, System.Func<NancyContext, Response>, System.Action<NancyContext>, System.Func<NancyContext, System.Exception, Response>>;

public class FakeRouteResolver : IRouteResolver
{
Expand All @@ -11,7 +10,14 @@ public class FakeRouteResolver : IRouteResolver

ResolveResult IRouteResolver.Resolve(NancyContext context)
{
return new ResolveResult(new FakeRoute(), new DynamicDictionary(), null, null, null);
return new ResolveResult
{
Route = new FakeRoute(),
Parameters = new DynamicDictionary(),
Before = null,
After = null,
OnError = null
};
}
}
}
14 changes: 7 additions & 7 deletions src/Nancy.Tests/Unit/NancyEngineFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ namespace Nancy.Tests.Unit
using Nancy.Tests.Fakes;
using Xunit;
using Nancy.Culture;
using ResolveResult = System.Tuple<Nancy.Routing.Route, DynamicDictionary, System.Func<NancyContext, Response>, System.Action<NancyContext>, System.Func<NancyContext, System.Exception, Response>>;

public class NancyEngineFixture
{
Expand Down Expand Up @@ -42,7 +41,8 @@ public NancyEngineFixture()
contextFactory = A.Fake<INancyContextFactory>();
A.CallTo(() => contextFactory.Create(A<Request>._)).Returns(context);

A.CallTo(() => resolver.Resolve(A<NancyContext>.Ignored)).Returns(new ResolveResult(route, DynamicDictionary.Empty, null, null, null));
var resolveResult = new ResolveResult { Route = route, Parameters = DynamicDictionary.Empty, Before = null, After = null, OnError = null };
A.CallTo(() => resolver.Resolve(A<NancyContext>.Ignored)).Returns(resolveResult);

var applicationPipelines = new Pipelines();

Expand Down Expand Up @@ -126,7 +126,7 @@ public void HandleRequest_should_set_correct_response_on_returned_context()
var request = new Request("GET", "/", "http");

A.CallTo(() => this.requestDispatcher.Dispatch(this.context)).Invokes(x => this.context.Response = this.response);

// When
var result = this.engine.HandleRequest(request);

Expand Down Expand Up @@ -361,7 +361,7 @@ public void Should_store_exception_details_if_dispatcher_throws()
null);

A.CallTo(() => resolver.Resolve(A<NancyContext>.Ignored)).Returns(resolvedRoute);

A.CallTo(() => this.requestDispatcher.Dispatch(context)).Throws(new NotImplementedException());

var request = new Request("GET", "/", "http");
Expand All @@ -378,8 +378,8 @@ public void Should_invoke_the_error_request_hook_if_one_exists_when_dispatcher_t
{
// Given
var testEx = new Exception();
var errorRoute =

var errorRoute =
new Route("GET", "/", null, x => { throw testEx; });

var resolvedRoute = new ResolveResult(
Expand Down Expand Up @@ -519,7 +519,7 @@ public void Should_persist_original_exception_in_requestexecutionexception_when_
var expectedException = new Exception();

var resolvedRoute = new ResolveResult(
new FakeRoute(),
new FakeRoute(),
DynamicDictionary.Empty,
null,
null,
Expand Down
70 changes: 36 additions & 34 deletions src/Nancy.Tests/Unit/Routing/DefaultRequestDispatcherFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ namespace Nancy.Tests.Unit.Routing
using Nancy.Responses.Negotiation;
using Nancy.Routing;
using Xunit;
using ResolveResult = System.Tuple<Nancy.Routing.Route, DynamicDictionary, System.Func<NancyContext, Response>, System.Action<NancyContext>, System.Func<NancyContext, System.Exception, Response>>;

public class DefaultRequestDispatcherFixture
{
Expand All @@ -28,15 +27,17 @@ public DefaultRequestDispatcherFixture()
return (Response)((Route)arg.Arguments[0]).Action.Invoke(arg.Arguments[1]);
});

this.requestDispatcher =
this.requestDispatcher =
new DefaultRequestDispatcher(this.routeResolver, this.responseProcessors, this.routeInvoker);

var resolvedRoute = new ResolveResult(
new FakeRoute(),
DynamicDictionary.Empty,
null,
null,
null);
var resolvedRoute = new ResolveResult
{
Route = new FakeRoute(),
Parameters = DynamicDictionary.Empty,
Before = null,
After = null,
OnError = null
};

A.CallTo(() => this.routeResolver.Resolve(A<NancyContext>._)).Returns(resolvedRoute);
}
Expand All @@ -50,22 +51,25 @@ public void Should_invoke_module_before_hook_followed_by_resolved_route_followed

var route = new FakeRoute
{
Action = parameters => {
Action = parameters =>
{
capturedExecutionOrder.Add("RouteInvoke");
return null;
}
};

var resolvedRoute = new ResolveResult(
route,
DynamicDictionary.Empty,
ctx => { capturedExecutionOrder.Add("Prehook"); return null; },
ctx => capturedExecutionOrder.Add("Posthook"),
null);
var resolvedRoute = new ResolveResult
{
Route = route,
Parameters = DynamicDictionary.Empty,
Before = ctx => { capturedExecutionOrder.Add("Prehook"); return null; },
After = ctx => capturedExecutionOrder.Add("Posthook"),
OnError = null
};

A.CallTo(() => this.routeResolver.Resolve(A<NancyContext>.Ignored)).Returns(resolvedRoute);

var context =
var context =
new NancyContext { Request = new Request("GET", "/", "http") };

// When
Expand Down Expand Up @@ -95,7 +99,8 @@ public void Should_not_invoke_resolved_route_if_module_before_hook_returns_respo
var resolvedRoute = new ResolveResult(
route,
DynamicDictionary.Empty,
ctx => {
ctx =>
{
capturedExecutionOrder.Add("Prehook");
return new Response();
},
Expand Down Expand Up @@ -228,7 +233,7 @@ public void Should_set_the_route_parameters_from_resolved_route()
public void Should_invoke_route_resolver_with_context_for_current_request()
{
// Given
var context =
var context =
new NancyContext
{
Request = new FakeRequest("GET", "/")
Expand Down Expand Up @@ -262,7 +267,7 @@ public void Should_invoke_route_resolver_with_path_when_path_does_not_contain_fi
null);

A.CallTo(() => this.routeResolver.Resolve(context))
.Invokes(x => requestedPath = ((NancyContext) x.Arguments[0]).Request.Path)
.Invokes(x => requestedPath = ((NancyContext)x.Arguments[0]).Request.Path)
.Returns(resolvedRoute);

// When
Expand All @@ -282,7 +287,7 @@ public void Should_invoke_route_resolver_with_passed_in_accept_headers_when_path
{ new Tuple<string, decimal>("application/xml", 0.4m) }
};

var requestedAcceptHeaders =
var requestedAcceptHeaders =
new List<Tuple<string, decimal>>();

var request = new FakeRequest("GET", "/")
Expand Down Expand Up @@ -403,7 +408,7 @@ public void Should_invoke_route_resolver_with_distinct_mapped_media_ranged_when_
var jsonProcessor =
A.Fake<IResponseProcessor>();

var jsonProcessormappings =
var jsonProcessormappings =
new List<Tuple<string, MediaRange>> { { new Tuple<string, MediaRange>("json", "application/json") } };

A.CallTo(() => jsonProcessor.ExtensionMappings).Returns(jsonProcessormappings);
Expand Down Expand Up @@ -507,7 +512,7 @@ public void Should_call_route_invoker_with_resolved_route()
this.requestDispatcher.Dispatch(context);

// Then
A.CallTo(() => this.routeInvoker.Invoke(resolvedRoute.Item1, A<DynamicDictionary>._, A<NancyContext>._)).MustHaveHappened(Repeated.Exactly.Once);
A.CallTo(() => this.routeInvoker.Invoke(resolvedRoute.Route, A<DynamicDictionary>._, A<NancyContext>._)).MustHaveHappened(Repeated.Exactly.Once);
}

[Fact]
Expand All @@ -534,7 +539,7 @@ public void Should_invoke_route_resolver_with_path_containing_extension_when_map
this.responseProcessors.Add(jsonProcessor);

var resolvedRoute = new ResolveResult(
new NotFoundRoute("GET", "/"),
new NotFoundRoute("GET", "/"),
DynamicDictionary.Empty,
null,
null,
Expand Down Expand Up @@ -621,7 +626,7 @@ public void Should_invoke_module_onerror_hook_when_module_before_hook_throws_exc
}
};

var resolvedRoute = new Tuple<Route, DynamicDictionary, Func<NancyContext, Response>, Action<NancyContext>, Func<NancyContext, Exception, Response>>(
var resolvedRoute = new ResolveResult(
route,
DynamicDictionary.Empty,
ctx => { capturedExecutionOrder.Add("Prehook"); throw new Exception("Prehook"); },
Expand Down Expand Up @@ -657,7 +662,7 @@ public void Should_invoke_module_onerror_hook_when_route_invoker_throws_exceptio
}
};

var resolvedRoute = new Tuple<Route, DynamicDictionary, Func<NancyContext, Response>, Action<NancyContext>, Func<NancyContext, Exception, Response>>(
var resolvedRoute = new ResolveResult(
route,
DynamicDictionary.Empty,
ctx => null,
Expand Down Expand Up @@ -689,7 +694,7 @@ public void Should_invoke_module_onerror_hook_when_module_after_hook_throws_exce
Action = parameters => null
};

var resolvedRoute = new Tuple<Route, DynamicDictionary, Func<NancyContext, Response>, Action<NancyContext>, Func<NancyContext, Exception, Response>>(
var resolvedRoute = new ResolveResult(
route,
DynamicDictionary.Empty,
ctx => null,
Expand Down Expand Up @@ -718,7 +723,7 @@ public void Should_rethrow_exception_when_onerror_hook_does_return_response()
Action = parameters => { throw new Exception(); }
};

var resolvedRoute = new Tuple<Route, DynamicDictionary, Func<NancyContext, Response>, Action<NancyContext>, Func<NancyContext, Exception, Response>>(
var resolvedRoute = new ResolveResult(
route,
DynamicDictionary.Empty,
ctx => null,
Expand All @@ -745,7 +750,7 @@ public void Should_not_rethrow_exception_when_onerror_hook_returns_response()
Action = parameters => { throw new Exception(); }
};

var resolvedRoute = new Tuple<Route, DynamicDictionary, Func<NancyContext, Response>, Action<NancyContext>, Func<NancyContext, Exception, Response>>(
var resolvedRoute = new ResolveResult(
route,
DynamicDictionary.Empty,
ctx => null,
Expand All @@ -763,7 +768,7 @@ public void Should_not_rethrow_exception_when_onerror_hook_returns_response()
Assert.DoesNotThrow(() => this.requestDispatcher.Dispatch(context));
}

#if !__MonoCS__
#if !__MonoCS__
[Fact]
public void should_preserve_stacktrace_when_rethrowing_the_excption()
{
Expand All @@ -773,7 +778,7 @@ public void should_preserve_stacktrace_when_rethrowing_the_excption()
Action = o => BrokenMethod()
};

var resolvedRoute = new Tuple<Route, DynamicDictionary, Func<NancyContext, Response>, Action<NancyContext>, Func<NancyContext, Exception, Response>>(
var resolvedRoute = new ResolveResult(
route,
DynamicDictionary.Empty,
ctx => null,
Expand All @@ -785,12 +790,9 @@ public void should_preserve_stacktrace_when_rethrowing_the_excption()
var context =
new NancyContext { Request = new Request("GET", "/", "http") };



var exception = Assert.Throws<Exception>(() => this.requestDispatcher.Dispatch(context));

Assert.Throws<Exception>(() => requestDispatcher.Dispatch(context))
.StackTrace.ShouldContain("BrokenMethod");
exception.StackTrace.ShouldContain("BrokenMethod");
}
#endif

Expand Down
Loading