/src/Nancy.Tests/Unit/ViewEngines/DefaultViewFactoryFixture.cs

https://github.com/factormystic/Nancy · C# · 411 lines · 254 code · 99 blank · 58 comment · 2 complexity · 9ce0f77a11f7facfadef6ef2f9ed27e0 MD5 · raw file

  1. namespace Nancy.Tests.Unit.ViewEngines
  2. {
  3. using System;
  4. using System.Dynamic;
  5. using System.IO;
  6. using FakeItEasy;
  7. using Nancy.ViewEngines;
  8. using Nancy.Tests.Fakes;
  9. using Xunit;
  10. public class DefaultViewFactoryFixture
  11. {
  12. private readonly IViewResolver resolver;
  13. private readonly IRenderContextFactory renderContextFactory;
  14. public DefaultViewFactoryFixture()
  15. {
  16. this.resolver = A.Fake<IViewResolver>();
  17. this.renderContextFactory = A.Fake<IRenderContextFactory>();
  18. }
  19. private DefaultViewFactory CreateFactory(params IViewEngine[] viewEngines)
  20. {
  21. if (viewEngines == null)
  22. {
  23. viewEngines = new IViewEngine[] { };
  24. }
  25. return new DefaultViewFactory(this.resolver, viewEngines, this.renderContextFactory);
  26. }
  27. [Fact]
  28. public void Should_get_render_context_from_factory_when_rendering_view()
  29. {
  30. // Given
  31. var viewEngines = new[] {
  32. A.Fake<IViewEngine>(),
  33. };
  34. A.CallTo(() => viewEngines[0].Extensions).Returns(new[] { "html" });
  35. var location = new ViewLocationResult("location", "name", "html", GetEmptyContentReader());
  36. A.CallTo(() => this.resolver.GetViewLocation(A<string>.Ignored, A<object>.Ignored, A<ViewLocationContext>.Ignored)).Returns(location);
  37. var factory = this.CreateFactory(viewEngines);
  38. // When
  39. factory.RenderView("view.html", new object(), new ViewLocationContext());
  40. // Then
  41. A.CallTo(() => this.renderContextFactory.GetRenderContext(A<ViewLocationContext>.Ignored)).MustHaveHappened();
  42. }
  43. [Fact]
  44. public void Should_render_view_with_context_created_by_factory()
  45. {
  46. // Given
  47. var viewEngines = new[] {
  48. A.Fake<IViewEngine>(),
  49. };
  50. A.CallTo(() => viewEngines[0].Extensions).Returns(new[] { "html" });
  51. var location = new ViewLocationResult("location", "name", "html", GetEmptyContentReader());
  52. A.CallTo(() => this.resolver.GetViewLocation(A<string>.Ignored, A<object>.Ignored, A<ViewLocationContext>.Ignored)).Returns(location);
  53. var context = A.Fake<IRenderContext>();
  54. A.CallTo(() => this.renderContextFactory.GetRenderContext(A<ViewLocationContext>.Ignored)).Returns(context);
  55. var factory = this.CreateFactory(viewEngines);
  56. // When
  57. factory.RenderView("view.html", new object(), new ViewLocationContext());
  58. // Then
  59. A.CallTo(() => viewEngines[0].RenderView(A<ViewLocationResult>.Ignored, A<object>.Ignored, context)).MustHaveHappened();
  60. }
  61. [Fact]
  62. public void Should_not_build_render_context_more_than_once()
  63. {
  64. // Given
  65. var viewEngines = new[] {
  66. A.Fake<IViewEngine>(),
  67. };
  68. A.CallTo(() => viewEngines[0].Extensions).Returns(new[] { "html" });
  69. var location = new ViewLocationResult("location", "name", "html", GetEmptyContentReader());
  70. A.CallTo(() => this.resolver.GetViewLocation(A<string>.Ignored, A<object>.Ignored, A<ViewLocationContext>.Ignored)).Returns(location);
  71. var factory = this.CreateFactory(viewEngines);
  72. // When
  73. factory.RenderView("view.html", new object(), new ViewLocationContext());
  74. // Then
  75. A.CallTo(() => this.renderContextFactory.GetRenderContext(A<ViewLocationContext>.Ignored)).MustHaveHappened(Repeated.NoMoreThan.Once);
  76. }
  77. [Fact]
  78. public void Should_throw_argumentnullexception_when_rendering_view_and_viewlocationcontext_is_null()
  79. {
  80. // Given
  81. var factory = this.CreateFactory(null);
  82. // When
  83. var exception = Record.Exception(() => factory.RenderView("viewName", new object(), null));
  84. // Then
  85. exception.ShouldBeOfType<ArgumentNullException>();
  86. }
  87. [Fact]
  88. public void Should_throw_argumentexception_when_rendering_view_and_view_name_is_empty_and_model_is_null()
  89. {
  90. // Given
  91. var factory = this.CreateFactory(null);
  92. // When
  93. var exception = Record.Exception(() => factory.RenderView(string.Empty, null, new ViewLocationContext()));
  94. // Then
  95. exception.ShouldBeOfType<ArgumentException>();
  96. }
  97. [Fact]
  98. public void Should_throw_argumentexception_when_rendering_view_and_both_viewname_and_model_is_null()
  99. {
  100. // Given
  101. var factory = this.CreateFactory(null);
  102. // When
  103. var exception = Record.Exception(() => factory.RenderView(null, null, new ViewLocationContext()));
  104. // Then
  105. exception.ShouldBeOfType<ArgumentException>();
  106. }
  107. [Fact]
  108. public void Should_retrieve_view_from_view_locator_using_provided_view_name()
  109. {
  110. // Given
  111. var factory = this.CreateFactory();
  112. // When
  113. factory.RenderView("viewname.html", null, new ViewLocationContext());
  114. // Then)
  115. A.CallTo(() => this.resolver.GetViewLocation("viewname.html", A<object>.Ignored, A<ViewLocationContext>.Ignored)).MustHaveHappened();
  116. }
  117. [Fact]
  118. public void Should_retrieve_view_from_view_locator_using_provided_model()
  119. {
  120. // Given
  121. var factory = this.CreateFactory();
  122. var model = new object();
  123. // When
  124. factory.RenderView(null, model, new ViewLocationContext());
  125. // Then)
  126. A.CallTo(() => this.resolver.GetViewLocation(A<string>.Ignored, model, A<ViewLocationContext>.Ignored)).MustHaveHappened();
  127. }
  128. [Fact]
  129. public void Should_retrieve_view_from_view_locator_using_provided_module_path()
  130. {
  131. // Given
  132. var factory = this.CreateFactory();
  133. var model = new object();
  134. var viewLocationContext = new ViewLocationContext { ModulePath = "/bar" };
  135. // When
  136. factory.RenderView(null, model, viewLocationContext);
  137. // Then)
  138. A.CallTo(() => this.resolver.GetViewLocation(A<string>.Ignored, A<object>.Ignored, A<ViewLocationContext>.That.Matches(x => x.ModulePath.Equals("/bar")))).MustHaveHappened();
  139. }
  140. [Fact]
  141. public void Should_return_empty_action_when_view_could_not_be_located()
  142. {
  143. var factory = this.CreateFactory();
  144. A.CallTo(() => this.resolver.GetViewLocation(A<string>.Ignored, A<object>.Ignored, A<ViewLocationContext>.Ignored)).Returns(null);
  145. var response = factory.RenderView("foo", null, new ViewLocationContext());
  146. var stream = new MemoryStream();
  147. // When
  148. response.Contents.Invoke(stream);
  149. // Then
  150. stream.Length.ShouldEqual(0L);
  151. }
  152. [Fact]
  153. public void Should_call_first_view_engine_that_supports_extension_with_view_location_results()
  154. {
  155. // Given
  156. var viewEngines = new[] {
  157. A.Fake<IViewEngine>(),
  158. A.Fake<IViewEngine>(),
  159. };
  160. A.CallTo(() => viewEngines[0].Extensions).Returns(new[] { "html" });
  161. A.CallTo(() => viewEngines[1].Extensions).Returns(new[] { "html" });
  162. var location = new ViewLocationResult("location", "name", "html", GetEmptyContentReader());
  163. A.CallTo(() => this.resolver.GetViewLocation(A<string>.Ignored, A<object>.Ignored, A<ViewLocationContext>.Ignored)).Returns(location);
  164. var factory = this.CreateFactory(viewEngines);
  165. // When
  166. factory.RenderView("foo", null, new ViewLocationContext());
  167. // Then
  168. A.CallTo(() => viewEngines[0].RenderView(location, null, A<IRenderContext>.Ignored)).MustHaveHappened();
  169. }
  170. [Fact]
  171. public void Should_ignore_case_when_locating_view_engine_for_view_name_extension()
  172. {
  173. // Given
  174. var viewEngines = new[] {
  175. A.Fake<IViewEngine>(),
  176. };
  177. A.CallTo(() => viewEngines[0].Extensions).Returns(new[] { "HTML" });
  178. var location = new ViewLocationResult("location", "name", "html", GetEmptyContentReader());
  179. A.CallTo(() => this.resolver.GetViewLocation(A<string>.Ignored, A<object>.Ignored, A<ViewLocationContext>.Ignored)).Returns(location);
  180. var factory = this.CreateFactory(viewEngines);
  181. // When
  182. factory.RenderView("foo", null, new ViewLocationContext());
  183. // Then
  184. A.CallTo(() => viewEngines[0].RenderView(location, null, A<IRenderContext>.Ignored)).MustHaveHappened();
  185. }
  186. [Fact]
  187. public void Should_return_empty_action_when_no_view_engine_could_be_resolved()
  188. {
  189. // Given
  190. var location = new ViewLocationResult("location", "name", "html", GetEmptyContentReader());
  191. A.CallTo(() => this.resolver.GetViewLocation(A<string>.Ignored, A<object>.Ignored, A<ViewLocationContext>.Ignored)).Returns(location);
  192. var stream = new MemoryStream();
  193. var factory = this.CreateFactory();
  194. // When
  195. var response = factory.RenderView("foo", null, new ViewLocationContext());
  196. response.Contents.Invoke(stream);
  197. // Then
  198. stream.Length.ShouldEqual(0L);
  199. }
  200. [Fact]
  201. public void Should_return_response_from_invoked_engine()
  202. {
  203. // Given
  204. var viewEngines = new[] {
  205. A.Fake<IViewEngine>(),
  206. };
  207. Action<Stream> actionReturnedFromEngine = x => { };
  208. A.CallTo(() => viewEngines[0].Extensions).Returns(new[] { "html" });
  209. A.CallTo(() => viewEngines[0].RenderView(A<ViewLocationResult>.Ignored, null, A<IRenderContext>.Ignored)).Returns(actionReturnedFromEngine);
  210. var location = new ViewLocationResult("location", "name", "html", GetEmptyContentReader());
  211. A.CallTo(() => this.resolver.GetViewLocation(A<string>.Ignored, A<object>.Ignored, A<ViewLocationContext>.Ignored)).Returns(location);
  212. var factory = this.CreateFactory(viewEngines);
  213. // When
  214. var response = factory.RenderView("foo", null, new ViewLocationContext());
  215. // Then
  216. response.Contents.ShouldBeSameAs(actionReturnedFromEngine);
  217. }
  218. [Fact]
  219. public void Should_return_empty_action_when_view_engine_throws_exception()
  220. {
  221. var viewEngines = new[] {
  222. A.Fake<IViewEngine>(),
  223. };
  224. A.CallTo(() => viewEngines[0].Extensions).Returns(new[] { "html" });
  225. A.CallTo(() => viewEngines[0].RenderView(A<ViewLocationResult>.Ignored, null, A<IRenderContext>.Ignored)).Throws(new Exception());
  226. var location = new ViewLocationResult("location", "name", "html", GetEmptyContentReader());
  227. A.CallTo(() => this.resolver.GetViewLocation(A<string>.Ignored, A<object>.Ignored, A<ViewLocationContext>.Ignored)).Returns(location);
  228. var stream = new MemoryStream();
  229. var factory = this.CreateFactory(viewEngines);
  230. // When
  231. var response = factory.RenderView("foo", null, new ViewLocationContext());
  232. response.Contents.Invoke(stream);
  233. // Then
  234. stream.Length.ShouldEqual(0L);
  235. }
  236. [Fact]
  237. public void Should_invoke_view_engine_with_model()
  238. {
  239. // Given
  240. var viewEngines = new[] {
  241. A.Fake<IViewEngine>(),
  242. };
  243. A.CallTo(() => viewEngines[0].Extensions).Returns(new[] { "html" });
  244. A.CallTo(() => viewEngines[0].RenderView(A<ViewLocationResult>.Ignored, null, null)).Throws(new Exception());
  245. var location = new ViewLocationResult("location", "name", "html", GetEmptyContentReader());
  246. A.CallTo(() => this.resolver.GetViewLocation(A<string>.Ignored, A<object>.Ignored, A<ViewLocationContext>.Ignored)).Returns(location);
  247. var model = new object();
  248. var factory = this.CreateFactory(viewEngines);
  249. // When
  250. factory.RenderView("foo", model, new ViewLocationContext());
  251. // Then
  252. A.CallTo(() => viewEngines[0].RenderView(A<ViewLocationResult>.Ignored, model, A<IRenderContext>.Ignored)).MustHaveHappened();
  253. }
  254. [Fact]
  255. public void Should_covert_anonymoustype_model_to_expandoobject_before_invoking_view_engine()
  256. {
  257. // Given
  258. var viewEngines = new[] {
  259. A.Fake<IViewEngine>(),
  260. };
  261. A.CallTo(() => viewEngines[0].Extensions).Returns(new[] { "html" });
  262. var location = new ViewLocationResult("location", "name", "html", GetEmptyContentReader());
  263. A.CallTo(() => this.resolver.GetViewLocation(A<string>.Ignored, A<object>.Ignored, A<ViewLocationContext>.Ignored)).Returns(location);
  264. var model = new { Name = "" };
  265. var factory = this.CreateFactory(viewEngines);
  266. // When
  267. factory.RenderView("foo", model, new ViewLocationContext());
  268. // Then
  269. A.CallTo(() => viewEngines[0].RenderView(A<ViewLocationResult>.Ignored, A<object>.That.Matches(x => x.GetType().Equals(typeof(ExpandoObject))), A<IRenderContext>.Ignored)).MustHaveHappened();
  270. }
  271. [Fact]
  272. public void Should_transfer_anonymoustype_model_members_to_expandoobject_members_before_invoking_view_engines()
  273. {
  274. // Given
  275. var viewEngines = new[] {
  276. new FakeViewEngine { Extensions = new[] { "html"}}
  277. };
  278. var location = new ViewLocationResult("location", "name", "html", GetEmptyContentReader());
  279. A.CallTo(() => this.resolver.GetViewLocation(A<string>.Ignored, A<object>.Ignored, A<ViewLocationContext>.Ignored)).Returns(location);
  280. var model = new { Name = "Nancy" };
  281. var factory = this.CreateFactory(viewEngines);
  282. // When
  283. factory.RenderView("foo", model, new ViewLocationContext());
  284. // Then
  285. ((string)viewEngines[0].Model.Name).ShouldEqual("Nancy");
  286. }
  287. [Fact]
  288. public void Should_use_the_name_of_the_model_type_as_view_name_when_only_model_is_specified()
  289. {
  290. // Given
  291. var factory = this.CreateFactory();
  292. // When
  293. factory.RenderView(null, new object(), new ViewLocationContext());
  294. // Then
  295. A.CallTo(() => this.resolver.GetViewLocation("Object", A<object>.Ignored, A<ViewLocationContext>.Ignored)).MustHaveHappened();
  296. }
  297. [Fact]
  298. public void Should_use_the_name_of_the_model_type_without_model_suffix_as_view_name_when_only_model_is_specified()
  299. {
  300. // Given
  301. var factory = this.CreateFactory();
  302. // When
  303. factory.RenderView(null, new ViewModel(), new ViewLocationContext());
  304. // Then
  305. A.CallTo(() => this.resolver.GetViewLocation("View", A<object>.Ignored, A<ViewLocationContext>.Ignored)).MustHaveHappened();
  306. }
  307. private static Func<TextReader> GetEmptyContentReader()
  308. {
  309. return () => new StreamReader(new MemoryStream());
  310. }
  311. }
  312. }