From dcee0d2ff718dace8087f07f15fa24c9db579131 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Thu, 23 Apr 2015 12:18:42 -0700 Subject: [PATCH] Add tests for ReadOnlyTagHelperAttributes and TagHelperAttributes. #279 --- ...CaseSensitiveTagHelperAttributeComparer.cs | 39 + .../ReadOnlyTagHelperAttributeListTest.cs | 702 ++++++++++++++++++ .../TagHelpers/TagHelperAttributeListTest.cs | 698 +++++++++++++++++ .../TagHelpers/TagHelperContextTest.cs | 3 +- .../TagHelperExecutionContextTest.cs | 24 +- .../TagHelpers/TagHelperOutputTest.cs | 10 +- .../TagHelpers/TagHelperRunnerTest.cs | 18 +- .../Framework/BlockTypes.cs | 38 +- .../TagHelperParseTreeRewriterTest.cs | 696 +++++++++-------- 9 files changed, 1862 insertions(+), 366 deletions(-) create mode 100644 test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/CaseSensitiveTagHelperAttributeComparer.cs create mode 100644 test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/ReadOnlyTagHelperAttributeListTest.cs create mode 100644 test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperAttributeListTest.cs diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/CaseSensitiveTagHelperAttributeComparer.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/CaseSensitiveTagHelperAttributeComparer.cs new file mode 100644 index 0000000000..b28aebf668 --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/CaseSensitiveTagHelperAttributeComparer.cs @@ -0,0 +1,39 @@ +// 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 Microsoft.Internal.Web.Utils; + +namespace Microsoft.AspNet.Razor.Runtime.TagHelpers +{ + public class CaseSensitiveTagHelperAttributeComparer : IEqualityComparer + { + public readonly static CaseSensitiveTagHelperAttributeComparer Default = + new CaseSensitiveTagHelperAttributeComparer(); + + private CaseSensitiveTagHelperAttributeComparer() + { + } + + public bool Equals( + [NotNull] IReadOnlyTagHelperAttribute attributeX, + [NotNull] IReadOnlyTagHelperAttribute attributeY) + { + return + attributeX == attributeY || + // Normal comparer doesn't care about the Name case, in tests we do. + string.Equals(attributeX.Name, attributeY.Name, StringComparison.Ordinal) && + Equals(attributeX.Value, attributeY.Value); + } + + public int GetHashCode([NotNull] IReadOnlyTagHelperAttribute attribute) + { + return HashCodeCombiner + .Start() + .Add(attribute.Name, StringComparer.Ordinal) + .Add(attribute.Value) + .CombinedHash; + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/ReadOnlyTagHelperAttributeListTest.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/ReadOnlyTagHelperAttributeListTest.cs new file mode 100644 index 0000000000..efca1327b1 --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/ReadOnlyTagHelperAttributeListTest.cs @@ -0,0 +1,702 @@ +// 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.Linq; +using Xunit; + +namespace Microsoft.AspNet.Razor.Runtime.TagHelpers +{ + public class ReadOnlyTagHelperAttributeListTest + { + public static TheoryData IntIndexerData + { + get + { + var first = new TagHelperAttribute("First", "First Value"); + var second = new TagHelperAttribute("Second", "Second Value"); + var third = new TagHelperAttribute("Third", "Third Value"); + + return new TheoryData< + IEnumerable, // initialAttributes + int, // indexToLookup + IReadOnlyTagHelperAttribute> // expectedAttribute + { + { new[] { first }, 0, first }, + { new[] { first, second }, 0, first }, + { new[] { first, second }, 1, second }, + { new[] { first, second, third}, 1, second }, + { new[] { first, second, third }, 2, third }, + { new[] { first, first, second, third}, 1, first }, + }; + } + } + + [Theory] + [MemberData(nameof(IntIndexerData))] + public void IntIndexer_ReturnsExpectedAttribute( + IEnumerable initialAttributes, + int indexToLookup, + IReadOnlyTagHelperAttribute expectedAttribute) + { + // Arrange + var attributes = new ReadOnlyTagHelperAttributeList(initialAttributes); + + // Act + var attribute = attributes[indexToLookup]; + + // Assert + Assert.Equal(expectedAttribute, attribute, CaseSensitiveTagHelperAttributeComparer.Default); + } + + public static TheoryData IntIndexerThrowData + { + get + { + return new TheoryData { 2, -1, 20 }; + } + } + + [Theory] + [MemberData(nameof(IntIndexerThrowData))] + public void IntIndexer_ThrowsIfInvalidIndex(int index) + { + // Arrange + var attributes = new ReadOnlyTagHelperAttributeList( + new[] + { + new TagHelperAttribute("a", "av"), + new TagHelperAttribute("b", "bv") + }); + + // Act & Assert + var exception = Assert.Throws("index", () => attributes[index]); + } + + public static TheoryData StringIndexerData + { + get + { + var A = new TagHelperAttribute("AName", "AName Value"); + var A2 = new TagHelperAttribute("aname", "AName Second Value"); + var A3 = new TagHelperAttribute("AName", "AName Third Value"); + var B = new TagHelperAttribute("BName", "BName Value"); + var C = new TagHelperAttribute("CName", "CName Value"); + + return new TheoryData< + IEnumerable, // initialAttributes + string, // nameToLookup + IReadOnlyTagHelperAttribute> // expectedAttribute + { + { new[] { A }, "AName", A }, + { new[] { A }, "AnAmE", A }, + { new[] { A, B }, "AName", A }, + { new[] { A, B }, "AnAmE", A }, + { new[] { A, B }, "BName", B }, + { new[] { A, B }, "BnAmE", B }, + { new[] { A, B, C }, "BName", B }, + { new[] { A, B, C }, "bname", B }, + { new[] { A, B, C }, "CName", C }, + { new[] { A, B, C }, "cnamE", C }, + + // Multiple elements same name + { new[] { A, B, A2, C }, "AName", A }, + { new[] { A, B, A2, C }, "aname", A }, + { new[] { B, A2, A }, "aname", A2 }, + { new[] { B, A2, A, C }, "AName", A2 }, + { new[] { A, A3 }, "AName", A }, + { new[] { A3, A }, "aname", A3 }, + { new[] { A, A2, A3 }, "AName", A }, + { new[] { C, B, A3, A }, "AName", A3 }, + + // Null expected lookups + { new[] { A }, "_AName_", null }, + { new[] { A }, "completely different", null }, + { new[] { A, B }, "_AName_", null }, + { new[] { A, B }, "completely different", null }, + { new[] { A, B, C }, "_BName_", null }, + { new[] { A, B, C }, "completely different", null }, + { new[] { A, A2, B, C }, "_cnamE_", null }, + { new[] { A, A2, B, C }, "completely different", null }, + { new[] { A, A2, A3, B, C }, "_cnamE_", null }, + { new[] { A, A2, A3, B, C }, "completely different", null }, + }; + } + } + + [Theory] + [MemberData(nameof(StringIndexerData))] + public void StringIndexer_ReturnsExpectedAttribute( + IEnumerable initialAttributes, + string nameToLookup, + IReadOnlyTagHelperAttribute expectedAttribute) + { + // Arrange + var attributes = new ReadOnlyTagHelperAttributeList(initialAttributes); + + // Act + var attribute = attributes[nameToLookup]; + + // Assert + Assert.Equal(expectedAttribute, attribute, CaseSensitiveTagHelperAttributeComparer.Default); + } + + [Fact] + public void Count_ReturnsNumberOfAttributes() + { + // Arrange + var attributes = new ReadOnlyTagHelperAttributeList( + new[] + { + new TagHelperAttribute(), + new TagHelperAttribute(), + new TagHelperAttribute() + }); + + // Act + var count = attributes.Count; + + // Assert + Assert.Equal(3, count); + } + + public static TheoryData ContainsData + { + get + { + var A = new TagHelperAttribute("AName", "AName Value"); + var A2 = new TagHelperAttribute("aname", "AName Second Value"); + var A3 = new TagHelperAttribute("AName", "AName Third Value"); + var B = new TagHelperAttribute("BName", "BName Value"); + var C = new TagHelperAttribute("CName", "CName Value"); + + return new TheoryData< + IEnumerable, // initialAttributes + IReadOnlyTagHelperAttribute, // attributeToLookup + bool> // expected + { + { new[] { A }, A, true }, + { new[] { A }, new TagHelperAttribute(A.Name, A.Value), true }, + { new[] { A }, new TagHelperAttribute("aname", A.Value), true }, + { new[] { A, B }, A, true }, + { new[] { A, B }, new TagHelperAttribute(A.Name, A.Value), true }, + { new[] { A, B }, new TagHelperAttribute("AnaMe", A.Value), true }, + { new[] { A, B }, B, true }, + { new[] { A, B }, new TagHelperAttribute(B.Name, B.Value), true }, + { new[] { A, B }, new TagHelperAttribute("BNAME", B.Value), true }, + { new[] { A, B, C }, B, true }, + { new[] { A, B, C }, new TagHelperAttribute(B.Name, B.Value), true }, + { new[] { A, B, C }, new TagHelperAttribute("bname", B.Value), true }, + { new[] { A, B, C }, C, true }, + { new[] { A, B, C }, new TagHelperAttribute(C.Name, C.Value), true }, + { new[] { A, B, C }, new TagHelperAttribute("CNAme", C.Value), true }, + { new[] { A }, B, false }, + { new[] { A }, new TagHelperAttribute(A.Name, "different value"), false }, + { new[] { A }, new TagHelperAttribute("aname_not", "different value"), false }, + { new[] { A, B }, A2, false }, + { new[] { A, B }, new TagHelperAttribute(A.Name, "different value"), false }, + { new[] { A, B }, new TagHelperAttribute("AnaMe_not", "different value"), false }, + { new[] { A, B }, new TagHelperAttribute(B.Name, "different value"), false }, + { new[] { A, B }, new TagHelperAttribute("BNAME_not", "different value"), false }, + { new[] { A, B, C }, A2, false }, + { new[] { A, B, C }, new TagHelperAttribute(B.Name, "different value"), false }, + { new[] { A, B, C }, new TagHelperAttribute("bname_not", "different value"), false }, + { new[] { A, B, C }, new TagHelperAttribute(C.Name, "different value"), false }, + { new[] { A, B, C }, new TagHelperAttribute("CNAme_not", "different value"), false }, + + // Multiple elements same name + { new[] { A, B, A2, C }, A, true }, + { new[] { A, B, A2, C }, new TagHelperAttribute(A.Name, A.Value), true }, + { new[] { A, B, A2, C }, new TagHelperAttribute("aname", A.Value), true }, + { new[] { B, A2, A }, A2, true }, + { new[] { B, A2, A }, new TagHelperAttribute(A.Name, A.Value), true }, + { new[] { B, A2, A }, new TagHelperAttribute("AnAME", A2.Value), true }, + { new[] { B, A2, A, C }, A, true }, + { new[] { B, A2, A, C }, new TagHelperAttribute(A.Name, A.Value), true }, + { new[] { B, A2, A, C }, new TagHelperAttribute("ANAME", A.Value), true }, + { new[] { A, A3 }, A, true }, + { new[] { A, A3 }, new TagHelperAttribute(A.Name, A.Value), true }, + { new[] { A, A3 }, new TagHelperAttribute("ANamE", A.Value), true }, + { new[] { A3, A }, A3, true }, + { new[] { A3, A }, new TagHelperAttribute(A3.Name, A3.Value), true }, + { new[] { A3, A }, new TagHelperAttribute("anamE", A3.Value), true }, + { new[] { A, A2, A3 }, A, true }, + { new[] { A, A2, A3 }, new TagHelperAttribute(A.Name, A.Value), true }, + { new[] { A, A2, A3 }, new TagHelperAttribute("ANAme", A.Value), true }, + { new[] { C, B, A3, A }, A3, true }, + { new[] { C, B, A3, A }, new TagHelperAttribute(A3.Name, A3.Value), true }, + { new[] { C, B, A3, A }, new TagHelperAttribute("aname", A3.Value), true }, + { new[] { A, B, A2, C }, A3, false }, + { new[] { A, B, A2, C }, new TagHelperAttribute(A.Name, A3.Value), false }, + { new[] { A, B, A2, C }, new TagHelperAttribute("aname_not", "different value"), false }, + { new[] { B, A2, A }, A3, false }, + { new[] { B, A2, A }, new TagHelperAttribute(A.Name, A3.Value), false }, + { new[] { B, A2, A }, new TagHelperAttribute("AnAME_not", "different value"), false }, + { new[] { B, A2, A, C }, A3, false }, + { new[] { B, A2, A, C }, new TagHelperAttribute(A.Name, A3.Value), false }, + { new[] { B, A2, A, C }, new TagHelperAttribute("ANAME_not", "different value"), false }, + { new[] { A, A3 }, B, false }, + { new[] { A, A3 }, new TagHelperAttribute(A.Name, A2.Value), false }, + { new[] { A, A3 }, new TagHelperAttribute("ANamE_not", "different value"), false }, + { new[] { A3, A }, B, false }, + { new[] { A3, A }, new TagHelperAttribute(A3.Name, A2.Value), false }, + { new[] { A3, A }, new TagHelperAttribute("anamE_not", "different value"), false }, + { new[] { A, A2, A3 }, B, false }, + { new[] { A, A2, A3 }, new TagHelperAttribute(A.Name, B.Value), false }, + { new[] { A, A2, A3 }, new TagHelperAttribute("ANAme_not", "different value"), false }, + { new[] { C, B, A3, A }, A2, false }, + { new[] { C, B, A3, A }, new TagHelperAttribute(A3.Name, A2.Value), false }, + { new[] { C, B, A3, A }, new TagHelperAttribute("aname_not", "different value"), false }, + }; + } + } + + [Theory] + [MemberData(nameof(ContainsData))] + public void Contains_ReturnsExpectedResult( + IEnumerable initialAttributes, + IReadOnlyTagHelperAttribute attributeToLookup, + bool expected) + { + // Arrange + var attributes = new ReadOnlyTagHelperAttributeList(initialAttributes); + + // Act + var contains = attributes.Contains(attributeToLookup); + + // Assert + Assert.Equal(expected, contains); + } + + public static TheoryData ContainsNameData + { + get + { + var A = new TagHelperAttribute("AName", "AName Value"); + var A2 = new TagHelperAttribute("aname", "AName Second Value"); + var A3 = new TagHelperAttribute("AName", "AName Third Value"); + var B = new TagHelperAttribute("BName", "BName Value"); + var C = new TagHelperAttribute("CName", "CName Value"); + + return new TheoryData< + IEnumerable, // initialAttributes + string, // nameToLookup + bool> // expected + { + { new[] { A }, A.Name, true }, + { new[] { A }, "aname", true }, + { new[] { A, B }, A.Name, true }, + { new[] { A, B }, "AnaMe", true }, + { new[] { A, B }, B.Name, true }, + { new[] { A, B }, "BNAME", true }, + { new[] { A, B, C }, B.Name, true }, + { new[] { A, B, C }, "bname", true }, + { new[] { A, B, C }, C.Name, true }, + { new[] { A, B, C }, "CNAme", true }, + { new[] { A }, B.Name, false }, + { new[] { A, B }, C.Name, false }, + { new[] { A, B, C }, "different", false }, + + // Multiple elements same name + { new[] { A, B, A2, C }, A.Name, true }, + { new[] { A, B, A2, C }, "aname", true }, + { new[] { B, A2, A }, A2.Name, true }, + { new[] { B, A2, A }, "AnAME", true }, + { new[] { B, A2, A, C }, A.Name, true }, + { new[] { B, A2, A, C }, "ANAME", true }, + { new[] { A, A3 }, A.Name, true }, + { new[] { A, A3 }, "ANamE", true }, + { new[] { A, A2, A3 }, A.Name, true }, + { new[] { A, A2, A3 }, "ANAme", true }, + { new[] { C, B, A3, A }, A3.Name, true }, + { new[] { C, B, A3, A }, "aname", true }, + { new[] { A, B, A2, C }, "aname_not", false }, + { new[] { B, A2, A }, C.Name, false }, + { new[] { B, A2, A }, "AnAME_not", false }, + { new[] { B, A2, A, C }, "different", false }, + { new[] { B, A2, A, C }, "ANAME_not", false }, + { new[] { A, A3 }, B.Name, false }, + { new[] { A, A3 }, "ANamE_not", false }, + { new[] { A3, A }, B.Name, false }, + { new[] { A3, A }, "anamE_not", false }, + { new[] { A, A2, A3 }, B.Name, false }, + { new[] { A, A2, A3 }, "ANAme_not", false }, + { new[] { C, B, A3, A }, "different", false }, + { new[] { C, B, A3, A }, "aname_not", false }, + }; + } + } + + [Theory] + [MemberData(nameof(ContainsNameData))] + public void ContainsName_ReturnsExpectedResult( + IEnumerable initialAttributes, + string nameToLookup, + bool expected) + { + // Arrange + var attributes = new ReadOnlyTagHelperAttributeList(initialAttributes); + + // Act + var contains = attributes.ContainsName(nameToLookup); + + // Assert + Assert.Equal(expected, contains); + } + + public static TheoryData IndexOfData + { + get + { + var A = new TagHelperAttribute("AName", "AName Value"); + var A2 = new TagHelperAttribute("aname", "AName Second Value"); + var A3 = new TagHelperAttribute("AName", "AName Third Value"); + var B = new TagHelperAttribute("BName", "BName Value"); + var C = new TagHelperAttribute("CName", "CName Value"); + + return new TheoryData< + IEnumerable, // initialAttributes + IReadOnlyTagHelperAttribute, // attributeToLookup + int> // expected + { + { new[] { A }, A, 0 }, + { new[] { A }, new TagHelperAttribute(A.Name, A.Value), 0 }, + { new[] { A }, new TagHelperAttribute("aname", A.Value), 0 }, + { new[] { A, B }, A, 0 }, + { new[] { A, B }, new TagHelperAttribute(A.Name, A.Value), 0 }, + { new[] { A, B }, new TagHelperAttribute("AnaMe", A.Value), 0 }, + { new[] { A, B }, B, 1 }, + { new[] { A, B }, new TagHelperAttribute(B.Name, B.Value), 1 }, + { new[] { A, B }, new TagHelperAttribute("BNAME", B.Value), 1 }, + { new[] { A, B, C }, B, 1 }, + { new[] { A, B, C }, new TagHelperAttribute(B.Name, B.Value), 1 }, + { new[] { A, B, C }, new TagHelperAttribute("bname", B.Value), 1 }, + { new[] { A, B, C }, C, 2 }, + { new[] { A, B, C }, new TagHelperAttribute(C.Name, C.Value), 2 }, + { new[] { A, B, C }, new TagHelperAttribute("CNAme", C.Value), 2 }, + { new[] { A }, B, -1 }, + { new[] { A }, new TagHelperAttribute(A.Name, "different value"), -1 }, + { new[] { A }, new TagHelperAttribute("aname_not", "different value"), -1 }, + { new[] { A, B }, A2, -1 }, + { new[] { A, B }, new TagHelperAttribute(A.Name, "different value"), -1 }, + { new[] { A, B }, new TagHelperAttribute("AnaMe_not", "different value"), -1 }, + { new[] { A, B }, new TagHelperAttribute(B.Name, "different value"), -1 }, + { new[] { A, B }, new TagHelperAttribute("BNAME_not", "different value"), -1 }, + { new[] { A, B, C }, A2, -1 }, + { new[] { A, B, C }, new TagHelperAttribute(B.Name, "different value"), -1 }, + { new[] { A, B, C }, new TagHelperAttribute("bname_not", "different value"), -1 }, + { new[] { A, B, C }, new TagHelperAttribute(C.Name, "different value"), -1 }, + { new[] { A, B, C }, new TagHelperAttribute("CNAme_not", "different value"), -1 }, + + // Multiple elements same name + { new[] { A, B, A2, C }, A, 0 }, + { new[] { A, B, A2, C }, new TagHelperAttribute(A.Name, A.Value), 0 }, + { new[] { A, B, A2, C }, new TagHelperAttribute("aname", A.Value), 0 }, + { new[] { B, A2, A }, A2, 1 }, + { new[] { B, A2, A }, new TagHelperAttribute(A.Name, A.Value), 2 }, + { new[] { B, A2, A }, new TagHelperAttribute("AnAME", A2.Value), 1 }, + { new[] { B, A2, A, C }, A, 2 }, + { new[] { B, A2, A, C }, new TagHelperAttribute(A.Name, A.Value), 2 }, + { new[] { B, A2, A, C }, new TagHelperAttribute("ANAME", A.Value), 2 }, + { new[] { A, A3 }, A, 0 }, + { new[] { A, A3 }, new TagHelperAttribute(A.Name, A.Value), 0 }, + { new[] { A, A3 }, new TagHelperAttribute("ANamE", A.Value), 0 }, + { new[] { A3, A }, A3, 0 }, + { new[] { A3, A }, new TagHelperAttribute(A3.Name, A3.Value), 0 }, + { new[] { A3, A }, new TagHelperAttribute("anamE", A3.Value), 0 }, + { new[] { A, A2, A3 }, A, 0 }, + { new[] { A, A2, A3 }, new TagHelperAttribute(A.Name, A.Value), 0 }, + { new[] { A, A2, A3 }, new TagHelperAttribute("ANAme", A.Value), 0 }, + { new[] { C, B, A3, A }, A3, 2 }, + { new[] { C, B, A3, A }, new TagHelperAttribute(A3.Name, A3.Value), 2 }, + { new[] { C, B, A3, A }, new TagHelperAttribute("aname", A3.Value), 2 }, + { new[] { A, B, A2, C }, A3, -1 }, + { new[] { A, B, A2, C }, new TagHelperAttribute(A.Name, A3.Value), -1 }, + { new[] { A, B, A2, C }, new TagHelperAttribute("aname_not", "different value"), -1 }, + { new[] { B, A2, A }, A3, -1 }, + { new[] { B, A2, A }, new TagHelperAttribute(A.Name, A3.Value), -1 }, + { new[] { B, A2, A }, new TagHelperAttribute("AnAME_not", "different value"), -1 }, + { new[] { B, A2, A, C }, A3, -1 }, + { new[] { B, A2, A, C }, new TagHelperAttribute(A.Name, A3.Value), -1 }, + { new[] { B, A2, A, C }, new TagHelperAttribute("ANAME_not", "different value"), -1 }, + { new[] { A, A3 }, B, -1 }, + { new[] { A, A3 }, new TagHelperAttribute(A.Name, A2.Value), -1 }, + { new[] { A, A3 }, new TagHelperAttribute("ANamE_not", "different value"), -1 }, + { new[] { A3, A }, B, -1 }, + { new[] { A3, A }, new TagHelperAttribute(A3.Name, A2.Value), -1 }, + { new[] { A3, A }, new TagHelperAttribute("anamE_not", "different value"), -1 }, + { new[] { A, A2, A3 }, B, -1 }, + { new[] { A, A2, A3 }, new TagHelperAttribute(A.Name, B.Value), -1 }, + { new[] { A, A2, A3 }, new TagHelperAttribute("ANAme_not", "different value"), -1 }, + { new[] { C, B, A3, A }, A2, -1 }, + { new[] { C, B, A3, A }, new TagHelperAttribute(A3.Name, A2.Value), -1 }, + { new[] { C, B, A3, A }, new TagHelperAttribute("aname_not", "different value"), -1 }, + }; + } + } + + [Theory] + [MemberData(nameof(IndexOfData))] + public void IndexOf_ReturnsExpectedResult( + IEnumerable initialAttributes, + IReadOnlyTagHelperAttribute attributeToLookup, + int expected) + { + // Arrange + var attributes = new ReadOnlyTagHelperAttributeList(initialAttributes); + + // Act + var index = attributes.IndexOf(attributeToLookup); + + // Assert + Assert.Equal(expected, index); + } + + public static TheoryData TryGetAttributeData + { + get + { + var A = new TagHelperAttribute("AName", "AName Value"); + var A2 = new TagHelperAttribute("aname", "AName Second Value"); + var A3 = new TagHelperAttribute("AName", "AName Third Value"); + var B = new TagHelperAttribute("BName", "BName Value"); + var C = new TagHelperAttribute("CName", "CName Value"); + + return new TheoryData< + IEnumerable, // initialAttributes + string, // nameToLookup + IReadOnlyTagHelperAttribute, // expectedAttribute + bool> // expectedResult + { + { new[] { A }, "AName", A, true }, + { new[] { A }, "AnAmE", A, true }, + { new[] { A, B }, "AName", A, true }, + { new[] { A, B }, "AnAmE", A, true }, + { new[] { A, B }, "BName", B, true }, + { new[] { A, B }, "BnAmE", B, true }, + { new[] { A, B, C }, "BName", B, true }, + { new[] { A, B, C }, "bname", B, true }, + { new[] { A, B, C }, "CName", C, true }, + { new[] { A, B, C }, "cnamE", C, true }, + + // Multiple elements same name + { new[] { A, B, A2, C }, "AName", A, true }, + { new[] { A, B, A2, C }, "aname", A, true }, + { new[] { B, A2, A }, "aname", A2, true }, + { new[] { B, A2, A, C }, "AName", A2, true }, + { new[] { A, A3 }, "AName", A, true }, + { new[] { A3, A }, "aname", A3, true }, + { new[] { A, A2, A3 }, "AName", A, true }, + { new[] { C, B, A3, A }, "AName", A3, true }, + + // Null expected lookups + { new[] { A }, "_AName_", null, false }, + { new[] { A }, "completely different", null, false }, + { new[] { A, B }, "_AName_", null, false }, + { new[] { A, B }, "completely different", null, false }, + { new[] { A, B, C }, "_BName_", null, false }, + { new[] { A, B, C }, "completely different", null, false }, + { new[] { A, A2, B, C }, "_cnamE_", null, false }, + { new[] { A, A2, B, C }, "completely different", null, false }, + { new[] { A, A2, A3, B, C }, "_cnamE_", null, false }, + { new[] { A, A2, A3, B, C }, "completely different", null, false }, + }; + } + } + + [Theory] + [MemberData(nameof(TryGetAttributeData))] + public void TryGetAttribute_ReturnsExpectedValueAndAttribute( + IEnumerable initialAttributes, + string nameToLookup, + IReadOnlyTagHelperAttribute expectedAttribute, + bool expectedResult) + { + // Arrange + var attributes = new ReadOnlyTagHelperAttributeList(initialAttributes); + IReadOnlyTagHelperAttribute attribute; + + // Act + var result = attributes.TryGetAttribute(nameToLookup, out attribute); + + // Assert + Assert.Equal(expectedResult, result); + Assert.Equal(expectedAttribute, attribute, CaseSensitiveTagHelperAttributeComparer.Default); + } + + public static TheoryData TryGetAttributesData + { + get + { + var A = new TagHelperAttribute("AName", "AName Value"); + var A2 = new TagHelperAttribute("aname", "AName Second Value"); + var A3 = new TagHelperAttribute("AName", "AName Third Value"); + var B = new TagHelperAttribute("BName", "BName Value"); + var C = new TagHelperAttribute("CName", "CName Value"); + + return new TheoryData< + IEnumerable, // initialAttributes + string, // nameToLookup + IEnumerable, // expectedAttributes + bool> // expectedResult + { + { new[] { A }, "AName", new[] { A }, true }, + { new[] { A }, "AnAmE", new[] { A }, true }, + { new[] { A, B }, "AName", new[] { A }, true }, + { new[] { A, B }, "AnAmE", new[] { A }, true }, + { new[] { A, B }, "BName", new[] { B }, true }, + { new[] { A, B }, "BnAmE", new[] { B }, true }, + { new[] { A, B, C }, "BName", new[] { B }, true }, + { new[] { A, B, C }, "bname", new[] { B }, true }, + { new[] { A, B, C }, "CName", new[] { C }, true }, + { new[] { A, B, C }, "cnamE", new[] { C }, true }, + + // Multiple elements same name + { new[] { A, B, A2, C }, "AName", new[] { A, A2 }, true }, + { new[] { A, B, A2, C }, "aname", new[] { A, A2 }, true }, + { new[] { B, A2, A }, "aname", new[] { A2, A }, true }, + { new[] { B, A2, A, C }, "AName", new[] { A2, A }, true }, + { new[] { A, A3 }, "AName", new[] { A, A3 }, true }, + { new[] { A3, A }, "aname", new[] { A3, A }, true }, + { new[] { A, A2, A3 }, "AName", new[] { A, A2, A3 }, true }, + { new[] { C, B, A3, A }, "AName", new[] { A3, A }, true }, + + // Null expected lookups + { new[] { A }, "_AName_", Enumerable.Empty(), false }, + { new[] { A }, "completely different", Enumerable.Empty(), false }, + { new[] { A, B }, "_AName_", Enumerable.Empty(), false }, + { new[] { A, B }, "completely different", Enumerable.Empty(), false }, + { new[] { A, B, C }, "_BName_", Enumerable.Empty(), false }, + { new[] { A, B, C }, "way different", Enumerable.Empty(), false }, + { new[] { A, A2, B, C }, "_cnamE_", Enumerable.Empty(), false }, + { new[] { A, A2, B, C }, "way different", Enumerable.Empty(), false }, + { new[] { A, A2, A3, B, C }, "_cnamE_", Enumerable.Empty(), false }, + { new[] { A, A2, A3, B, C }, "different", Enumerable.Empty(), false }, + }; + } + } + + [Theory] + [MemberData(nameof(TryGetAttributesData))] + public void TryGetAttributes_ReturnsExpectedValueAndAttribute( + IEnumerable initialAttributes, + string nameToLookup, + IEnumerable expectedAttributes, + bool expectedResult) + { + // Arrange + var attributes = new ReadOnlyTagHelperAttributeList(initialAttributes); + IEnumerable resolvedAttributes; + + // Act + var result = attributes.TryGetAttributes(nameToLookup, out resolvedAttributes); + + // Assert + Assert.Equal(expectedResult, result); + Assert.Equal(expectedAttributes, resolvedAttributes, CaseSensitiveTagHelperAttributeComparer.Default); + } + + [Fact] + public void Attributes_EqualsInitialAttributes() + { + // Arrange + var expectedAttributes = new[] + { + new TagHelperAttribute("A", "AV"), + new TagHelperAttribute("B", "BV") + }; + + // Act + var attributes = new TestableReadOnlyTagHelperAttributes(expectedAttributes); + + // Assert + Assert.Equal(expectedAttributes, attributes.PublicAttributes); + } + + [Fact] + public void GetEnumerator_ReturnsUnderlyingAttributesEnumerator() + { + // Arrange & Act + var attributes = new TestableReadOnlyTagHelperAttributes(new[] + { + new TagHelperAttribute("A", "AV"), + new TagHelperAttribute("B", "BV") + }); + + // Assert + Assert.Equal(attributes.GetEnumerator(), attributes.PublicAttributes.GetEnumerator()); + } + + [Fact] + public void ModifyingUnderlyingAttributes_AffectsExposedAttributes() + { + // Arrange + var attributes = new TestableReadOnlyTagHelperAttributes(Enumerable.Empty()); + var expectedAttributes = new[] + { + new TagHelperAttribute("A", "AV"), + new TagHelperAttribute("B", "BV") + }; + + // Act + attributes.PublicAttributes.AddRange(expectedAttributes); + + // Assert + Assert.Equal(attributes, expectedAttributes, CaseSensitiveTagHelperAttributeComparer.Default); + } + + + [Theory] + [MemberData(nameof(IntIndexerData))] + public void ModifyingUnderlyingAttributes_IntIndexer_ReturnsExpectedResult( + IEnumerable initialAttributes, + int indexToLookup, + IReadOnlyTagHelperAttribute expectedAttribute) + { + // Arrange + var attributes = new TestableReadOnlyTagHelperAttributes(Enumerable.Empty()); + attributes.PublicAttributes.AddRange(initialAttributes); + + // Act + var attribute = attributes[indexToLookup]; + + // Assert + Assert.Equal(expectedAttribute, attribute, CaseSensitiveTagHelperAttributeComparer.Default); + } + + [Theory] + [MemberData(nameof(StringIndexerData))] + public void ModifyingUnderlyingAttributes_StringIndexer_ReturnsExpectedResult( + IEnumerable initialAttributes, + string nameToLookup, + IReadOnlyTagHelperAttribute expectedAttribute) + { + // Arrange + var attributes = new TestableReadOnlyTagHelperAttributes(Enumerable.Empty()); + attributes.PublicAttributes.AddRange(initialAttributes); + + // Act + var attribute = attributes[nameToLookup]; + + // Assert + Assert.Equal(expectedAttribute, attribute, CaseSensitiveTagHelperAttributeComparer.Default); + } + + private class TestableReadOnlyTagHelperAttributes : ReadOnlyTagHelperAttributeList + { + public TestableReadOnlyTagHelperAttributes(IEnumerable attributes) + : base(attributes) + { + } + + public List PublicAttributes + { + get + { + return Attributes; + } + } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperAttributeListTest.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperAttributeListTest.cs new file mode 100644 index 0000000000..4f8224fb69 --- /dev/null +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperAttributeListTest.cs @@ -0,0 +1,698 @@ +// 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.Linq; +using Xunit; + +namespace Microsoft.AspNet.Razor.Runtime.TagHelpers +{ + public class TagHelperAttributeListTest + { + [Theory] + [MemberData( + nameof(ReadOnlyTagHelperAttributeListTest.IntIndexerData), + MemberType = typeof(ReadOnlyTagHelperAttributeListTest))] + public void IntIndexer_GetsExpectedAttribute( + IEnumerable initialAttributes, + int indexToLookup, + TagHelperAttribute expectedAttribute) + { + // Arrange + var attributes = new TagHelperAttributeList(initialAttributes); + + // Act + var attribute = attributes[indexToLookup]; + + // Assert + Assert.Equal(expectedAttribute, attribute, CaseSensitiveTagHelperAttributeComparer.Default); + } + + public static TheoryData IntIndexerSetData + { + get + { + var first = new TagHelperAttribute("First", "First Value"); + var second = new TagHelperAttribute("Second", "Second Value"); + var third = new TagHelperAttribute("Third", "Third Value"); + var set = new TagHelperAttribute("Set", "Set Value"); + + return new TheoryData< + IEnumerable, // initialAttributes + int, // indexToSet + TagHelperAttribute, // setValue + IEnumerable> // expectedAttributes + { + { new[] { first }, 0, set, new[] { set } }, + { new[] { first, second }, 0, set, new[] { set, second } }, + { new[] { first, second }, 1, set, new[] { first, set } }, + { new[] { first, second, third}, 1, set, new[] { first, set, third } }, + { new[] { first, second, third }, 2, set, new[] { first, second, set } }, + { new[] { first, first, second, third}, 1, set, new[] { first, set, second, third } }, + }; + } + } + + [Theory] + [MemberData(nameof(IntIndexerSetData))] + public void IntIndexer_SetsAttributeAtExpectedIndex( + IEnumerable initialAttributes, + int indexToSet, + TagHelperAttribute setValue, + IEnumerable expectedAttributes) + { + // Arrange + var attributes = new TagHelperAttributeList(initialAttributes); + + // Act + attributes[indexToSet] = setValue; + + // Assert + Assert.Equal(expectedAttributes, attributes, CaseSensitiveTagHelperAttributeComparer.Default); + } + + [Theory] + [MemberData( + nameof(ReadOnlyTagHelperAttributeListTest.IntIndexerThrowData), + MemberType = typeof(ReadOnlyTagHelperAttributeListTest))] + public void IntIndexer_Getter_ThrowsIfIndexInvalid(int index) + { + // Arrange + var attributes = new TagHelperAttributeList(new[] + { + new TagHelperAttribute("A", "AV"), + new TagHelperAttribute("B", "BV") + }); + + // Act & Assert + var exception = Assert.Throws("index", () => attributes[index]); + } + + [Theory] + [MemberData( + nameof(ReadOnlyTagHelperAttributeListTest.IntIndexerThrowData), + MemberType = typeof(ReadOnlyTagHelperAttributeListTest))] + public void IntIndexer_Setter_ThrowsIfIndexInvalid(int index) + { + // Arrange + var attributes = new TagHelperAttributeList(new[] + { + new TagHelperAttribute("A", "AV"), + new TagHelperAttribute("B", "BV") + }); + + // Act & Assert + var exception = Assert.Throws("index", () => + { + attributes[index] = new TagHelperAttribute("C", "CV"); + }); + } + + [Theory] + [MemberData( + nameof(ReadOnlyTagHelperAttributeListTest.StringIndexerData), + MemberType = typeof(ReadOnlyTagHelperAttributeListTest))] + public void StringIndexer_GetsExpectedAttribute( + IEnumerable initialAttributes, + string nameToLookup, + TagHelperAttribute expectedAttribute) + { + // Arrange + var attributes = new TagHelperAttributeList(initialAttributes); + + // Act + var attribute = attributes[nameToLookup]; + + // Assert + Assert.Equal(expectedAttribute, attribute, CaseSensitiveTagHelperAttributeComparer.Default); + } + + public static TheoryData StringIndexerSetData + { + get + { + var A = new TagHelperAttribute("AName", "AName Value"); + var ASet = new TagHelperAttribute("aname", "AName Set Value"); + var A2 = new TagHelperAttribute("aname", "AName Second Value"); + var A2Set = new TagHelperAttribute("aname", "AName Second Set Value"); + var A3 = new TagHelperAttribute("AName", "AName Third Value"); + var A3Set = new TagHelperAttribute("aname", "AName Third Set Value"); + var B = new TagHelperAttribute("BName", "BName Value"); + var BSet = new TagHelperAttribute("bname", "BName Set Value"); + var C = new TagHelperAttribute("CName", "CName Value"); + var CSet = new TagHelperAttribute("cname", "CName Set Value"); + var set = new TagHelperAttribute("Set", "Set Value"); + + return new TheoryData< + IEnumerable, // initialAttributes + string, // keyToSet + TagHelperAttribute, // setValue + IEnumerable> // expectedAttributes + { + { new[] { A }, "AName", ASet, new[] { ASet } }, + { new[] { A }, "AnAmE", ASet, new[] { ASet } }, + { new[] { A }, "AnAmE", "AV", new[] { new TagHelperAttribute("AnAmE", "AV") } }, + { new[] { A, B }, "AName", ASet, new[] { ASet, B } }, + { new[] { A, B }, "AnAmE", ASet, new[] { ASet, B } }, + { new[] { A, B }, "AnAmE", "AV", new[] { new TagHelperAttribute("AnAmE", "AV"), B } }, + { new[] { A, B }, "BName", BSet, new[] { A, BSet } }, + { new[] { A, B }, "BnAmE", BSet, new[] { A, BSet } }, + { new[] { A, B }, "BnAmE", "BV", new[] { A, new TagHelperAttribute("BnAmE", "BV") } }, + { new[] { A, B, C }, "BName", BSet, new[] { A, BSet, C } }, + { new[] { A, B, C }, "bname", BSet, new[] { A, BSet, C } }, + { new[] { A, B, C }, "bname", "BV", new[] { A, new TagHelperAttribute("bname", "BV"), C } }, + { new[] { A, B, C }, "CName", CSet, new[] { A, B, CSet } }, + { new[] { A, B, C }, "cnamE", CSet, new[] { A, B, CSet } }, + { new[] { A, B, C }, "cnamE", "CV", new[] { A, B, new TagHelperAttribute("cnamE", "CV") } }, + { Enumerable.Empty(), "Set", set, new[] { set } }, + { new[] { B }, "Set", set, new[] { B, set } }, + { new[] { B }, "Set", "Set Value", new[] { B, set } }, + { new[] { A, B }, "Set", set, new[] { A, B, set } }, + { new[] { A, B }, "Set", "Set Value", new[] { A, B, set } }, + + // Multiple elements same name + { new[] { A, B, A2, C }, "AName", ASet, new[] { ASet, B, C } }, + { new[] { A, B, A2, C }, "aname", ASet, new[] { ASet, B, C } }, + { new[] { A, B, A2, C }, "aname", "av", new[] { new TagHelperAttribute("aname", "av"), B, C } }, + { new[] { B, A2, A }, "aname", A2Set, new[] { B, A2Set } }, + { new[] { B, A2, A }, "aname", "av", new[] { B, new TagHelperAttribute("aname", "av") } }, + { new[] { B, A2, A, C }, "AName", A2Set, new[] { B, A2Set, C } }, + { new[] { B, A2, A, C }, "AName", "av", new[] { B, new TagHelperAttribute("AName", "av"), C } }, + { new[] { A, A3 }, "AName", ASet, new[] { ASet } }, + { new[] { A, A3 }, "AName", "av", new[] { new TagHelperAttribute("AName", "av") } }, + { new[] { A3, A }, "aname", A3Set, new[] { A3Set } }, + { new[] { A3, A }, "aname", "av", new[] { new TagHelperAttribute("aname", "av") } }, + { new[] { A, A2, A3 }, "AName", ASet, new[] { ASet } }, + { new[] { A, A2, A3 }, "AName", "av", new[] { new TagHelperAttribute("AName", "av") } }, + { new[] { C, B, A3, A }, "AName", A3Set, new[] { C, B, A3Set } }, + { new[] { C, B, A3, A }, "AName", "av", new[] { C, B, new TagHelperAttribute("AName", "av") } }, + { new[] { A, A2, A3 }, "BNamE", BSet, new[] { A, A2, A3, BSet } }, + { new[] { A, A2, A3 }, "bname", "BName Set Value", new[] { A, A2, A3, BSet } }, + { new[] { A, A2, A3, B, C }, "Set", set, new[] { A, A2, A3, B, C, set } }, + { new[] { A, A2, A3, B, C }, "Set", "Set Value", new[] { A, A2, A3, B, C, set } }, + }; + } + } + + [Theory] + [MemberData(nameof(StringIndexerSetData))] + public void StringIndexer_SetsAttributeAtExpectedLocation( + IEnumerable initialAttributes, + string keyToSet, + TagHelperAttribute setValue, + IEnumerable expectedAttributes) + { + // Arrange + var attributes = new TagHelperAttributeList(initialAttributes); + + // Act + attributes[keyToSet] = setValue; + + // Assert + Assert.Equal(expectedAttributes, attributes, CaseSensitiveTagHelperAttributeComparer.Default); + } + + [Fact] + public void StringIndexer_Setter_ThrowsIfIndexInvalid() + { + // Arrange + var attributes = new TagHelperAttributeList(new[] + { + new TagHelperAttribute("A", "AV"), + new TagHelperAttribute("B", "BV") + }); + + // Act & Assert + var exception = Assert.Throws("index", () => + { + attributes[2] = new TagHelperAttribute("C", "CV"); + }); + } + + public static TheoryData StringIndexerSetterThrowData + { + get + { + // attributes + return new TheoryData + { + { new TagHelperAttributeList() }, + { new TagHelperAttributeList { { "something", "a value" } } }, + { new TagHelperAttributeList { { "somethingelse", "a value" } } }, + { new TagHelperAttributeList { { "SomethingElse", "a value" } } }, + { new TagHelperAttributeList { { "something", "a value" }, { "somethingelse", "a value" } } }, + { new TagHelperAttributeList { { "SomethingElse", "a value" }, { "somethingelse", "a value" } } } + }; + } + } + + [Theory] + [MemberData(nameof(StringIndexerSetterThrowData))] + public void StringIndexer_Setter_ThrowsIfUnmatchingKey( + TagHelperAttributeList attributes) + { + // Arrange + var expectedMessage = $"Cannot add a {nameof(TagHelperAttribute)} with inconsistent names. The " + + $"{nameof(TagHelperAttribute.Name)} property 'somethingelse' must match the location 'something'." + + $"{Environment.NewLine}Parameter name: name"; + + // Act & Assert + var exception = Assert.Throws("name", () => + { + attributes["something"] = new TagHelperAttribute("somethingelse", "value"); + }); + Assert.Equal(expectedMessage, exception.Message); + } + + + [Fact] + public void ICollection_IsReadOnly_ReturnsFalse() + { + // Arrange + var attributes = new TagHelperAttributeList() as ICollection; + + // Act + var isReadOnly = attributes.IsReadOnly; + + // Assert + Assert.False(isReadOnly); + } + + public static TheoryData AddData + { + get + { + var A = new TagHelperAttribute("AName", "AName Value"); + var A2 = new TagHelperAttribute("aname", "AName Second Value"); + var B = new TagHelperAttribute("BName", "BName Value"); + + return new TheoryData< + IEnumerable, // initialAttributes + TagHelperAttribute, // attributeToAdd + IEnumerable> // expectedAttributes + { + { Enumerable.Empty(), A, new[] { A } }, + { new[] { A }, B, new[] { A, B } }, + { new[] { A }, A2, new[] { A, A2 } }, + }; + } + } + + [Theory] + [MemberData(nameof(AddData))] + public void Add_AppendsAttributes( + IEnumerable initialAttributes, + TagHelperAttribute attributeToAdd, + IEnumerable expectedAttributes) + { + // Arrange + var attributes = new TagHelperAttributeList(initialAttributes); + + // Act + attributes.Add(attributeToAdd); + + // Assert + Assert.Equal(expectedAttributes, attributes, CaseSensitiveTagHelperAttributeComparer.Default); + } + + [Fact] + public void Add_ThrowsWhenNameAndValueAreNull() + { + // Arrange + var attributes = new TagHelperAttributeList(); + var expectedMessage = $"Cannot add a '{typeof(TagHelperAttribute).FullName}' with a null " + + $"'{nameof(TagHelperAttribute.Name)}'.{Environment.NewLine}Parameter name: attribute"; + + // Act & Assert + var exception = Assert.Throws("attribute", + () => attributes.Add(new TagHelperAttribute())); + Assert.Equal(expectedMessage, exception.Message); + } + + [Fact] + public void Add_ThrowsWhenNameIsNull() + { + // Arrange + var attributes = new TagHelperAttributeList(); + var expectedMessage = $"Cannot add a '{typeof(TagHelperAttribute).FullName}' with a null " + + $"'{nameof(TagHelperAttribute.Name)}'.{Environment.NewLine}Parameter name: attribute"; + + // Act & Assert + var exception = Assert.Throws("attribute", + () => attributes.Add(new TagHelperAttribute + { + Value = "Anything" + })); + Assert.Equal(expectedMessage, exception.Message); + } + + public static TheoryData InsertData + { + get + { + var A = new TagHelperAttribute("AName", "AName Value"); + var A2 = new TagHelperAttribute("aname", "AName Second Value"); + var B = new TagHelperAttribute("BName", "BName Value"); + + return new TheoryData< + IEnumerable, // initialAttributes + TagHelperAttribute, // attributeToAdd + int, // locationToInsert + IEnumerable> // expectedAttributes + { + { Enumerable.Empty(), A, 0, new[] { A } }, + { new[] { A }, B, 1, new[] { A, B } }, + { new[] { A }, B, 0, new[] { B, A } }, + { new[] { A }, A2, 1, new[] { A, A2 } }, + { new[] { A }, A2, 0, new[] { A2, A } }, + { new[] { A, B }, A2, 0, new[] { A2, A, B } }, + { new[] { A, B }, A2, 1, new[] { A, A2, B } }, + { new[] { A, B }, A2, 2, new[] { A, B, A2 } }, + }; + } + } + + [Theory] + [MemberData(nameof(InsertData))] + public void Insert_InsertsAttributes( + IEnumerable initialAttributes, + TagHelperAttribute attributeToAdd, + int locationToInsert, + IEnumerable expectedAttributes) + { + // Arrange + var attributes = new TagHelperAttributeList(initialAttributes); + + // Act + attributes.Insert(locationToInsert, attributeToAdd); + + // Assert + Assert.Equal(expectedAttributes, attributes, CaseSensitiveTagHelperAttributeComparer.Default); + } + + [Fact] + public void Insert_ThrowsWhenNameIsNull() + { + // Arrange + var attributes = new TagHelperAttributeList(); + var expectedMessage = $"Cannot add a '{typeof(TagHelperAttribute).FullName}' with a null " + + $"'{nameof(TagHelperAttribute.Name)}'.{Environment.NewLine}Parameter name: attribute"; + + // Act & Assert + var exception = Assert.Throws("attribute", + () => attributes.Insert(0, new TagHelperAttribute + { + Value = "Anything" + })); + Assert.Equal(expectedMessage, exception.Message); + } + + [Fact] + public void Insert_ThrowsWhenIndexIsOutOfRange() + { + // Arrange + var attributes = new TagHelperAttributeList( + new[] + { + new TagHelperAttribute("a", "av"), + new TagHelperAttribute("b", "bv"), + }); + + // Act & Assert + var exception = Assert.Throws("index", + () => attributes.Insert(3, new TagHelperAttribute("c", "cb"))); + } + + public static TheoryData CopyToData + { + get + { + var A = new TagHelperAttribute("AName", "AName Value"); + var A2 = new TagHelperAttribute("aname", "AName Second Value"); + var B = new TagHelperAttribute("BName", "BName Value"); + + return new TheoryData< + IEnumerable, // initialAttributes + TagHelperAttribute[], // attributesToCopy + int, // locationToCopy + IEnumerable> // expectedAttributes + { + { Enumerable.Empty(), new[] { A }, 0, new[] { A } }, + { Enumerable.Empty(), new[] { A, B }, 0, new[] { A, B } }, + { new[] { A }, new[] { B }, 1, new[] { A, B } }, + { new[] { A }, new[] { B }, 0, new[] { B } }, + { new[] { A }, new[] { A2 }, 1, new[] { A, A2 } }, + { new[] { A }, new[] { A2 }, 0, new[] { A2 } }, + { new[] { A, B }, new[] { A2 }, 0, new[] { A2, B } }, + { new[] { A, B }, new[] { A2 }, 1, new[] { A, A2 } }, + { new[] { A, B }, new[] { A2 }, 2, new[] { A, B, A2 } }, + { new[] { A, B }, new[] { A2, A2 }, 0, new[] { A2, A2 } }, + { new[] { A, B, A2 }, new[] { A2, A2 }, 1, new[] { A, A2, A2 } }, + { new[] { A, B }, new[] { A2, A2 }, 2, new[] { A, B, A2, A2 } }, + }; + } + } + + [Theory] + [MemberData(nameof(CopyToData))] + public void CopyTo_CopiesAttributes( + IEnumerable initialAttributes, + TagHelperAttribute[] attributesToCopy, + int locationToCopy, + IEnumerable expectedAttributes) + { + // Arrange + var attributes = new TagHelperAttributeList(initialAttributes); + var attributeDestination = new TagHelperAttribute[expectedAttributes.Count()]; + attributes.ToArray().CopyTo(attributeDestination, 0); + + // Act + attributesToCopy.CopyTo(attributeDestination, locationToCopy); + + // Assert + Assert.Equal(expectedAttributes, attributeDestination, CaseSensitiveTagHelperAttributeComparer.Default); + } + + public static TheoryData RemoveAllData + { + get + { + var A = new TagHelperAttribute("AName", "AName Value"); + var A2 = new TagHelperAttribute("aname", "AName Second Value"); + var A3 = new TagHelperAttribute("AName", "AName Third Value"); + var B = new TagHelperAttribute("BName", "BName Value"); + var C = new TagHelperAttribute("CName", "CName Value"); + + return new TheoryData< + IEnumerable, // initialAttributes + string, // keyToRemove + IEnumerable, // expectedAttributes + bool> // expectedRemoval + { + { new[] { A }, "AName", Enumerable.Empty(), true }, + { new[] { A }, "AnAmE", Enumerable.Empty(), true }, + { new[] { A, B }, "AName", new[] { B }, true }, + { new[] { A, B }, "AnAmE", new[] { B }, true }, + { new[] { A, B }, "BName", new[] { A }, true }, + { new[] { A, B }, "BnAmE", new[] { A }, true }, + { new[] { A, B, C }, "BName", new[] { A, C }, true }, + { new[] { A, B, C }, "bname", new[] { A, C }, true }, + { new[] { A, B, C }, "CName", new[] { A, B }, true }, + { new[] { A, B, C }, "cnamE", new[] { A, B }, true }, + + // Multiple elements same name + { new[] { A, B, A2, C }, "AName", new[] { B, C }, true }, + { new[] { A, B, A2, C }, "aname", new[] { B, C }, true }, + { new[] { B, A2, A }, "aname", new[] { B }, true }, + { new[] { B, A2, A, C }, "AName", new[] { B, C }, true }, + { new[] { A, A3 }, "AName", Enumerable.Empty(), true }, + { new[] { A3, A }, "aname", Enumerable.Empty(), true }, + { new[] { A, A2, A3 }, "AName", Enumerable.Empty(), true }, + { new[] { C, B, A3, A }, "AName", new[] { C, B }, true }, + + // No removal expected lookups + { Enumerable.Empty(), "_0_", Enumerable.Empty(), false }, + { new[] { A }, "_AName_", new[] { A }, false }, + { new[] { A }, "completely different", new[] { A }, false }, + { new[] { A, B }, "_AName_", new[] { A, B }, false }, + { new[] { A, B }, "completely different", new[] { A, B }, false }, + { new[] { A, B, C }, "_BName_", new[] { A, B, C }, false }, + { new[] { A, B, C }, "completely different", new[] { A, B, C }, false }, + { new[] { A, A2, B, C }, "_cnamE_", new[] { A, A2, B, C }, false }, + { new[] { A, A2, B, C }, "completely different", new[] { A, A2, B, C }, false }, + { new[] { A, A2, A3, B, C }, "_cnamE_", new[] { A, A2, A3, B, C }, false }, + { new[] { A, A2, A3, B, C }, "completely different", new[] { A, A2, A3, B, C }, false }, + }; + } + } + + [Theory] + [MemberData(nameof(RemoveAllData))] + public void RemoveAll_RemovesAllExpectedAttributes( + IEnumerable initialAttributes, + string keyToRemove, + IEnumerable expectedAttributes, + bool expectedRemoval) + { + // Arrange + var attributes = new TagHelperAttributeList(initialAttributes); + + // Act + var removed = attributes.RemoveAll(keyToRemove); + + // Assert + Assert.Equal(expectedRemoval, removed); + Assert.Equal(expectedAttributes, attributes, CaseSensitiveTagHelperAttributeComparer.Default); + } + + public static TheoryData RemoveData + { + get + { + var A = new TagHelperAttribute("AName", "av"); + var A2 = new TagHelperAttribute("aname", "av"); + var A3 = new TagHelperAttribute("AName", "av"); + var B = new TagHelperAttribute("BName", "bv"); + var C = new TagHelperAttribute("CName", "cv"); + var empty = Enumerable.Empty(); + + return new TheoryData< + IEnumerable, // initialAttributes + TagHelperAttribute, // attributeToRemove + IEnumerable, // expectedAttributes + bool> // expectedResult + { + { new[] { A }, A, empty, true }, + { new[] { A }, new TagHelperAttribute("AnAmE", "av"), empty, true }, + { new[] { A, B }, A, new[] { B }, true }, + { new[] { A, B }, new TagHelperAttribute("AnAmE", "av"), new[] { B }, true }, + { new[] { A, B }, B, new[] { A }, true }, + { new[] { A, B }, new TagHelperAttribute("BnAmE", "bv"), new[] { A }, true }, + { new[] { A, B, C }, B, new[] { A, C }, true }, + { new[] { A, B, C }, new TagHelperAttribute("bname", "bv"), new[] { A, C }, true }, + { new[] { A, B, C }, C, new[] { A, B }, true }, + { new[] { A, B, C }, new TagHelperAttribute("cnamE", "cv"), new[] { A, B }, true }, + + // Multiple elements same name + { new[] { A, B, A2, C }, A, new[] { B, A2, C }, true }, + { new[] { A, B, A2, C }, new TagHelperAttribute("aname", "av"), new[] { B, A2, C }, true }, + { new[] { B, A2, A }, new TagHelperAttribute("aname", "av"), new[] { B, A }, true }, + { new[] { B, A2, A, C }, A, new[] { B, A, C }, true }, + { new[] { A, A3 }, A3, new[] { A3 }, true }, + { new[] { A3, A }, new TagHelperAttribute("aname", "av"), new[] { A }, true }, + { new[] { A, A2, A3 }, new TagHelperAttribute("AName", "av"), new[] { A2, A3 }, true }, + { new[] { C, B, A3, A }, new TagHelperAttribute("AName", "av"), new[] { C, B, A }, true }, + + // Null expected lookups + { Enumerable.Empty(), "_0_", Enumerable.Empty(), false }, + { new[] { A }, "_AName_", new[] { A }, false }, + { new[] { A }, "completely different", new[] { A }, false }, + { new[] { A, B }, "_AName_", new[] { A, B }, false }, + { new[] { A, B }, "completely different", new[] { A, B }, false }, + { new[] { A, B, C }, "_BName_", new[] { A, B, C }, false }, + { new[] { A, B, C }, "completely different", new[] { A, B, C }, false }, + { new[] { A, A2, B, C }, "_cnamE_", new[] { A, A2, B, C }, false }, + { new[] { A, A2, B, C }, "completely different", new[] { A, A2, B, C }, false }, + { new[] { A, A2, A3, B, C }, "_cnamE_", new[] { A, A2, A3, B, C }, false }, + { new[] { A, A2, A3, B, C }, "completely different", new[] { A, A2, A3, B, C }, false }, + }; + } + } + + [Theory] + [MemberData(nameof(RemoveData))] + public void Remove_ReturnsExpectedValueAndRemovesFirstAttribute( + IEnumerable initialAttributes, + TagHelperAttribute attributeToRemove, + IEnumerable expectedAttributes, + bool expectedResult) + { + // Arrange + var attributes = new TagHelperAttributeList(initialAttributes); + + // Act + var result = attributes.Remove(attributeToRemove); + + // Assert + Assert.Equal(expectedResult, result); + Assert.Equal(expectedAttributes, attributes, CaseSensitiveTagHelperAttributeComparer.Default); + } + + public static TheoryData RemoveAtData + { + get + { + var A = new TagHelperAttribute("AName", "AName Value"); + var A2 = new TagHelperAttribute("aname", "AName Second Value"); + var B = new TagHelperAttribute("BName", "BName Value"); + + return new TheoryData< + IEnumerable, // initialAttributes + int, // locationToRemove + IEnumerable> // expectedAttributes + { + { new[] { A }, 0, Enumerable.Empty() }, + { new[] { A, B }, 0, new[] { B } }, + { new[] { A, B }, 1, new[] { A } }, + { new[] { A, A2 }, 0, new[] { A2 } }, + { new[] { A, A2 }, 1, new[] { A } }, + { new[] { A, B, A2 }, 0, new[] { B, A2 } }, + { new[] { A, B, A2 }, 1, new[] { A, A2 } }, + { new[] { A, B, A2 }, 2, new[] { A, B } }, + }; + } + } + + [Theory] + [MemberData(nameof(RemoveAtData))] + public void RemoveAt_RemovesAttributeAtSpecifiedIndex( + IEnumerable initialAttributes, + int locationToRemove, + IEnumerable expectedAttributes) + { + // Arrange + var attributes = new TagHelperAttributeList(initialAttributes); + + // Act + attributes.RemoveAt(locationToRemove); + + // Assert + Assert.Equal(expectedAttributes, attributes, CaseSensitiveTagHelperAttributeComparer.Default); + } + + [Fact] + public void RemoveAt_ThrowsWhenIndexIsOutOfRange() + { + // Arrange + var attributes = new TagHelperAttributeList( + new[] + { + new TagHelperAttribute("a", "av"), + new TagHelperAttribute("b", "bv"), + }); + + // Act & Assert + var exception = Assert.Throws("index", + () => attributes.RemoveAt(3)); + } + + [Fact] + public void Clear_RemovesAllAttributes() + { + // Arrange + var attributes = new TagHelperAttributeList( + new[] + { + new TagHelperAttribute("a", "av"), + new TagHelperAttribute("b", "bv"), + }); + + // Act + attributes.Clear(); + + // Assert + Assert.Empty(attributes); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperContextTest.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperContextTest.cs index ee91780356..1d068f6495 100644 --- a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperContextTest.cs +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperContextTest.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Xunit; @@ -21,7 +22,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers // Act var context = new TagHelperContext( - allAttributes: new Dictionary(), + allAttributes: Enumerable.Empty(), items: expectedItems, uniqueId: string.Empty, getChildContentAsync: () => Task.FromResult(new DefaultTagHelperContent())); diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperExecutionContextTest.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperExecutionContextTest.cs index 9cd9d895e3..d8b247c386 100644 --- a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperExecutionContextTest.cs +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperExecutionContextTest.cs @@ -148,6 +148,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers } } + [Theory] [MemberData(nameof(DictionaryCaseTestingData))] public void HtmlAttributes_IgnoresCase(string originalName, string updatedName) { @@ -160,22 +161,23 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers // Assert var attribute = Assert.Single(executionContext.HTMLAttributes); - Assert.Equal(new KeyValuePair(originalName, "something else"), attribute); + Assert.Equal(new TagHelperAttribute(originalName, "something else"), attribute); } + [Theory] [MemberData(nameof(DictionaryCaseTestingData))] public void AllAttributes_IgnoresCase(string originalName, string updatedName) { // Arrange var executionContext = new TagHelperExecutionContext("p", selfClosing: false); - executionContext.AllAttributes[originalName] = false; + executionContext.AllAttributes.Add(originalName, value: false); // Act - executionContext.AllAttributes[updatedName] = true; + executionContext.AllAttributes[updatedName].Value = true; // Assert var attribute = Assert.Single(executionContext.AllAttributes); - Assert.Equal(new KeyValuePair(originalName, true), attribute); + Assert.Equal(new TagHelperAttribute(originalName, true), attribute); } [Fact] @@ -183,7 +185,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { // Arrange var executionContext = new TagHelperExecutionContext("p", selfClosing: false); - var expectedAttributes = new Dictionary + var expectedAttributes = new TagHelperAttributeList { { "class", "btn" }, { "foo", "bar" } @@ -194,7 +196,10 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers executionContext.AddHtmlAttribute("foo", "bar"); // Assert - Assert.Equal(expectedAttributes, executionContext.HTMLAttributes); + Assert.Equal( + expectedAttributes, + executionContext.HTMLAttributes, + CaseSensitiveTagHelperAttributeComparer.Default); } [Fact] @@ -202,7 +207,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { // Arrange var executionContext = new TagHelperExecutionContext("p", selfClosing: false); - var expectedAttributes = new Dictionary + var expectedAttributes = new TagHelperAttributeList { { "class", "btn" }, { "something", true }, @@ -215,7 +220,10 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers executionContext.AddHtmlAttribute("foo", "bar"); // Assert - Assert.Equal(expectedAttributes, executionContext.AllAttributes); + Assert.Equal( + expectedAttributes, + executionContext.AllAttributes, + CaseSensitiveTagHelperAttributeComparer.Default); } [Fact] diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperOutputTest.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperOutputTest.cs index 39d7912f13..08b5caa43b 100644 --- a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperOutputTest.cs +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperOutputTest.cs @@ -1,7 +1,6 @@ // 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.Collections.Generic; using Xunit; namespace Microsoft.AspNet.Razor.Runtime.TagHelpers @@ -142,7 +141,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { // Arrange var tagHelperOutput = new TagHelperOutput("p", - attributes: new Dictionary + new TagHelperAttributeList { { "class", "btn" }, { "something", " spaced " } @@ -175,7 +174,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { // Arrange var tagHelperOutput = new TagHelperOutput("p", - attributes: new Dictionary + new TagHelperAttributeList { { originalName, "btn" }, }); @@ -185,7 +184,10 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers // Assert var attribute = Assert.Single(tagHelperOutput.Attributes); - Assert.Equal(new KeyValuePair(originalName, "super button"), attribute); + Assert.Equal( + new TagHelperAttribute(updateName, "super button"), + attribute, + CaseSensitiveTagHelperAttributeComparer.Default); } } } \ No newline at end of file diff --git a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperRunnerTest.cs b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperRunnerTest.cs index 499452d490..32565bf13c 100644 --- a/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperRunnerTest.cs +++ b/test/Microsoft.AspNet.Razor.Runtime.Test/TagHelpers/TagHelperRunnerTest.cs @@ -135,8 +135,8 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers // Assert Assert.Equal("foo", output.TagName); - Assert.Equal("somethingelse", output.Attributes["class"]); - Assert.Equal("world", output.Attributes["hello"]); + Assert.Equal("somethingelse", output.Attributes["class"].Value); + Assert.Equal("world", output.Attributes["hello"].Value); Assert.Equal(true, output.SelfClosing); } @@ -154,7 +154,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers var output = await runner.RunAsync(executionContext); // Assert - Assert.Equal("True", output.Attributes["foo"]); + Assert.Equal("True", output.Attributes["foo"].Value); } [Fact] @@ -183,8 +183,14 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers Processed = true; output.TagName = "foo"; - output.Attributes["class"] = "somethingelse"; - output.Attributes["hello"] = "world"; + + TagHelperAttribute classAttribute; + if (output.Attributes.TryGetAttribute("class", out classAttribute)) + { + classAttribute.Value = "somethingelse"; + } + + output.Attributes.Add("hello", "world"); output.SelfClosing = true; } } @@ -203,7 +209,7 @@ namespace Microsoft.AspNet.Razor.Runtime.TagHelpers { public override void Process(TagHelperContext context, TagHelperOutput output) { - output.Attributes["foo"] = context.AllAttributes["foo"].ToString(); + output.Attributes.Add("foo", context.AllAttributes["foo"].Value.ToString()); } } diff --git a/test/Microsoft.AspNet.Razor.Test/Framework/BlockTypes.cs b/test/Microsoft.AspNet.Razor.Test/Framework/BlockTypes.cs index 17ae9ca15a..b44b4bd008 100644 --- a/test/Microsoft.AspNet.Razor.Test/Framework/BlockTypes.cs +++ b/test/Microsoft.AspNet.Razor.Test/Framework/BlockTypes.cs @@ -153,24 +153,26 @@ namespace Microsoft.AspNet.Razor.Test.Framework public class MarkupTagHelperBlock : TagHelperBlock { public MarkupTagHelperBlock(string tagName) - : this(tagName, selfClosing: false, attributes: new Dictionary()) + : this(tagName, selfClosing: false, attributes: new List>()) { } public MarkupTagHelperBlock(string tagName, bool selfClosing) - : this(tagName, selfClosing, new Dictionary()) + : this(tagName, selfClosing, new List>()) { } - public MarkupTagHelperBlock(string tagName, - IDictionary attributes) + public MarkupTagHelperBlock( + string tagName, + IList> attributes) : this(tagName, selfClosing: false, attributes: attributes, children: new SyntaxTreeNode[0]) { } - public MarkupTagHelperBlock(string tagName, - bool selfClosing, - IDictionary attributes) + public MarkupTagHelperBlock( + string tagName, + bool selfClosing, + IList> attributes) : this(tagName, selfClosing, attributes, new SyntaxTreeNode[0]) { } @@ -179,27 +181,29 @@ namespace Microsoft.AspNet.Razor.Test.Framework : this( tagName, selfClosing: false, - attributes: new Dictionary(), + attributes: new List>(), children: children) { } public MarkupTagHelperBlock(string tagName, bool selfClosing, params SyntaxTreeNode[] children) - : this(tagName, selfClosing, new Dictionary(), children) + : this(tagName, selfClosing, new List>(), children) { } - public MarkupTagHelperBlock(string tagName, - IDictionary attributes, - params SyntaxTreeNode[] children) + public MarkupTagHelperBlock( + string tagName, + IList> attributes, + params SyntaxTreeNode[] children) : base(new TagHelperBlockBuilder(tagName, selfClosing: false, attributes: attributes, children: children)) { } - - public MarkupTagHelperBlock(string tagName, - bool selfClosing, - IDictionary attributes, - params SyntaxTreeNode[] children) + + public MarkupTagHelperBlock( + string tagName, + bool selfClosing, + IList> attributes, + params SyntaxTreeNode[] children) : base(new TagHelperBlockBuilder(tagName, selfClosing, attributes, children)) { } diff --git a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperParseTreeRewriterTest.cs b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperParseTreeRewriterTest.cs index 1714bf48f8..01f4acdc1c 100644 --- a/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperParseTreeRewriterTest.cs +++ b/test/Microsoft.AspNet.Razor.Test/TagHelpers/TagHelperParseTreeRewriterTest.cs @@ -62,9 +62,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "p", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - ["class"] = factory.Markup("btn") + new KeyValuePair("class", factory.Markup("btn")) })) }, { @@ -73,9 +73,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "p", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - ["class"] = dateTimeNow + new KeyValuePair("class", dateTimeNow) })) }, { @@ -83,9 +83,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "p", - attributes: new Dictionary + attributes: new List> { - ["class"] = factory.Markup("btn") + new KeyValuePair("class", factory.Markup("btn")) }, children: factory.Markup("words and spaces"))) }, @@ -94,9 +94,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "p", - attributes: new Dictionary + attributes: new List> { - ["class"] = dateTimeNow + new KeyValuePair("class", dateTimeNow) }, children: factory.Markup("words and spaces"))) }, @@ -105,9 +105,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "p", - attributes: new Dictionary + attributes: new List> { - ["class"] = factory.Markup("btn") + new KeyValuePair("class", factory.Markup("btn")) }, children: new SyntaxTreeNode[] { @@ -124,9 +124,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "strong", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - ["catchAll"] = factory.Markup("hi") + new KeyValuePair("catchAll", factory.Markup("hi")) })) }, { @@ -135,9 +135,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "strong", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - ["catchAll"] = dateTimeNow + new KeyValuePair("catchAll", dateTimeNow) })) }, { @@ -145,9 +145,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "strong", - attributes: new Dictionary + attributes: new List> { - ["catchAll"] = factory.Markup("hi") + new KeyValuePair("catchAll", factory.Markup("hi")) }, children: factory.Markup("words and spaces"))) }, @@ -156,9 +156,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "strong", - attributes: new Dictionary + attributes: new List> { - ["catchAll"] = dateTimeNow + new KeyValuePair("catchAll", dateTimeNow) }, children: factory.Markup("words and spaces"))) }, @@ -205,10 +205,10 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "p", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - ["notRequired"] = factory.Markup("a"), - ["class"] = factory.Markup("btn") + new KeyValuePair("notRequired", factory.Markup("a")), + new KeyValuePair("class", factory.Markup("btn")) })) }, { @@ -217,10 +217,10 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "p", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - ["notRequired"] = dateTimeNow, - ["class"] = factory.Markup("btn") + new KeyValuePair("notRequired", dateTimeNow), + new KeyValuePair("class", factory.Markup("btn")) })) }, { @@ -228,10 +228,10 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "p", - attributes: new Dictionary + attributes: new List> { - ["notRequired"] = factory.Markup("a"), - ["class"] = factory.Markup("btn") + new KeyValuePair("notRequired", factory.Markup("a")), + new KeyValuePair("class", factory.Markup("btn")) }, children: factory.Markup("words and spaces"))) }, @@ -241,10 +241,10 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "div", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - ["style"] = new MarkupBlock(), - ["class"] = factory.Markup("btn") + new KeyValuePair("style", new MarkupBlock()), + new KeyValuePair("class", factory.Markup("btn")) })) }, { @@ -253,10 +253,10 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "div", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - ["style"] = dateTimeNow, - ["class"] = factory.Markup("btn") + new KeyValuePair("style", dateTimeNow), + new KeyValuePair("class", factory.Markup("btn")) })) }, { @@ -264,10 +264,10 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "div", - attributes: new Dictionary + attributes: new List> { - ["style"] = new MarkupBlock(), - ["class"] = factory.Markup("btn") + new KeyValuePair("style", new MarkupBlock()), + new KeyValuePair("class", factory.Markup("btn")) }, children: factory.Markup("words and spaces"))) }, @@ -276,10 +276,10 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "div", - attributes: new Dictionary + attributes: new List> { - ["style"] = dateTimeNow, - ["class"] = dateTimeNow + new KeyValuePair("style", dateTimeNow), + new KeyValuePair("class", dateTimeNow) }, children: factory.Markup("words and spaces"))) }, @@ -288,10 +288,10 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "div", - attributes: new Dictionary + attributes: new List> { - ["style"] = new MarkupBlock(), - ["class"] = factory.Markup("btn") + new KeyValuePair("style", new MarkupBlock()), + new KeyValuePair("class", factory.Markup("btn")) }, children: new SyntaxTreeNode[] { @@ -308,10 +308,10 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "p", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - ["class"] = factory.Markup("btn"), - ["catchAll"] = factory.Markup("hi") + new KeyValuePair("class", factory.Markup("btn")), + new KeyValuePair("catchAll", factory.Markup("hi")) })) }, { @@ -319,10 +319,10 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "p", - attributes: new Dictionary + attributes: new List> { - ["class"] = factory.Markup("btn"), - ["catchAll"] = factory.Markup("hi") + new KeyValuePair("class", factory.Markup("btn")), + new KeyValuePair("catchAll", factory.Markup("hi")) }, children: factory.Markup("words and spaces"))) }, @@ -332,11 +332,11 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "div", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - ["style"] = new MarkupBlock(), - ["class"] = factory.Markup("btn"), - ["catchAll"] = factory.Markup("hi") + new KeyValuePair("style", new MarkupBlock()), + new KeyValuePair("class", factory.Markup("btn")), + new KeyValuePair("catchAll", factory.Markup("hi")) })) }, { @@ -344,11 +344,11 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "div", - attributes: new Dictionary + attributes: new List> { - ["style"] = new MarkupBlock(), - ["class"] = factory.Markup("btn"), - ["catchAll"] = factory.Markup("hi") + new KeyValuePair("style", new MarkupBlock()), + new KeyValuePair("class", factory.Markup("btn")), + new KeyValuePair("catchAll", factory.Markup("hi")) }, children: factory.Markup("words and spaces"))) }, @@ -358,11 +358,11 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "div", - attributes: new Dictionary + attributes: new List> { - ["style"] = dateTimeNow, - ["class"] = dateTimeNow, - ["catchAll"] = dateTimeNow + new KeyValuePair("style", dateTimeNow), + new KeyValuePair("class", dateTimeNow), + new KeyValuePair("catchAll", dateTimeNow) }, children: factory.Markup("words and spaces"))) }, @@ -371,11 +371,11 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "div", - attributes: new Dictionary + attributes: new List> { - ["style"] = new MarkupBlock(), - ["class"] = factory.Markup("btn"), - ["catchAll"] = factory.Markup("hi") + new KeyValuePair("style", new MarkupBlock()), + new KeyValuePair("class", factory.Markup("btn")), + new KeyValuePair("catchAll", factory.Markup("hi")) }, children: new SyntaxTreeNode[] { @@ -446,9 +446,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "p", - attributes: new Dictionary + attributes: new List> { - ["class"] = factory.Markup("btn") + new KeyValuePair("class", factory.Markup("btn")) }, children: new[] { @@ -461,9 +461,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "strong", - attributes: new Dictionary + attributes: new List> { - ["catchAll"] = factory.Markup("hi") + new KeyValuePair("catchAll", factory.Markup("hi")) }, children: new SyntaxTreeNode[] { @@ -476,9 +476,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "p", - attributes: new Dictionary + attributes: new List> { - ["class"] = factory.Markup("btn") + new KeyValuePair("class", factory.Markup("btn")) }, children: new[] { @@ -493,9 +493,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "strong", - attributes: new Dictionary + attributes: new List> { - ["catchAll"] = factory.Markup("hi") + new KeyValuePair("catchAll", factory.Markup("hi")) }, children: new SyntaxTreeNode[] { @@ -510,15 +510,15 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "p", - attributes: new Dictionary + attributes: new List> { - ["class"] = factory.Markup("btn") + new KeyValuePair("class", factory.Markup("btn")) }, children: new MarkupTagHelperBlock( "strong", - attributes: new Dictionary + attributes: new List> { - ["catchAll"] = factory.Markup("hi") + new KeyValuePair("catchAll", factory.Markup("hi")) }, children: new[] { @@ -531,15 +531,15 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "strong", - attributes: new Dictionary + attributes: new List> { - ["catchAll"] = factory.Markup("hi") + new KeyValuePair("catchAll", factory.Markup("hi")) }, children: new MarkupTagHelperBlock( "p", - attributes: new Dictionary + attributes: new List> { - ["class"] = factory.Markup("btn") + new KeyValuePair("class", factory.Markup("btn")) }, children: new[] { @@ -552,15 +552,15 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "p", - attributes: new Dictionary + attributes: new List> { - ["class"] = factory.Markup("btn") + new KeyValuePair("class", factory.Markup("btn")) }, children: new MarkupTagHelperBlock( "p", - attributes: new Dictionary + attributes: new List> { - ["class"] = factory.Markup("btn") + new KeyValuePair("class", factory.Markup("btn")) }, children: new[] { @@ -573,15 +573,15 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "strong", - attributes: new Dictionary + attributes: new List> { - ["catchAll"] = factory.Markup("hi") + new KeyValuePair("catchAll", factory.Markup("hi")) }, children: new MarkupTagHelperBlock( "strong", - attributes: new Dictionary + attributes: new List> { - ["catchAll"] = factory.Markup("hi") + new KeyValuePair("catchAll", factory.Markup("hi")) }, children: new[] { @@ -594,9 +594,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "p", - attributes: new Dictionary + attributes: new List> { - ["class"] = factory.Markup("btn") + new KeyValuePair("class", factory.Markup("btn")) }, children: new[] { @@ -604,9 +604,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers blockFactory.MarkupTagBlock("

"), new MarkupTagHelperBlock( "p", - attributes: new Dictionary + attributes: new List> { - ["class"] = factory.Markup("btn") + new KeyValuePair("class", factory.Markup("btn")) }, children: new[] { @@ -623,9 +623,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "strong", - attributes: new Dictionary + attributes: new List> { - ["catchAll"] = factory.Markup("hi") + new KeyValuePair("catchAll", factory.Markup("hi")) }, children: new[] { @@ -633,9 +633,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers blockFactory.MarkupTagBlock(""), new MarkupTagHelperBlock( "strong", - attributes: new Dictionary + attributes: new List> { - ["catchAll"] = factory.Markup("hi") + new KeyValuePair("catchAll", factory.Markup("hi")) }, children: new[] { @@ -701,9 +701,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "p", - attributes: new Dictionary + attributes: new List> { - ["class"] = factory.Markup("btn") + new KeyValuePair("class", factory.Markup("btn")) })), new[] { @@ -720,10 +720,10 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "p", - attributes: new Dictionary + attributes: new List> { - ["notRequired"] = factory.Markup("hi"), - ["class"] = factory.Markup("btn") + new KeyValuePair("notRequired", factory.Markup("hi")), + new KeyValuePair("class", factory.Markup("btn")) })), new[] { @@ -747,9 +747,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "p", - attributes: new Dictionary + attributes: new List> { - ["class"] = factory.Markup("btn") + new KeyValuePair("class", factory.Markup("btn")) })), new[] { @@ -763,10 +763,10 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "p", - attributes: new Dictionary + attributes: new List> { - ["notRequired"] = factory.Markup("hi"), - ["class"] = factory.Markup("btn") + new KeyValuePair("notRequired", factory.Markup("hi")), + new KeyValuePair("class", factory.Markup("btn")) })), new[] { @@ -779,9 +779,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers "

", new MarkupBlock( new MarkupTagHelperBlock("p", - attributes: new Dictionary + attributes: new List> { - ["class"] = factory.Markup("btn") + new KeyValuePair("class", factory.Markup("btn")) }, children: blockFactory.MarkupTagBlock("

"))), new[] @@ -798,10 +798,10 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers "

", new MarkupBlock( new MarkupTagHelperBlock("p", - attributes: new Dictionary + attributes: new List> { - ["notRequired"] = factory.Markup("hi"), - ["class"] = factory.Markup("btn") + new KeyValuePair("notRequired", factory.Markup("hi")), + new KeyValuePair("class", factory.Markup("btn")) }, children: blockFactory.MarkupTagBlock("

"))), new[] @@ -819,9 +819,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "p", - attributes: new Dictionary + attributes: new List> { - ["class"] = factory.Markup("btn") + new KeyValuePair("class", factory.Markup("btn")) })), new[] { @@ -838,10 +838,10 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "p", - attributes: new Dictionary + attributes: new List> { - ["notRequired"] = factory.Markup("hi"), - ["class"] = factory.Markup("btn") + new KeyValuePair("notRequired", factory.Markup("hi")), + new KeyValuePair("class", factory.Markup("btn")) })), new[] { @@ -1033,9 +1033,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "th:myth", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - { "class", factory.Markup("btn") } + new KeyValuePair("class", factory.Markup("btn")) })), availableDescriptorsColon }, @@ -1045,9 +1045,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "PREFIXmyth", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - { "class", factory.Markup("btn") } + new KeyValuePair("class", factory.Markup("btn")) })), availableDescriptorsText }, @@ -1057,9 +1057,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "th:myth2", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - { "class", factory.Markup("btn") } + new KeyValuePair("class", factory.Markup("btn")) })), availableDescriptorsColon }, @@ -1069,9 +1069,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "PREFIXmyth2", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - { "class", factory.Markup("btn") } + new KeyValuePair("class", factory.Markup("btn")) })), availableDescriptorsText }, @@ -1080,9 +1080,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "th:myth", - attributes: new Dictionary + attributes: new List> { - { "class", factory.Markup("btn") } + new KeyValuePair("class", factory.Markup("btn")) }, children: factory.Markup("words and spaces"))), availableDescriptorsColon @@ -1092,9 +1092,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "PREFIXmyth", - attributes: new Dictionary + attributes: new List> { - { "class", factory.Markup("btn") } + new KeyValuePair("class", factory.Markup("btn")) }, children: factory.Markup("words and spaces"))), availableDescriptorsText @@ -1105,17 +1105,19 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "th:myth2", selfClosing: true, - attributes: new Dictionary + attributes: new List> { { - "bound", - new MarkupBlock( + new KeyValuePair( + "bound", new MarkupBlock( - new ExpressionBlock( - factory.CodeTransition(), - factory.Code("DateTime.Now") - .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) - .Accepts(AcceptedCharacters.NonWhiteSpace)))) } + new MarkupBlock( + new ExpressionBlock( + factory.CodeTransition(), + factory.Code("DateTime.Now") + .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) + .Accepts(AcceptedCharacters.NonWhiteSpace))))) + } })), availableDescriptorsColon }, @@ -1125,17 +1127,19 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "PREFIXmyth2", selfClosing: true, - attributes: new Dictionary + attributes: new List> { { - "bound", - new MarkupBlock( + new KeyValuePair( + "bound", new MarkupBlock( - new ExpressionBlock( - factory.CodeTransition(), - factory.Code("DateTime.Now") - .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) - .Accepts(AcceptedCharacters.NonWhiteSpace)))) } + new MarkupBlock( + new ExpressionBlock( + factory.CodeTransition(), + factory.Code("DateTime.Now") + .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) + .Accepts(AcceptedCharacters.NonWhiteSpace))))) + } })), availableDescriptorsText }, @@ -1180,9 +1184,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "myth", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - { "bound", new MarkupBlock() } + new KeyValuePair("bound", new MarkupBlock()) })), new[] { @@ -1197,9 +1201,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "myth", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - { "bound", factory.CodeMarkup(" true") } + new KeyValuePair("bound", factory.CodeMarkup(" true")) })), new RazorError[0] }, @@ -1209,9 +1213,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "myth", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - { "bound", factory.CodeMarkup(" ") } + new KeyValuePair("bound", factory.CodeMarkup(" ")) })), new[] { @@ -1226,9 +1230,10 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "myth", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - { "bound", new MarkupBlock() } + new KeyValuePair("bound", new MarkupBlock()), + new KeyValuePair("bound", new MarkupBlock()) })), new[] { @@ -1246,9 +1251,10 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "myth", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - { "bound", factory.CodeMarkup(" ") } + new KeyValuePair("bound", factory.CodeMarkup(" ")), + new KeyValuePair("bound", factory.CodeMarkup(" ")) })), new[] { @@ -1266,9 +1272,10 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "myth", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - { "bound", factory.CodeMarkup(string.Empty).With(SpanCodeGenerator.Null) } + new KeyValuePair("bound", factory.CodeMarkup("true")), + new KeyValuePair("bound", factory.CodeMarkup(string.Empty).With(SpanCodeGenerator.Null)) })), new[] { @@ -1283,10 +1290,10 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "myth", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - { "bound", factory.CodeMarkup(string.Empty).With(SpanCodeGenerator.Null) }, - { "name", new MarkupBlock() } + new KeyValuePair("bound", factory.CodeMarkup(string.Empty).With(SpanCodeGenerator.Null)), + new KeyValuePair("name", new MarkupBlock()) })), new[] { @@ -1301,10 +1308,10 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "myth", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - { "bound", factory.CodeMarkup(string.Empty).With(SpanCodeGenerator.Null) }, - { "name", factory.Markup(" ") } + new KeyValuePair("bound", factory.CodeMarkup(string.Empty).With(SpanCodeGenerator.Null)), + new KeyValuePair("name", factory.Markup(" ")) })), new[] { @@ -1319,10 +1326,12 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "myth", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - { "bound", factory.CodeMarkup(string.Empty).With(SpanCodeGenerator.Null) }, - { "name", factory.Markup(string.Empty).With(SpanCodeGenerator.Null) } + new KeyValuePair("bound", factory.CodeMarkup("true")), + new KeyValuePair("name", factory.Markup("john")), + new KeyValuePair("bound", factory.CodeMarkup(string.Empty).With(SpanCodeGenerator.Null)), + new KeyValuePair("name", factory.Markup(string.Empty).With(SpanCodeGenerator.Null)) })), new[] { @@ -1337,9 +1346,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "myth", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - { "BouND", new MarkupBlock() } + new KeyValuePair("BouND", new MarkupBlock()) })), new[] { @@ -1354,9 +1363,10 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "myth", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - { "BOUND", new MarkupBlock() } + new KeyValuePair("BOUND", new MarkupBlock()), + new KeyValuePair("bOUnd", new MarkupBlock()) })), new[] { @@ -1373,10 +1383,10 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock( "myth", - new Dictionary + new List> { - { "BOUND", factory.CodeMarkup(string.Empty).With(SpanCodeGenerator.Null) }, - { "nAMe", factory.Markup("john") } + new KeyValuePair("BOUND", factory.CodeMarkup(string.Empty).With(SpanCodeGenerator.Null)), + new KeyValuePair("nAMe", factory.Markup("john")) })), new[] { @@ -1391,19 +1401,20 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "myth", selfClosing: true, - attributes: new Dictionary + attributes: new List> { { - "bound", - new MarkupBlock( + new KeyValuePair( + "bound", new MarkupBlock( - factory.Markup(" "), - new ExpressionBlock( - factory.CodeTransition(), - factory.Code("true") - .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) - .Accepts(AcceptedCharacters.NonWhiteSpace))), - factory.Markup(" ")) + new MarkupBlock( + factory.Markup(" "), + new ExpressionBlock( + factory.CodeTransition(), + factory.Code("true") + .AsImplicitExpression(CSharpCodeParser.DefaultKeywords) + .Accepts(AcceptedCharacters.NonWhiteSpace))), + factory.Markup(" "))) } })), new RazorError[0] @@ -1414,19 +1425,20 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupTagHelperBlock( "myth", selfClosing: true, - attributes: new Dictionary + attributes: new List> { { - "bound", - new MarkupBlock( + new KeyValuePair( + "bound", new MarkupBlock( - factory.Markup(" "), - new ExpressionBlock( - factory.CodeTransition(), - factory.MetaCode("(").Accepts(AcceptedCharacters.None), - factory.Code("true").AsExpression(), - factory.MetaCode(")").Accepts(AcceptedCharacters.None))), - factory.Markup(" ")) + new MarkupBlock( + factory.Markup(" "), + new ExpressionBlock( + factory.CodeTransition(), + factory.MetaCode("(").Accepts(AcceptedCharacters.None), + factory.Code("true").AsExpression(), + factory.MetaCode(")").Accepts(AcceptedCharacters.None))), + factory.Markup(" "))) } })), new RazorError[0] @@ -3116,29 +3128,31 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers "

", new MarkupBlock( new MarkupTagHelperBlock("p", - new Dictionary + new List> { - { "class", new MarkupBlock() } + new KeyValuePair("class", new MarkupBlock()) })) }, { "

", new MarkupBlock( new MarkupTagHelperBlock("p", - new Dictionary + new List> { - { "class", new MarkupBlock() } + new KeyValuePair("class", new MarkupBlock()) })) }, { "

", new MarkupBlock( new MarkupTagHelperBlock("p", - new Dictionary + new List> { // We expected a markup node here because attribute values without quotes can only ever // be a single item, hence don't need to be enclosed by a block. - { "class", factory.Markup("").With(SpanCodeGenerator.Null) }, + new KeyValuePair( + "class", + factory.Markup("").With(SpanCodeGenerator.Null)), })) }, { @@ -3146,11 +3160,13 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock("p", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - { "class1", new MarkupBlock() }, - { "class2", factory.Markup("").With(SpanCodeGenerator.Null) }, - { "class3", new MarkupBlock() }, + new KeyValuePair("class1", new MarkupBlock()), + new KeyValuePair( + "class2", + factory.Markup("").With(SpanCodeGenerator.Null)), + new KeyValuePair("class3", new MarkupBlock()), })) }, { @@ -3158,11 +3174,13 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers new MarkupBlock( new MarkupTagHelperBlock("p", selfClosing: true, - attributes: new Dictionary + attributes: new List> { - { "class1", new MarkupBlock() }, - { "class2", new MarkupBlock() }, - { "class3", factory.Markup("").With(SpanCodeGenerator.Null) }, + new KeyValuePair("class1", new MarkupBlock()), + new KeyValuePair("class2", new MarkupBlock()), + new KeyValuePair( + "class3", + factory.Markup("").With(SpanCodeGenerator.Null)), })) }, }; @@ -3209,7 +3227,7 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers "

", new MarkupBlock( new MarkupTagHelperBlock("p", - new Dictionary())), + new List>())), new [] { new RazorError( @@ -3221,9 +3239,9 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers "

", new MarkupBlock( new MarkupTagHelperBlock("p", - new Dictionary + new List> { - { "bar", factory.Markup("false") } + new KeyValuePair("bar", factory.Markup("false")) })), new [] { @@ -3236,9 +3254,11 @@ namespace Microsoft.AspNet.Razor.Test.TagHelpers "