PageRenderTime 38ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 1ms

/test/System.Web.Mvc.Test/Html/Test/TemplateHelpersTest.cs

https://bitbucket.org/mdavid/aspnetwebstack
C# | 1035 lines | 720 code | 164 blank | 151 comment | 0 complexity | 56d69a27b0d814a7f5854d86c8da11fd MD5 | raw file
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using System.Globalization;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Net;
  7. using System.Threading;
  8. using System.Web.Routing;
  9. using System.Web.UI.WebControls;
  10. using Microsoft.Web.UnitTestUtil;
  11. using Moq;
  12. using Xunit;
  13. using Assert = Microsoft.TestCommon.AssertEx;
  14. namespace System.Web.Mvc.Html.Test
  15. {
  16. public class TemplateHelpersTest
  17. {
  18. // ExecuteTemplate
  19. private class ExecuteTemplateModel
  20. {
  21. public string MyProperty { get; set; }
  22. public Nullable<int> MyNullableProperty { get; set; }
  23. }
  24. [Fact]
  25. public void ExecuteTemplateCallsGetViewNamesWithProvidedTemplateNameAndMetadataInformation()
  26. {
  27. using (new MockViewEngine())
  28. {
  29. // Arrange
  30. HtmlHelper html = MakeHtmlHelper(new ExecuteTemplateModel());
  31. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  32. metadata.TemplateHint = "templateHint";
  33. metadata.DataTypeName = "dataType";
  34. string[] hints = null;
  35. // Act
  36. TemplateHelpers.ExecuteTemplate(
  37. html, MakeViewData(html, metadata), "templateName", DataBoundControlMode.ReadOnly,
  38. (_metadata, _hints) =>
  39. {
  40. hints = _hints;
  41. return new[] { "String" };
  42. },
  43. TemplateHelpers.GetDefaultActions);
  44. // Assert
  45. Assert.NotNull(hints);
  46. Assert.Equal(3, hints.Length);
  47. Assert.Equal("templateName", hints[0]);
  48. Assert.Equal("templateHint", hints[1]);
  49. Assert.Equal("dataType", hints[2]);
  50. }
  51. }
  52. [Fact]
  53. public void ExecuteTemplateUsesViewFromViewEngineInReadOnlyMode()
  54. {
  55. using (MockViewEngine engine = new MockViewEngine())
  56. {
  57. // Arrange
  58. HtmlHelper html = MakeHtmlHelper(new ExecuteTemplateModel { MyProperty = "Hello" });
  59. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  60. ViewContext callbackViewContext = null;
  61. engine.Engine.Setup(e => e.FindPartialView(html.ViewContext, "DisplayTemplates/String", true))
  62. .Returns(new ViewEngineResult(engine.View.Object, engine.Engine.Object))
  63. .Verifiable();
  64. engine.View.Setup(v => v.Render(It.IsAny<ViewContext>(), It.IsAny<TextWriter>()))
  65. .Callback<ViewContext, TextWriter>((vc, tw) =>
  66. {
  67. callbackViewContext = vc;
  68. tw.Write("View Text");
  69. })
  70. .Verifiable();
  71. ViewDataDictionary viewData = MakeViewData(html, metadata);
  72. // Act
  73. string result = TemplateHelpers.ExecuteTemplate(
  74. html, viewData, "templateName", DataBoundControlMode.ReadOnly,
  75. delegate { return new[] { "String" }; },
  76. TemplateHelpers.GetDefaultActions);
  77. // Assert
  78. engine.Engine.Verify();
  79. engine.View.Verify();
  80. Assert.Equal("View Text", result);
  81. Assert.Same(engine.View.Object, callbackViewContext.View);
  82. Assert.Same(viewData, callbackViewContext.ViewData);
  83. Assert.Same(html.ViewContext.TempData, callbackViewContext.TempData);
  84. TemplateHelpers.ActionCacheViewItem cacheItem = TemplateHelpers.GetActionCache(html)["DisplayTemplates/String"] as TemplateHelpers.ActionCacheViewItem;
  85. Assert.NotNull(cacheItem);
  86. Assert.Equal("DisplayTemplates/String", cacheItem.ViewName);
  87. }
  88. }
  89. [Fact]
  90. public void ExecuteTemplateUsesViewFromViewEngineInEditMode()
  91. {
  92. using (MockViewEngine engine = new MockViewEngine())
  93. {
  94. // Arrange
  95. HtmlHelper html = MakeHtmlHelper(new ExecuteTemplateModel { MyProperty = "Hello" });
  96. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  97. ViewContext callbackViewContext = null;
  98. engine.Engine.Setup(e => e.FindPartialView(html.ViewContext, "EditorTemplates/String", true))
  99. .Returns(new ViewEngineResult(engine.View.Object, engine.Engine.Object))
  100. .Verifiable();
  101. engine.View.Setup(v => v.Render(It.IsAny<ViewContext>(), It.IsAny<TextWriter>()))
  102. .Callback<ViewContext, TextWriter>((vc, tw) =>
  103. {
  104. callbackViewContext = vc;
  105. tw.Write("View Text");
  106. })
  107. .Verifiable();
  108. ViewDataDictionary viewData = MakeViewData(html, metadata);
  109. // Act
  110. string result = TemplateHelpers.ExecuteTemplate(
  111. html, viewData, "templateName", DataBoundControlMode.Edit,
  112. delegate { return new[] { "String" }; },
  113. TemplateHelpers.GetDefaultActions);
  114. // Assert
  115. engine.Engine.Verify();
  116. engine.View.Verify();
  117. Assert.Equal("View Text", result);
  118. Assert.Same(engine.View.Object, callbackViewContext.View);
  119. Assert.Same(viewData, callbackViewContext.ViewData);
  120. Assert.Same(html.ViewContext.TempData, callbackViewContext.TempData);
  121. TemplateHelpers.ActionCacheViewItem cacheItem = TemplateHelpers.GetActionCache(html)["EditorTemplates/String"] as TemplateHelpers.ActionCacheViewItem;
  122. Assert.NotNull(cacheItem);
  123. Assert.Equal("EditorTemplates/String", cacheItem.ViewName);
  124. }
  125. }
  126. [Fact]
  127. public void ExecuteTemplateUsesViewFromDefaultActionsInReadOnlyMode()
  128. {
  129. using (MockViewEngine engine = new MockViewEngine())
  130. {
  131. // Arrange
  132. HtmlHelper html = MakeHtmlHelper(new ExecuteTemplateModel { MyProperty = "Hello" });
  133. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  134. engine.Engine.Setup(e => e.FindPartialView(html.ViewContext, "DisplayTemplates/String", It.IsAny<bool>()))
  135. .Returns(new ViewEngineResult(new string[0]))
  136. .Verifiable();
  137. ViewDataDictionary viewData = MakeViewData(html, metadata);
  138. // Act
  139. TemplateHelpers.ExecuteTemplate(
  140. html, viewData, "templateName", DataBoundControlMode.ReadOnly,
  141. delegate { return new[] { "String" }; },
  142. TemplateHelpers.GetDefaultActions);
  143. // Assert
  144. engine.Engine.Verify();
  145. TemplateHelpers.ActionCacheCodeItem cacheItem = TemplateHelpers.GetActionCache(html)["DisplayTemplates/String"] as TemplateHelpers.ActionCacheCodeItem;
  146. Assert.NotNull(cacheItem);
  147. Assert.Equal(DefaultDisplayTemplates.StringTemplate, cacheItem.Action);
  148. }
  149. }
  150. [Fact]
  151. public void ExecuteTemplateUsesViewFromDefaultActionsInEditMode()
  152. {
  153. using (MockViewEngine engine = new MockViewEngine())
  154. {
  155. // Arrange
  156. HtmlHelper html = MakeHtmlHelper(new ExecuteTemplateModel { MyProperty = "Hello" });
  157. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  158. engine.Engine.Setup(e => e.FindPartialView(html.ViewContext, "EditorTemplates/String", It.IsAny<bool>()))
  159. .Returns(new ViewEngineResult(new string[0]))
  160. .Verifiable();
  161. ViewDataDictionary viewData = MakeViewData(html, metadata);
  162. // Act
  163. TemplateHelpers.ExecuteTemplate(
  164. html, viewData, "templateName", DataBoundControlMode.Edit,
  165. delegate { return new[] { "String" }; },
  166. TemplateHelpers.GetDefaultActions);
  167. // Assert
  168. engine.Engine.Verify();
  169. TemplateHelpers.ActionCacheCodeItem cacheItem = TemplateHelpers.GetActionCache(html)["EditorTemplates/String"] as TemplateHelpers.ActionCacheCodeItem;
  170. Assert.NotNull(cacheItem);
  171. Assert.Equal(DefaultEditorTemplates.StringTemplate, cacheItem.Action);
  172. }
  173. }
  174. [Fact]
  175. public void ExecuteTemplatePrefersExistingActionCacheItem()
  176. {
  177. using (MockViewEngine engine = new MockViewEngine())
  178. {
  179. // Arrange
  180. HtmlHelper html = MakeHtmlHelper(new ExecuteTemplateModel { MyProperty = "Hello" });
  181. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  182. ViewDataDictionary viewData = MakeViewData(html, metadata);
  183. TemplateHelpers.GetActionCache(html).Add("EditorTemplates/String",
  184. new TemplateHelpers.ActionCacheCodeItem { Action = _ => "Action Text" });
  185. // Act
  186. string result = TemplateHelpers.ExecuteTemplate(
  187. html, viewData, "templateName", DataBoundControlMode.Edit,
  188. delegate { return new[] { "String" }; },
  189. TemplateHelpers.GetDefaultActions);
  190. // Assert
  191. engine.Engine.Verify();
  192. engine.Engine.Verify(e => e.FindPartialView(It.IsAny<ControllerContext>(), It.IsAny<string>(), It.IsAny<bool>()), Times.Never());
  193. Assert.Equal("Action Text", result);
  194. }
  195. }
  196. [Fact]
  197. public void ExecuteTemplateThrowsWhenNoTemplatesMatch()
  198. {
  199. using (new MockViewEngine())
  200. {
  201. // Arrange
  202. HtmlHelper html = MakeHtmlHelper(new ExecuteTemplateModel { MyProperty = "Hello" });
  203. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  204. ViewDataDictionary viewData = MakeViewData(html, metadata);
  205. // Act & Assert
  206. Assert.Throws<InvalidOperationException>(
  207. () => TemplateHelpers.ExecuteTemplate(html, viewData, "templateName", DataBoundControlMode.Edit, delegate { return new string[0]; }, TemplateHelpers.GetDefaultActions),
  208. "Unable to locate an appropriate template for type System.String.");
  209. }
  210. }
  211. [Fact]
  212. public void ExecuteTemplateCreatesNewHtmlHelperWithCorrectViewDataForDefaultAction()
  213. {
  214. using (MockViewEngine engine = new MockViewEngine(false))
  215. {
  216. // Arrange
  217. HtmlHelper html = MakeHtmlHelper(new ExecuteTemplateModel { MyProperty = "Hello" });
  218. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  219. ViewDataDictionary viewData = MakeViewData(html, metadata);
  220. HtmlHelper passedHtmlHelper = null;
  221. // Act
  222. TemplateHelpers.ExecuteTemplate(
  223. html, viewData, "templateName", DataBoundControlMode.Edit,
  224. delegate { return new[] { "String" }; },
  225. delegate
  226. {
  227. return new Dictionary<string, Func<HtmlHelper, string>>
  228. {
  229. {
  230. "String", _htmlHelper =>
  231. {
  232. passedHtmlHelper = _htmlHelper;
  233. return "content";
  234. }
  235. }
  236. };
  237. });
  238. // Assert
  239. Assert.NotNull(passedHtmlHelper);
  240. Assert.Same(passedHtmlHelper.ViewData, passedHtmlHelper.ViewContext.ViewData);
  241. Assert.NotSame(html.ViewData, passedHtmlHelper.ViewData);
  242. }
  243. }
  244. [Fact]
  245. public void ExecuteTemplateCreatesNewHtmlHelperWithCorrectViewDataForCachedAction()
  246. {
  247. using (MockViewEngine engine = new MockViewEngine())
  248. {
  249. // Arrange
  250. HtmlHelper html = MakeHtmlHelper(new ExecuteTemplateModel { MyProperty = "Hello" });
  251. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  252. ViewDataDictionary viewData = MakeViewData(html, metadata);
  253. HtmlHelper passedHtmlHelper = null;
  254. TemplateHelpers.GetActionCache(html).Add(
  255. "EditorTemplates/String",
  256. new TemplateHelpers.ActionCacheCodeItem
  257. {
  258. Action = _htmlHelper =>
  259. {
  260. passedHtmlHelper = _htmlHelper;
  261. return "content";
  262. }
  263. });
  264. // Act
  265. string result = TemplateHelpers.ExecuteTemplate(
  266. html, viewData, "templateName", DataBoundControlMode.Edit,
  267. delegate { return new[] { "String" }; },
  268. TemplateHelpers.GetDefaultActions);
  269. // Assert
  270. Assert.NotNull(passedHtmlHelper);
  271. Assert.Same(passedHtmlHelper.ViewData, passedHtmlHelper.ViewContext.ViewData);
  272. Assert.NotSame(html.ViewData, passedHtmlHelper.ViewData);
  273. }
  274. }
  275. // GetActionCache
  276. [Fact]
  277. public void CacheIsCreatedIfNotPresent()
  278. {
  279. // Arrange
  280. Hashtable items = new Hashtable();
  281. Mock<HttpContextBase> context = new Mock<HttpContextBase>();
  282. context.Setup(c => c.Items).Returns(items);
  283. Mock<ViewContext> viewContext = new Mock<ViewContext>();
  284. viewContext.Setup(c => c.HttpContext).Returns(context.Object);
  285. Mock<IViewDataContainer> viewDataContainer = new Mock<IViewDataContainer>();
  286. HtmlHelper helper = new HtmlHelper(viewContext.Object, viewDataContainer.Object);
  287. // Act
  288. Dictionary<string, TemplateHelpers.ActionCacheItem> cache = TemplateHelpers.GetActionCache(helper);
  289. // Assert
  290. Assert.NotNull(cache);
  291. Assert.Empty(cache);
  292. Assert.Contains((object)cache, items.Values.OfType<object>());
  293. }
  294. [Fact]
  295. public void CacheIsReusedIfPresent()
  296. {
  297. // Arrange
  298. Hashtable items = new Hashtable();
  299. Mock<HttpContextBase> context = new Mock<HttpContextBase>();
  300. context.Setup(c => c.Items).Returns(items);
  301. Mock<ViewContext> viewContext = new Mock<ViewContext>();
  302. viewContext.Setup(c => c.HttpContext).Returns(context.Object);
  303. Mock<IViewDataContainer> viewDataContainer = new Mock<IViewDataContainer>();
  304. HtmlHelper helper = new HtmlHelper(viewContext.Object, viewDataContainer.Object);
  305. // Act
  306. Dictionary<string, TemplateHelpers.ActionCacheItem> cache1 = TemplateHelpers.GetActionCache(helper);
  307. Dictionary<string, TemplateHelpers.ActionCacheItem> cache2 = TemplateHelpers.GetActionCache(helper);
  308. // Assert
  309. Assert.NotNull(cache1);
  310. Assert.Same(cache1, cache2);
  311. }
  312. // GetViewNames
  313. [Fact]
  314. public void GetViewNamesFullOrderingOfBuiltInValueType()
  315. {
  316. // Arrange
  317. ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(double));
  318. // Act
  319. List<string> result = TemplateHelpers.GetViewNames(metadata, "UIHint", "DataType").ToList();
  320. // Assert
  321. Assert.Equal(4, result.Count);
  322. Assert.Equal("UIHint", result[0]);
  323. Assert.Equal("DataType", result[1]);
  324. Assert.Equal("Double", result[2]);
  325. Assert.Equal("String", result[3]);
  326. }
  327. [Fact]
  328. public void GetViewNamesFullOrderingOfComplexType()
  329. {
  330. // Arrange
  331. ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(HttpWebRequest));
  332. // Act
  333. List<string> result = TemplateHelpers.GetViewNames(metadata, "UIHint", "DataType").ToList();
  334. // Assert
  335. Assert.Equal(6, result.Count);
  336. Assert.Equal("UIHint", result[0]);
  337. Assert.Equal("DataType", result[1]);
  338. Assert.Equal("HttpWebRequest", result[2]);
  339. Assert.Equal("WebRequest", result[3]);
  340. Assert.Equal("MarshalByRefObject", result[4]);
  341. Assert.Equal("Object", result[5]);
  342. }
  343. [Fact]
  344. public void GetViewNamesFullOrderingOfInterface()
  345. {
  346. // Arrange
  347. ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(IDisposable));
  348. // Act
  349. List<string> result = TemplateHelpers.GetViewNames(metadata, "UIHint", "DataType").ToList();
  350. // Assert
  351. Assert.Equal(4, result.Count);
  352. Assert.Equal("UIHint", result[0]);
  353. Assert.Equal("DataType", result[1]);
  354. Assert.Equal("IDisposable", result[2]);
  355. Assert.Equal("Object", result[3]);
  356. }
  357. [Fact]
  358. public void GetViewNamesFullOrderingOfComplexTypeThatImplementsIEnumerable()
  359. {
  360. // Arrange
  361. ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(List<int>));
  362. // Act
  363. List<string> result = TemplateHelpers.GetViewNames(metadata, "UIHint", "DataType").ToList();
  364. // Assert
  365. Assert.Equal(5, result.Count);
  366. Assert.Equal("UIHint", result[0]);
  367. Assert.Equal("DataType", result[1]);
  368. Assert.Equal("List`1", result[2]);
  369. Assert.Equal("Collection", result[3]);
  370. Assert.Equal("Object", result[4]);
  371. }
  372. [Fact]
  373. public void GetViewNamesFullOrderingOfInterfaceThatRequiresIEnumerable()
  374. {
  375. // Arrange
  376. ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(IList<int>));
  377. // Act
  378. List<string> result = TemplateHelpers.GetViewNames(metadata, "UIHint", "DataType").ToList();
  379. // Assert
  380. Assert.Equal(5, result.Count);
  381. Assert.Equal("UIHint", result[0]);
  382. Assert.Equal("DataType", result[1]);
  383. Assert.Equal("IList`1", result[2]);
  384. Assert.Equal("Collection", result[3]);
  385. Assert.Equal("Object", result[4]);
  386. }
  387. [Fact]
  388. public void GetViewNamesNullUIHintNotIncludedInList()
  389. {
  390. // Arrange
  391. ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(Object));
  392. // Act
  393. List<string> result = TemplateHelpers.GetViewNames(metadata, null, "DataType").ToList();
  394. // Assert
  395. Assert.Equal(2, result.Count);
  396. Assert.Equal("DataType", result[0]);
  397. Assert.Equal("Object", result[1]);
  398. }
  399. [Fact]
  400. public void GetViewNamesNullDataTypeNotIncludedInList()
  401. {
  402. // Arrange
  403. ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(Object));
  404. // Act
  405. List<string> result = TemplateHelpers.GetViewNames(metadata, "UIHint", null).ToList();
  406. // Assert
  407. Assert.Equal(2, result.Count);
  408. Assert.Equal("UIHint", result[0]);
  409. Assert.Equal("Object", result[1]);
  410. }
  411. [Fact]
  412. public void GetViewNamesConvertsNullableOfTIntoT()
  413. {
  414. // Arrange
  415. ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(Nullable<int>));
  416. // Act
  417. List<string> result = TemplateHelpers.GetViewNames(metadata, null, null).ToList();
  418. // Assert
  419. Assert.Equal(2, result.Count);
  420. Assert.Equal("Int32", result[0]);
  421. Assert.Equal("String", result[1]);
  422. }
  423. // Template
  424. private class TemplateModel
  425. {
  426. public object MyProperty { get; set; }
  427. }
  428. [Fact]
  429. public void TemplateNullExpressionThrows()
  430. {
  431. // Arrange
  432. HtmlHelper<object> html = MakeHtmlHelper<object>(null);
  433. // Act & Assert
  434. Assert.ThrowsArgumentNull(
  435. () => TemplateHelpers.Template(html, null, "templateName", "htmlFieldName", DataBoundControlMode.ReadOnly,
  436. null /* additionalViewData */, TemplateHelperSpy),
  437. "expression");
  438. }
  439. [Fact]
  440. public void TemplateDataNotFound()
  441. {
  442. // Arrange
  443. HtmlHelper<object> html = MakeHtmlHelper<object>(null);
  444. // Act
  445. string result = TemplateHelpers.Template(html, "UnknownObject", "templateName", null, DataBoundControlMode.ReadOnly,
  446. null /* additionalViewData */, TemplateHelperSpy);
  447. // Assert
  448. Assert.Equal("Model = (null), ModelType = System.String, RealModelType = System.String, PropertyName = (null), HtmlFieldName = UnknownObject, TemplateName = templateName, Mode = ReadOnly, AdditionalViewData = (null)", result);
  449. }
  450. [Fact]
  451. public void TemplateHtmlFieldNameReplacesExpression()
  452. {
  453. // Arrange
  454. HtmlHelper<object> html = MakeHtmlHelper<object>(null);
  455. // Act
  456. string result = TemplateHelpers.Template(html, "UnknownObject", "templateName", "htmlFieldName", DataBoundControlMode.ReadOnly,
  457. new { foo = "Bar" }, TemplateHelperSpy);
  458. // Assert
  459. Assert.Equal("Model = (null), ModelType = System.String, RealModelType = System.String, PropertyName = (null), HtmlFieldName = htmlFieldName, TemplateName = templateName, Mode = ReadOnly, AdditionalViewData = { foo: Bar }", result);
  460. }
  461. [Fact]
  462. public void TemplateDataFoundInViewDataDictionaryHasNoPropertyName()
  463. {
  464. // Arrange
  465. HtmlHelper<object> html = MakeHtmlHelper<object>(null);
  466. html.ViewContext.ViewData["Key"] = 42;
  467. // Act
  468. string result = TemplateHelpers.Template(html, "Key", null, null, DataBoundControlMode.Edit, null /* additionalViewData */, TemplateHelperSpy);
  469. // Assert
  470. Assert.Equal("Model = 42, ModelType = System.Int32, RealModelType = System.Int32, PropertyName = (null), HtmlFieldName = Key, TemplateName = (null), Mode = Edit, AdditionalViewData = (null)", result);
  471. }
  472. [Fact]
  473. public void TemplateDataFoundInViewDataDictionarySubPropertyHasPropertyName()
  474. {
  475. // Arrange
  476. HtmlHelper<object> html = MakeHtmlHelper<object>(null);
  477. html.ViewContext.ViewData["Key"] = new TemplateModel { MyProperty = "Hello!" };
  478. // Act
  479. string result = TemplateHelpers.Template(html, "Key.MyProperty", null, null, DataBoundControlMode.ReadOnly,
  480. null /* additionalViewData */, TemplateHelperSpy);
  481. // Assert
  482. Assert.Equal("Model = Hello!, ModelType = System.Object, RealModelType = System.String, PropertyName = MyProperty, HtmlFieldName = Key.MyProperty, TemplateName = (null), Mode = ReadOnly, AdditionalViewData = (null)", result);
  483. }
  484. [Fact]
  485. public void TemplateDataFoundInModelHasPropertyName()
  486. {
  487. // Arrange
  488. HtmlHelper<TemplateModel> html = MakeHtmlHelper<TemplateModel>(new TemplateModel { MyProperty = "Hello!" });
  489. // Act
  490. string result = TemplateHelpers.Template(html, "MyProperty", null, null, DataBoundControlMode.ReadOnly,
  491. null /* additionalViewData */, TemplateHelperSpy);
  492. // Assert
  493. Assert.Equal("Model = Hello!, ModelType = System.Object, RealModelType = System.String, PropertyName = MyProperty, HtmlFieldName = MyProperty, TemplateName = (null), Mode = ReadOnly, AdditionalViewData = (null)", result);
  494. }
  495. [Fact]
  496. public void TemplateNullDataFoundInModelHasPropertyTypeInsteadOfActualModelType()
  497. {
  498. // Arrange
  499. HtmlHelper<TemplateModel> html = MakeHtmlHelper<TemplateModel>(new TemplateModel());
  500. // Act
  501. string result = TemplateHelpers.Template(html, "MyProperty", null, null, DataBoundControlMode.ReadOnly,
  502. null /* additionalViewData */, TemplateHelperSpy);
  503. // Assert
  504. Assert.Equal("Model = (null), ModelType = System.Object, RealModelType = System.Object, PropertyName = MyProperty, HtmlFieldName = MyProperty, TemplateName = (null), Mode = ReadOnly, AdditionalViewData = (null)", result);
  505. }
  506. // TemplateFor
  507. private class TemplateForModel
  508. {
  509. public int MyField = 0;
  510. public object MyProperty { get; set; }
  511. public Nullable<int> MyNullableProperty { get; set; }
  512. }
  513. [Fact]
  514. public void TemplateForNonUnsupportedExpressionTypeThrows()
  515. {
  516. // Arrange
  517. HtmlHelper<TemplateForModel> html = MakeHtmlHelper<TemplateForModel>(null);
  518. // Act & Assert
  519. Assert.Throws<InvalidOperationException>(
  520. () => TemplateHelpers.TemplateFor(html, model => new Object(), "templateName", "htmlFieldName", DataBoundControlMode.ReadOnly,
  521. null /* additionalViewData */, TemplateHelperSpy),
  522. "Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.");
  523. }
  524. [Fact]
  525. public void TemplateForWithNonNullExpression()
  526. {
  527. // Arrange
  528. HtmlHelper<TemplateForModel> html = MakeHtmlHelper(new TemplateForModel { MyProperty = "Hello!" });
  529. // Act
  530. string result = TemplateHelpers.TemplateFor(html, model => model.MyProperty, "templateName", null, DataBoundControlMode.ReadOnly,
  531. new { foo = "Bar" }, TemplateHelperSpy);
  532. // Assert
  533. Assert.Equal("Model = Hello!, ModelType = System.Object, RealModelType = System.String, PropertyName = MyProperty, HtmlFieldName = MyProperty, TemplateName = templateName, Mode = ReadOnly, AdditionalViewData = { foo: Bar }", result);
  534. }
  535. [Fact]
  536. public void TemplateForHtmlFieldNameReplacesExpression()
  537. {
  538. // Arrange
  539. HtmlHelper<TemplateForModel> html = MakeHtmlHelper(new TemplateForModel { MyProperty = "Hello!" });
  540. // Act
  541. string result = TemplateHelpers.TemplateFor(html, model => model.MyProperty, "templateName", "htmlFieldName",
  542. DataBoundControlMode.ReadOnly, null /* additionalViewData */, TemplateHelperSpy);
  543. // Assert
  544. Assert.Equal("Model = Hello!, ModelType = System.Object, RealModelType = System.String, PropertyName = MyProperty, HtmlFieldName = htmlFieldName, TemplateName = templateName, Mode = ReadOnly, AdditionalViewData = (null)", result);
  545. }
  546. [Fact]
  547. public void TemplateForNullModelStillRetainsTypeInformation()
  548. {
  549. // Arrange
  550. HtmlHelper<TemplateForModel> html = MakeHtmlHelper<TemplateForModel>(null);
  551. // Act
  552. string result = TemplateHelpers.TemplateFor(html, model => model.MyProperty, null, null, DataBoundControlMode.ReadOnly,
  553. null /* additionalViewData */, TemplateHelperSpy);
  554. // Assert
  555. Assert.Equal("Model = (null), ModelType = System.Object, RealModelType = System.Object, PropertyName = MyProperty, HtmlFieldName = MyProperty, TemplateName = (null), Mode = ReadOnly, AdditionalViewData = (null)", result);
  556. }
  557. [Fact]
  558. public void TemplateForNullPropertyStillRetainsTypeInformation()
  559. {
  560. // Arrange
  561. HtmlHelper<TemplateForModel> html = MakeHtmlHelper(new TemplateForModel());
  562. // Act
  563. string result = TemplateHelpers.TemplateFor(html, model => model.MyProperty, null, null, DataBoundControlMode.ReadOnly,
  564. null /* additionalViewData */, TemplateHelperSpy);
  565. // Assert
  566. Assert.Equal("Model = (null), ModelType = System.Object, RealModelType = System.Object, PropertyName = MyProperty, HtmlFieldName = MyProperty, TemplateName = (null), Mode = ReadOnly, AdditionalViewData = (null)", result);
  567. }
  568. [Fact]
  569. public void TemplateForNullableValueTYpePropertyRetainsNullableValueTYpeForNullPropertyValue()
  570. {
  571. // Arrange
  572. HtmlHelper<TemplateForModel> html = MakeHtmlHelper(new TemplateForModel());
  573. // Act
  574. string result = TemplateHelpers.TemplateFor(html, model => model.MyNullableProperty, null, null, DataBoundControlMode.ReadOnly,
  575. null /* additionalViewData */, TemplateHelperSpy);
  576. // Assert
  577. Assert.Equal("Model = (null), ModelType = System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], RealModelType = System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], PropertyName = MyNullableProperty, HtmlFieldName = MyNullableProperty, TemplateName = (null), Mode = ReadOnly, AdditionalViewData = (null)", result);
  578. }
  579. [Fact]
  580. public void TemplateForNullableValueTypePropertyRetainsNullableValueTypeForNonNullPropertyValue()
  581. {
  582. // Arrange
  583. HtmlHelper<TemplateForModel> html = MakeHtmlHelper(new TemplateForModel { MyNullableProperty = 42 });
  584. // Act
  585. string result = TemplateHelpers.TemplateFor(html, model => model.MyNullableProperty, null, null, DataBoundControlMode.ReadOnly,
  586. null /* additionalViewData */, TemplateHelperSpy);
  587. // Assert
  588. Assert.Equal("Model = 42, ModelType = System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], RealModelType = System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], PropertyName = MyNullableProperty, HtmlFieldName = MyNullableProperty, TemplateName = (null), Mode = ReadOnly, AdditionalViewData = (null)", result);
  589. }
  590. [Fact]
  591. public void TemplateForWithParameterExpression()
  592. {
  593. // Arrange
  594. HtmlHelper<TemplateForModel> html = MakeHtmlHelper(new TemplateForModel());
  595. // Act
  596. string result = TemplateHelpers.TemplateFor(html, model => model, null, null, DataBoundControlMode.ReadOnly,
  597. null /* additionalViewData */, TemplateHelperSpy);
  598. // Assert
  599. Assert.Equal("Model = System.Web.Mvc.Html.Test.TemplateHelpersTest+TemplateForModel, ModelType = System.Web.Mvc.Html.Test.TemplateHelpersTest+TemplateForModel, RealModelType = System.Web.Mvc.Html.Test.TemplateHelpersTest+TemplateForModel, PropertyName = (null), HtmlFieldName = (empty), TemplateName = (null), Mode = ReadOnly, AdditionalViewData = (null)", result);
  600. }
  601. [Fact]
  602. public void TemplateForWithFieldExpression()
  603. {
  604. // Arrange
  605. HtmlHelper<TemplateForModel> html = MakeHtmlHelper(new TemplateForModel { MyField = 42 });
  606. // Act
  607. string result = TemplateHelpers.TemplateFor(html, model => model.MyField, null, null, DataBoundControlMode.ReadOnly,
  608. null /* additionalViewData */, TemplateHelperSpy);
  609. // Assert
  610. Assert.Equal("Model = 42, ModelType = System.Int32, RealModelType = System.Int32, PropertyName = (null), HtmlFieldName = MyField, TemplateName = (null), Mode = ReadOnly, AdditionalViewData = (null)", result);
  611. }
  612. // TemplateHelper
  613. private class TemplateHelperModel
  614. {
  615. public string MyProperty { get; set; }
  616. }
  617. [Fact]
  618. public void TemplateHelperNonNullNonEmptyStringModel()
  619. {
  620. // Arrange
  621. HtmlHelper html = MakeHtmlHelper(new TemplateHelperModel { MyProperty = "Hello" });
  622. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  623. // Act
  624. string result = TemplateHelpers.TemplateHelper(html, metadata, "htmlFieldName", "templateName", DataBoundControlMode.ReadOnly,
  625. null /* additionalViewData */, ExecuteTemplateSpy);
  626. // Assert
  627. Assert.Equal("Model = Hello, ModelType = System.String, RealModelType = System.String, PropertyName = MyProperty, FormattedModelValue = Hello, HtmlFieldPrefix = FieldPrefix.htmlFieldName, TemplateName = templateName, Mode = ReadOnly", result);
  628. }
  629. [Fact]
  630. public void TemplateHelperEmptyStringModel()
  631. {
  632. // Arrange
  633. HtmlHelper html = MakeHtmlHelper(new TemplateHelperModel { MyProperty = "" });
  634. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  635. metadata.ConvertEmptyStringToNull = false;
  636. // Act
  637. string result = TemplateHelpers.TemplateHelper(html, metadata, "htmlFieldName", "templateName", DataBoundControlMode.ReadOnly,
  638. null /* additionalViewData */, ExecuteTemplateSpy);
  639. // Assert
  640. Assert.Equal("Model = , ModelType = System.String, RealModelType = System.String, PropertyName = MyProperty, FormattedModelValue = , HtmlFieldPrefix = FieldPrefix.htmlFieldName, TemplateName = templateName, Mode = ReadOnly", result);
  641. }
  642. [Fact]
  643. public void TemplateHelperConvertsEmptyStringsToNull()
  644. {
  645. // Arrange
  646. HtmlHelper html = MakeHtmlHelper(new TemplateHelperModel { MyProperty = "" });
  647. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  648. metadata.ConvertEmptyStringToNull = true;
  649. // Act
  650. string result = TemplateHelpers.TemplateHelper(html, metadata, "htmlFieldName", "templateName", DataBoundControlMode.ReadOnly,
  651. null /* additionalViewData */, ExecuteTemplateSpy);
  652. // Assert
  653. Assert.Equal("Model = (null), ModelType = System.String, RealModelType = System.String, PropertyName = MyProperty, FormattedModelValue = , HtmlFieldPrefix = FieldPrefix.htmlFieldName, TemplateName = templateName, Mode = ReadOnly", result);
  654. }
  655. [Fact]
  656. public void TemplateHelperConvertsNullModelsToNullDisplayTextInReadOnlyMode()
  657. {
  658. // Arrange
  659. HtmlHelper html = MakeHtmlHelper(new TemplateHelperModel());
  660. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  661. metadata.NullDisplayText = "NullDisplayText";
  662. // Act
  663. string result = TemplateHelpers.TemplateHelper(html, metadata, "htmlFieldName", "templateName", DataBoundControlMode.ReadOnly,
  664. null /* additionalViewData */, ExecuteTemplateSpy);
  665. // Assert
  666. Assert.Equal("Model = (null), ModelType = System.String, RealModelType = System.String, PropertyName = MyProperty, FormattedModelValue = NullDisplayText, HtmlFieldPrefix = FieldPrefix.htmlFieldName, TemplateName = templateName, Mode = ReadOnly", result);
  667. }
  668. [Fact]
  669. public void TemplateHelperDoesNotConvertNullModelsToNullDisplayTextInEditMode()
  670. {
  671. // Arrange
  672. HtmlHelper html = MakeHtmlHelper(new TemplateHelperModel());
  673. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  674. metadata.NullDisplayText = "NullDisplayText";
  675. // Act
  676. string result = TemplateHelpers.TemplateHelper(html, metadata, "htmlFieldName", "templateName", DataBoundControlMode.Edit,
  677. null /* additionalViewData */, ExecuteTemplateSpy);
  678. // Assert
  679. Assert.Equal("Model = (null), ModelType = System.String, RealModelType = System.String, PropertyName = MyProperty, FormattedModelValue = , HtmlFieldPrefix = FieldPrefix.htmlFieldName, TemplateName = templateName, Mode = Edit", result);
  680. }
  681. [Fact]
  682. public void TemplateHelperAppliesDisplayFormatStringInReadOnlyMode()
  683. {
  684. // Arrange
  685. HtmlHelper html = MakeHtmlHelper(new TemplateHelperModel { MyProperty = "Hello" });
  686. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  687. metadata.DisplayFormatString = "{0} world!";
  688. // Act
  689. string result = TemplateHelpers.TemplateHelper(html, metadata, "htmlFieldName", "templateName", DataBoundControlMode.ReadOnly,
  690. null /* additionalViewData */, ExecuteTemplateSpy);
  691. // Assert
  692. Assert.Equal("Model = Hello, ModelType = System.String, RealModelType = System.String, PropertyName = MyProperty, FormattedModelValue = Hello world!, HtmlFieldPrefix = FieldPrefix.htmlFieldName, TemplateName = templateName, Mode = ReadOnly", result);
  693. }
  694. [Fact]
  695. public void TemplateHelperDoesNotApplyDisplayFormatStringInReadOnlyModeForNullModel()
  696. {
  697. // Arrange
  698. HtmlHelper html = MakeHtmlHelper(new TemplateHelperModel());
  699. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  700. metadata.DisplayFormatString = "{0} world!";
  701. // Act
  702. string result = TemplateHelpers.TemplateHelper(html, metadata, "htmlFieldName", "templateName", DataBoundControlMode.ReadOnly,
  703. null /* additionalViewData */, ExecuteTemplateSpy);
  704. // Assert
  705. Assert.Equal("Model = (null), ModelType = System.String, RealModelType = System.String, PropertyName = MyProperty, FormattedModelValue = , HtmlFieldPrefix = FieldPrefix.htmlFieldName, TemplateName = templateName, Mode = ReadOnly", result);
  706. }
  707. [Fact]
  708. public void TemplateHelperAppliesEditFormatStringInEditMode()
  709. {
  710. HtmlHelper html = MakeHtmlHelper(new TemplateHelperModel { MyProperty = "Hello" });
  711. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  712. metadata.EditFormatString = "{0} world!";
  713. // Act
  714. string result = TemplateHelpers.TemplateHelper(html, metadata, "htmlFieldName", "templateName", DataBoundControlMode.Edit,
  715. null /* additionalViewData */, ExecuteTemplateSpy);
  716. // Assert
  717. Assert.Equal("Model = Hello, ModelType = System.String, RealModelType = System.String, PropertyName = MyProperty, FormattedModelValue = Hello world!, HtmlFieldPrefix = FieldPrefix.htmlFieldName, TemplateName = templateName, Mode = Edit", result);
  718. }
  719. [Fact]
  720. public void TemplateHelperDoesNotApplyEditFormatStringInEditModeForNullModel()
  721. {
  722. // Arrange
  723. HtmlHelper html = MakeHtmlHelper(new TemplateHelperModel());
  724. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  725. metadata.EditFormatString = "{0} world!";
  726. // Act
  727. string result = TemplateHelpers.TemplateHelper(html, metadata, "htmlFieldName", "templateName", DataBoundControlMode.Edit,
  728. null /* additionalViewData */, ExecuteTemplateSpy);
  729. // Assert
  730. Assert.Equal("Model = (null), ModelType = System.String, RealModelType = System.String, PropertyName = MyProperty, FormattedModelValue = , HtmlFieldPrefix = FieldPrefix.htmlFieldName, TemplateName = templateName, Mode = Edit", result);
  731. }
  732. [Fact]
  733. public void TemplateHelperAddsNonNullModelToVisitedObjects()
  734. { // DDB #224750
  735. HtmlHelper html = MakeHtmlHelper(new TemplateHelperModel { MyProperty = "Hello" });
  736. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  737. ViewDataDictionary viewData = null;
  738. // Act
  739. TemplateHelpers.TemplateHelper(
  740. html, metadata, "htmlFieldName", "templateName", DataBoundControlMode.ReadOnly, null /* additionalViewData */,
  741. (_html, _viewData, _templateName, _mode, _getViews, _getDefaultActions) =>
  742. {
  743. viewData = _viewData;
  744. return String.Empty;
  745. });
  746. // Assert
  747. Assert.NotNull(viewData);
  748. Assert.True(viewData.TemplateInfo.VisitedObjects.Contains("Hello"));
  749. }
  750. [Fact]
  751. public void TemplateHelperAddsNullModelsTypeToVisitedObjects()
  752. { // DDB #224750
  753. HtmlHelper html = MakeHtmlHelper(new TemplateHelperModel());
  754. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  755. ViewDataDictionary viewData = null;
  756. // Act
  757. TemplateHelpers.TemplateHelper(
  758. html, metadata, "htmlFieldName", "templateName", DataBoundControlMode.ReadOnly, null /* additionalViewData */,
  759. (_html, _viewData, _templateName, _mode, _getViews, _getDefaultActions) =>
  760. {
  761. viewData = _viewData;
  762. return String.Empty;
  763. });
  764. // Assert
  765. Assert.NotNull(viewData);
  766. Assert.True(viewData.TemplateInfo.VisitedObjects.Contains(typeof(string)));
  767. }
  768. [Fact]
  769. public void TemplateHelperReturnsEmptyStringForAlreadyVisitedObject()
  770. { // DDB #224750
  771. HtmlHelper html = MakeHtmlHelper(new TemplateHelperModel { MyProperty = "Hello" });
  772. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  773. html.ViewData.TemplateInfo.VisitedObjects.Add("Hello");
  774. // Act
  775. string result = TemplateHelpers.TemplateHelper(html, metadata, "htmlFieldName", "templateName", DataBoundControlMode.ReadOnly,
  776. null /* additionalViewData */);
  777. // Assert
  778. Assert.Equal(String.Empty, result);
  779. }
  780. [Fact]
  781. public void TemplateHelperReturnsEmptyStringForAlreadyVisitedType()
  782. { // DDB #224750
  783. HtmlHelper html = MakeHtmlHelper(new TemplateHelperModel());
  784. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  785. html.ViewData.TemplateInfo.VisitedObjects.Add(typeof(string));
  786. // Act
  787. string result = TemplateHelpers.TemplateHelper(html, metadata, "htmlFieldName", "templateName", DataBoundControlMode.ReadOnly,
  788. null /* additionalViewData */);
  789. // Assert
  790. Assert.Equal(String.Empty, result);
  791. }
  792. [Fact]
  793. public void TemplateHelperPreservesSameInstanceOfModelMetadata()
  794. { // DDB #225858
  795. HtmlHelper html = MakeHtmlHelper(new TemplateHelperModel());
  796. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  797. ViewDataDictionary callbackViewData = null;
  798. // Act
  799. string result = TemplateHelpers.TemplateHelper(html, metadata, "htmlFieldName", "templateName", DataBoundControlMode.ReadOnly,
  800. null /* additionalViewData */,
  801. (_html, _viewData, _templateName, _mode, _getViewNames, _getDefaultActions) =>
  802. {
  803. callbackViewData = _viewData;
  804. return String.Empty;
  805. });
  806. // Assert
  807. Assert.NotNull(callbackViewData);
  808. Assert.Same(metadata, callbackViewData.ModelMetadata);
  809. }
  810. [Fact]
  811. public void TemplateHelperFormatsValuesUsingCurrentCulture()
  812. {
  813. CultureInfo existingCulture = Thread.CurrentThread.CurrentCulture;
  814. try
  815. {
  816. // Arrange
  817. Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("es-PR");
  818. HtmlHelper html = MakeHtmlHelper(new { MyProperty = new DateTime(2009, 11, 18, 16, 12, 8, DateTimeKind.Utc) });
  819. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  820. metadata.DisplayFormatString = "{0:F}";
  821. // Act
  822. string result = TemplateHelpers.TemplateHelper(html, metadata, "htmlFieldName", "templateName", DataBoundControlMode.ReadOnly,
  823. null /* additionalViewData */, ExecuteTemplateSpy);
  824. // Assert
  825. Assert.Equal("Model = 18/11/2009 04:12:08 p.m., ModelType = System.DateTime, RealModelType = System.DateTime, PropertyName = MyProperty, FormattedModelValue = miƩrcoles, 18 de noviembre de 2009 04:12:08 p.m., HtmlFieldPrefix = FieldPrefix.htmlFieldName, TemplateName = templateName, Mode = ReadOnly", result);
  826. }
  827. finally
  828. {
  829. Thread.CurrentThread.CurrentCulture = existingCulture;
  830. }
  831. }
  832. [Fact]
  833. public void TemplateHelperPreservesExistingViewData()
  834. {
  835. HtmlHelper html = MakeHtmlHelper(new TemplateHelperModel());
  836. html.ViewData["Foo"] = "Bar";
  837. html.ViewData["Baz"] = 42;
  838. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  839. ViewDataDictionary callbackViewData = null;
  840. // Act
  841. string result = TemplateHelpers.TemplateHelper(html, metadata, "htmlFieldName", "templateName", DataBoundControlMode.ReadOnly,
  842. null /* additionalViewData */,
  843. (_html, _viewData, _templateName, _mode, _getViewNames, _getDefaultActions) =>
  844. {
  845. callbackViewData = _viewData;
  846. return String.Empty;
  847. });
  848. // Assert
  849. Assert.NotSame(html.ViewData, callbackViewData);
  850. Assert.Equal(2, callbackViewData.Count);
  851. Assert.Equal("Bar", callbackViewData["Foo"]);
  852. Assert.Equal(42, callbackViewData["Baz"]);
  853. }
  854. [Fact]
  855. public void TemplateHelperMergesAdditionalViewData()
  856. {
  857. HtmlHelper html = MakeHtmlHelper(new TemplateHelperModel());
  858. html.ViewData["Foo"] = "Bar";
  859. html.ViewData["Baz"] = 42;
  860. ModelMetadata metadata = ModelMetadata.FromStringExpression("MyProperty", html.ViewData);
  861. ViewDataDictionary callbackViewData = null;
  862. // Act
  863. string result = TemplateHelpers.TemplateHelper(html, metadata, "htmlFieldName", "templateName", DataBoundControlMode.ReadOnly,
  864. new { foo = "New Foo", hello = "World!" },
  865. (_html, _viewData, _templateName, _mode, _getViewNames, _getDefaultActions) =>
  866. {
  867. callbackViewData = _viewData;
  868. return String.Empty;
  869. });
  870. // Assert
  871. Assert.NotSame(h