Skip to content

Commit

Permalink
Create AddMultipleAttributes
Browse files Browse the repository at this point in the history
  • Loading branch information
Ryan Nowak committed May 17, 2019
1 parent d99b074 commit 1b2fb76
Show file tree
Hide file tree
Showing 2 changed files with 220 additions and 0 deletions.
28 changes: 28 additions & 0 deletions src/Components/Components/src/RenderTree/RenderTreeBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,34 @@ public void AddAttribute(int sequence, in RenderTreeFrame frame)
Append(frame.WithAttributeSequence(sequence));
}

/// <summary>
/// Adds frames representing multiple attributes with the same sequence number.
/// </summary>
/// <typeparam name="T">The attribute value type.</typeparam>
/// <param name="sequence">An integer that represents the position of the instruction in the source code.</param>
/// <param name="attributes">A collection of key-value pairs representing attributes.</param>
public void AddMultipleAttributes<T>(int sequence, IEnumerable<KeyValuePair<string, T>> attributes)
{
// NOTE: The IEnumerable<KeyValuePair<string, T>> is the simplest way to support a variety of
// different types like IReadOnlyDictionary<>, Dictionary<>, and IDictionary<>.
//
// None of those types are contravariant, and since we want to support attributes having a value
// of type object, the simplest thing to do is drop down to IEnumerable<KeyValuePair<>> which
// is contravariant. This also gives us things like List<KeyValuePair<>> and KeyValuePair<>[]
// for free even though we don't expect those types to be common.

// Calling this up-front just to make sure we validate before mutating anything.
AssertCanAddAttribute();

if (attributes != null)
{
foreach (var attribute in attributes)
{
AddAttribute(sequence, attribute.Key, attribute.Value);
}
}
}

/// <summary>
/// Appends a frame representing a child component.
/// </summary>
Expand Down
192 changes: 192 additions & 0 deletions src/Components/Components/test/RenderTreeBuilderTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Microsoft.AspNetCore.Components.RenderTree;
using Microsoft.AspNetCore.Components.Test.Helpers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
Expand Down Expand Up @@ -245,6 +246,197 @@ public void CanAddAttributes()
frame => AssertFrame.Text(frame, "some text"));
}

[Fact]
public void CanAddMultipleAttributes_AllowsNull()
{
// Arrange
var builder = new RenderTreeBuilder(new TestRenderer());

// Act
builder.OpenElement(0, "myelement");
builder.AddMultipleAttributes<object>(0, null);
builder.CloseElement();

// Assert
var frames = builder.GetFrames().AsEnumerable().ToArray();
Assert.Collection(
frames,
frame => AssertFrame.Element(frame, "myelement", 1));
}

[Fact]
public void CanAddMultipleAttributes_InterspersedWithOtherAttributes()
{
// Arrange
var builder = new RenderTreeBuilder(new TestRenderer());
Action<UIEventArgs> eventHandler = eventInfo => { };

// Act
builder.OpenElement(0, "myelement");
builder.AddAttribute(0, "attribute1", "value 1");
builder.AddMultipleAttributes(0, new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase)
{
{ "attribute1", "test1" },
{ "attribute2", true },
{ "attribute3", eventHandler },
});
builder.AddAttribute(0, "attribute2", false);
builder.AddMultipleAttributes(0, new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase)
{
{ "attribute4", "test4" },
{ "attribute5", false },
{ "attribute6", eventHandler },
});
builder.AddAttribute(0, "attribute7", "the end");
builder.CloseElement();

// Assert
var frames = builder.GetFrames().AsEnumerable().ToArray();
Assert.Collection(
frames,
frame => AssertFrame.Element(frame, "myelement", 8),
frame => AssertFrame.Attribute(frame, "attribute1", "value 1"),
frame => AssertFrame.Attribute(frame, "attribute1", "test1"),
frame => AssertFrame.Attribute(frame, "attribute2", true),
frame => AssertFrame.Attribute(frame, "attribute3", eventHandler),
frame => AssertFrame.Attribute(frame, "attribute4", "test4"),
frame => AssertFrame.Attribute(frame, "attribute6", eventHandler),
frame => AssertFrame.Attribute(frame, "attribute7", "the end"));
}

[Fact]
public void CanAddMultipleAttributes_DictionaryString()
{
var attributes = new Dictionary<string, string>
{
{ "attribute1", "test1" },
{ "attribute2", "123" },
{ "attribute3", "456" },
};

// Act & Assert
CanAddMultipleAttributesTest(attributes);
}

[Fact]
public void CanAddMultipleAttributes_DictionaryObject()
{
var attributes = new Dictionary<string, object>
{
{ "attribute1", "test1" },
{ "attribute2", "123" },
{ "attribute3", true },
};

// Act & Assert
CanAddMultipleAttributesTest(attributes);
}

[Fact]
public void CanAddMultipleAttributes_IReadOnlyDictionaryString()
{
var attributes = new Dictionary<string, string>
{
{ "attribute1", "test1" },
{ "attribute2", "123" },
{ "attribute3", "456" },
};

// Act & Assert
CanAddMultipleAttributesTest((IReadOnlyDictionary<string, string>)attributes);
}

[Fact]
public void CanAddMultipleAttributes_IReadOnlyDictionaryObject()
{
var attributes = new Dictionary<string, object>
{
{ "attribute1", "test1" },
{ "attribute2", "123" },
{ "attribute3", true },
};

// Act & Assert
CanAddMultipleAttributesTest((IReadOnlyDictionary<string, object>)attributes);
}

[Fact]
public void CanAddMultipleAttributes_ListKvpString()
{
var attributes = new List<KeyValuePair<string, object>>()
{
new KeyValuePair<string, object>("attribute1", "test1"),
new KeyValuePair<string, object>("attribute2", "123"),
new KeyValuePair<string, object>("attribute3", "456"),
};

// Act & Assert
CanAddMultipleAttributesTest(attributes);
}

[Fact]
public void CanAddMultipleAttributes_ListKvpObject()
{
var attributes = new List<KeyValuePair<string, object>>()
{
new KeyValuePair<string, object>("attribute1", "test1"),
new KeyValuePair<string, object>("attribute2", "123"),
new KeyValuePair<string, object>("attribute3", true),
};

// Act & Assert
CanAddMultipleAttributesTest(attributes);
}

[Fact]
public void CanAddMultipleAttributes_ArrayKvpString()
{
var attributes = new KeyValuePair<string, string>[]
{
new KeyValuePair<string, string>("attribute1", "test1"),
new KeyValuePair<string, string>("attribute2", "123"),
new KeyValuePair<string, string>("attribute3", "456"),
};

// Act & Assert
CanAddMultipleAttributesTest(attributes);
}

[Fact]
public void CanAddMultipleAttributes_ArrayKvpObject()
{
var attributes = new KeyValuePair<string, object>[]
{
new KeyValuePair<string, object>("attribute1", "test1"),
new KeyValuePair<string, object>("attribute2", "123"),
new KeyValuePair<string, object>("attribute3", true),
};

// Act & Assert
CanAddMultipleAttributesTest(attributes);
}

private void CanAddMultipleAttributesTest<T>(IEnumerable<KeyValuePair<string, T>> attributes)
{
// Arrange
var builder = new RenderTreeBuilder(new TestRenderer());

// Act
builder.OpenElement(0, "myelement");
builder.AddMultipleAttributes(0, attributes);
builder.CloseElement();

// Assert
var frames = builder.GetFrames().AsEnumerable().ToArray();

var i = 1;
foreach (var attribute in attributes)
{
var frame = frames[i++];
AssertFrame.Attribute(frame, attribute.Key, attribute.Value);
}
}

[Fact]
public void CannotAddAttributeAtRoot()
{
Expand Down

0 comments on commit 1b2fb76

Please sign in to comment.