diff --git a/Mvc.sln b/Mvc.sln
index 8ecd806165..9bd980f531 100644
--- a/Mvc.sln
+++ b/Mvc.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
-VisualStudioVersion = 14.0.22115.0
+VisualStudioVersion = 14.0.22209.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}"
EndProject
@@ -102,6 +102,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "TagHelperSample.Web", "samp
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.TagHelpers", "src\Microsoft.AspNet.Mvc.TagHelpers\Microsoft.AspNet.Mvc.TagHelpers.kproj", "{B2347320-308E-4D2B-AEC8-005DFA68B0C9}"
EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.TagHelpers.Test", "test\Microsoft.AspNet.Mvc.TagHelpers.Test\Microsoft.AspNet.Mvc.TagHelpers.Test.kproj", "{860119ED-3DB1-424D-8D0A-30132A8A7D96}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -542,6 +544,16 @@ Global
{B2347320-308E-4D2B-AEC8-005DFA68B0C9}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{B2347320-308E-4D2B-AEC8-005DFA68B0C9}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{B2347320-308E-4D2B-AEC8-005DFA68B0C9}.Release|x86.ActiveCfg = Release|Any CPU
+ {860119ED-3DB1-424D-8D0A-30132A8A7D96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {860119ED-3DB1-424D-8D0A-30132A8A7D96}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {860119ED-3DB1-424D-8D0A-30132A8A7D96}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {860119ED-3DB1-424D-8D0A-30132A8A7D96}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {860119ED-3DB1-424D-8D0A-30132A8A7D96}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {860119ED-3DB1-424D-8D0A-30132A8A7D96}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {860119ED-3DB1-424D-8D0A-30132A8A7D96}.Release|Any CPU.Build.0 = Release|Any CPU
+ {860119ED-3DB1-424D-8D0A-30132A8A7D96}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {860119ED-3DB1-424D-8D0A-30132A8A7D96}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {860119ED-3DB1-424D-8D0A-30132A8A7D96}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -591,5 +603,6 @@ Global
{5DE8E4D9-AACD-4B5F-819F-F091383FB996} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{2223120F-D675-40DA-8CD8-11DC14A0B2C7} = {DAAE4C74-D06F-4874-A166-33305D2643CE}
{B2347320-308E-4D2B-AEC8-005DFA68B0C9} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
+ {860119ED-3DB1-424D-8D0A-30132A8A7D96} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
EndGlobalSection
EndGlobal
diff --git a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/Microsoft.AspNet.Mvc.TagHelpers.Test.kproj b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/Microsoft.AspNet.Mvc.TagHelpers.Test.kproj
new file mode 100644
index 0000000000..7321c7f047
--- /dev/null
+++ b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/Microsoft.AspNet.Mvc.TagHelpers.Test.kproj
@@ -0,0 +1,18 @@
+
+
+
+ 14.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+
+
+ 860119ed-3db1-424d-8d0a-30132a8a7d96
+ Microsoft.AspNet.Mvc.TagHelpers.Test
+
+
+
+ 2.0
+
+
+
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/TestableHtmlGenerator.cs b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/TestableHtmlGenerator.cs
new file mode 100644
index 0000000000..457e01716e
--- /dev/null
+++ b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/TestableHtmlGenerator.cs
@@ -0,0 +1,110 @@
+// Copyright (c) Microsoft Open Technologies, Inc. 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.Collections.Generic;
+using System.IO;
+using Microsoft.AspNet.Http;
+using Microsoft.AspNet.Mvc.ModelBinding;
+using Microsoft.AspNet.Mvc.Rendering;
+using Microsoft.AspNet.Routing;
+using Microsoft.AspNet.Security.DataProtection;
+using Microsoft.Framework.OptionsModel;
+using Moq;
+
+namespace Microsoft.AspNet.Mvc.TagHelpers
+{
+ public class TestableHtmlGenerator : DefaultHtmlGenerator
+ {
+ private IDictionary _validationAttributes;
+
+ public TestableHtmlGenerator(IModelMetadataProvider metadataProvider)
+ : this(metadataProvider, Mock.Of())
+ {
+ }
+
+ public TestableHtmlGenerator(IModelMetadataProvider metadataProvider, IUrlHelper urlHelper)
+ : this(
+ metadataProvider,
+ urlHelper,
+ validationAttributes: new Dictionary(StringComparer.OrdinalIgnoreCase))
+ {
+ }
+
+ public TestableHtmlGenerator(
+ IModelMetadataProvider metadataProvider,
+ IUrlHelper urlHelper,
+ IDictionary validationAttributes)
+ : base(Mock.Of(), GetAntiForgery(), metadataProvider, urlHelper)
+ {
+ _validationAttributes = validationAttributes;
+ }
+
+ public IDictionary ValidationAttributes
+ {
+ get { return _validationAttributes; }
+ }
+
+ public static ViewContext GetViewContext(
+ object model,
+ IHtmlGenerator htmlGenerator,
+ IModelMetadataProvider metadataProvider)
+ {
+ var serviceProvider = new Mock();
+ serviceProvider
+ .Setup(provider => provider.GetService(typeof(IHtmlGenerator)))
+ .Returns(htmlGenerator);
+
+ var httpContext = new Mock();
+ httpContext
+ .Setup(context => context.RequestServices)
+ .Returns(serviceProvider.Object);
+
+ var actionContext = new ActionContext(httpContext.Object, new RouteData(), new ActionDescriptor());
+ var viewData = new ViewDataDictionary(metadataProvider)
+ {
+ Model = model,
+ };
+ var viewContext = new ViewContext(actionContext, Mock.Of(), viewData, new StringWriter());
+
+ return viewContext;
+ }
+
+ public override TagBuilder GenerateAntiForgery(ViewContext viewContext)
+ {
+ return new TagBuilder("input")
+ {
+ Attributes =
+ {
+ { "name", "__RequestVerificationToken" },
+ { "type", "hidden" },
+ { "value", "olJlUDjrouRNWLen4tQJhauj1Z1rrvnb3QD65cmQU1Ykqi6S4" }, // 50 chars of a token.
+ },
+ };
+ }
+
+ protected override IDictionary GetValidationAttributes(
+ ViewContext viewContext,
+ ModelMetadata metadata,
+ string name)
+ {
+ return ValidationAttributes;
+ }
+
+ private static AntiForgery GetAntiForgery()
+ {
+ // AntiForgery must be passed to TestableHtmlGenerator constructor but will never be called.
+ var optionsAccessor = new Mock>();
+ optionsAccessor
+ .SetupGet(o => o.Options)
+ .Returns(new MvcOptions());
+ var antiForgery = new AntiForgery(
+ Mock.Of(),
+ Mock.Of(),
+ Mock.Of(),
+ optionsAccessor.Object);
+
+ return antiForgery;
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/TextAreaTagHelperTest.cs b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/TextAreaTagHelperTest.cs
new file mode 100644
index 0000000000..20faf2cca6
--- /dev/null
+++ b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/TextAreaTagHelperTest.cs
@@ -0,0 +1,194 @@
+// Copyright (c) Microsoft Open Technologies, Inc. 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.Collections.Generic;
+using System.Threading.Tasks;
+using Microsoft.AspNet.Mvc.ModelBinding;
+using Microsoft.AspNet.Mvc.Razor;
+using Microsoft.AspNet.Mvc.Rendering;
+using Microsoft.AspNet.Razor.Runtime.TagHelpers;
+using Xunit;
+
+namespace Microsoft.AspNet.Mvc.TagHelpers
+{
+ public class TextAreaTagHelperTest
+ {
+ // Model (List or Model instance), container type (Model or NestModel), model accessor,
+ // property path, expected content.
+ public static TheoryData