Skip to content

Commit 1b2fb76

Browse files
author
Ryan Nowak
committed
Create AddMultipleAttributes
1 parent d99b074 commit 1b2fb76

File tree

2 files changed

+220
-0
lines changed

2 files changed

+220
-0
lines changed

src/Components/Components/src/RenderTree/RenderTreeBuilder.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,34 @@ public void AddAttribute(int sequence, in RenderTreeFrame frame)
425425
Append(frame.WithAttributeSequence(sequence));
426426
}
427427

428+
/// <summary>
429+
/// Adds frames representing multiple attributes with the same sequence number.
430+
/// </summary>
431+
/// <typeparam name="T">The attribute value type.</typeparam>
432+
/// <param name="sequence">An integer that represents the position of the instruction in the source code.</param>
433+
/// <param name="attributes">A collection of key-value pairs representing attributes.</param>
434+
public void AddMultipleAttributes<T>(int sequence, IEnumerable<KeyValuePair<string, T>> attributes)
435+
{
436+
// NOTE: The IEnumerable<KeyValuePair<string, T>> is the simplest way to support a variety of
437+
// different types like IReadOnlyDictionary<>, Dictionary<>, and IDictionary<>.
438+
//
439+
// None of those types are contravariant, and since we want to support attributes having a value
440+
// of type object, the simplest thing to do is drop down to IEnumerable<KeyValuePair<>> which
441+
// is contravariant. This also gives us things like List<KeyValuePair<>> and KeyValuePair<>[]
442+
// for free even though we don't expect those types to be common.
443+
444+
// Calling this up-front just to make sure we validate before mutating anything.
445+
AssertCanAddAttribute();
446+
447+
if (attributes != null)
448+
{
449+
foreach (var attribute in attributes)
450+
{
451+
AddAttribute(sequence, attribute.Key, attribute.Value);
452+
}
453+
}
454+
}
455+
428456
/// <summary>
429457
/// Appends a frame representing a child component.
430458
/// </summary>

src/Components/Components/test/RenderTreeBuilderTest.cs

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Microsoft.AspNetCore.Components.RenderTree;
77
using Microsoft.AspNetCore.Components.Test.Helpers;
88
using System;
9+
using System.Collections.Generic;
910
using System.Linq;
1011
using System.Threading.Tasks;
1112
using Xunit;
@@ -245,6 +246,197 @@ public void CanAddAttributes()
245246
frame => AssertFrame.Text(frame, "some text"));
246247
}
247248

249+
[Fact]
250+
public void CanAddMultipleAttributes_AllowsNull()
251+
{
252+
// Arrange
253+
var builder = new RenderTreeBuilder(new TestRenderer());
254+
255+
// Act
256+
builder.OpenElement(0, "myelement");
257+
builder.AddMultipleAttributes<object>(0, null);
258+
builder.CloseElement();
259+
260+
// Assert
261+
var frames = builder.GetFrames().AsEnumerable().ToArray();
262+
Assert.Collection(
263+
frames,
264+
frame => AssertFrame.Element(frame, "myelement", 1));
265+
}
266+
267+
[Fact]
268+
public void CanAddMultipleAttributes_InterspersedWithOtherAttributes()
269+
{
270+
// Arrange
271+
var builder = new RenderTreeBuilder(new TestRenderer());
272+
Action<UIEventArgs> eventHandler = eventInfo => { };
273+
274+
// Act
275+
builder.OpenElement(0, "myelement");
276+
builder.AddAttribute(0, "attribute1", "value 1");
277+
builder.AddMultipleAttributes(0, new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase)
278+
{
279+
{ "attribute1", "test1" },
280+
{ "attribute2", true },
281+
{ "attribute3", eventHandler },
282+
});
283+
builder.AddAttribute(0, "attribute2", false);
284+
builder.AddMultipleAttributes(0, new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase)
285+
{
286+
{ "attribute4", "test4" },
287+
{ "attribute5", false },
288+
{ "attribute6", eventHandler },
289+
});
290+
builder.AddAttribute(0, "attribute7", "the end");
291+
builder.CloseElement();
292+
293+
// Assert
294+
var frames = builder.GetFrames().AsEnumerable().ToArray();
295+
Assert.Collection(
296+
frames,
297+
frame => AssertFrame.Element(frame, "myelement", 8),
298+
frame => AssertFrame.Attribute(frame, "attribute1", "value 1"),
299+
frame => AssertFrame.Attribute(frame, "attribute1", "test1"),
300+
frame => AssertFrame.Attribute(frame, "attribute2", true),
301+
frame => AssertFrame.Attribute(frame, "attribute3", eventHandler),
302+
frame => AssertFrame.Attribute(frame, "attribute4", "test4"),
303+
frame => AssertFrame.Attribute(frame, "attribute6", eventHandler),
304+
frame => AssertFrame.Attribute(frame, "attribute7", "the end"));
305+
}
306+
307+
[Fact]
308+
public void CanAddMultipleAttributes_DictionaryString()
309+
{
310+
var attributes = new Dictionary<string, string>
311+
{
312+
{ "attribute1", "test1" },
313+
{ "attribute2", "123" },
314+
{ "attribute3", "456" },
315+
};
316+
317+
// Act & Assert
318+
CanAddMultipleAttributesTest(attributes);
319+
}
320+
321+
[Fact]
322+
public void CanAddMultipleAttributes_DictionaryObject()
323+
{
324+
var attributes = new Dictionary<string, object>
325+
{
326+
{ "attribute1", "test1" },
327+
{ "attribute2", "123" },
328+
{ "attribute3", true },
329+
};
330+
331+
// Act & Assert
332+
CanAddMultipleAttributesTest(attributes);
333+
}
334+
335+
[Fact]
336+
public void CanAddMultipleAttributes_IReadOnlyDictionaryString()
337+
{
338+
var attributes = new Dictionary<string, string>
339+
{
340+
{ "attribute1", "test1" },
341+
{ "attribute2", "123" },
342+
{ "attribute3", "456" },
343+
};
344+
345+
// Act & Assert
346+
CanAddMultipleAttributesTest((IReadOnlyDictionary<string, string>)attributes);
347+
}
348+
349+
[Fact]
350+
public void CanAddMultipleAttributes_IReadOnlyDictionaryObject()
351+
{
352+
var attributes = new Dictionary<string, object>
353+
{
354+
{ "attribute1", "test1" },
355+
{ "attribute2", "123" },
356+
{ "attribute3", true },
357+
};
358+
359+
// Act & Assert
360+
CanAddMultipleAttributesTest((IReadOnlyDictionary<string, object>)attributes);
361+
}
362+
363+
[Fact]
364+
public void CanAddMultipleAttributes_ListKvpString()
365+
{
366+
var attributes = new List<KeyValuePair<string, object>>()
367+
{
368+
new KeyValuePair<string, object>("attribute1", "test1"),
369+
new KeyValuePair<string, object>("attribute2", "123"),
370+
new KeyValuePair<string, object>("attribute3", "456"),
371+
};
372+
373+
// Act & Assert
374+
CanAddMultipleAttributesTest(attributes);
375+
}
376+
377+
[Fact]
378+
public void CanAddMultipleAttributes_ListKvpObject()
379+
{
380+
var attributes = new List<KeyValuePair<string, object>>()
381+
{
382+
new KeyValuePair<string, object>("attribute1", "test1"),
383+
new KeyValuePair<string, object>("attribute2", "123"),
384+
new KeyValuePair<string, object>("attribute3", true),
385+
};
386+
387+
// Act & Assert
388+
CanAddMultipleAttributesTest(attributes);
389+
}
390+
391+
[Fact]
392+
public void CanAddMultipleAttributes_ArrayKvpString()
393+
{
394+
var attributes = new KeyValuePair<string, string>[]
395+
{
396+
new KeyValuePair<string, string>("attribute1", "test1"),
397+
new KeyValuePair<string, string>("attribute2", "123"),
398+
new KeyValuePair<string, string>("attribute3", "456"),
399+
};
400+
401+
// Act & Assert
402+
CanAddMultipleAttributesTest(attributes);
403+
}
404+
405+
[Fact]
406+
public void CanAddMultipleAttributes_ArrayKvpObject()
407+
{
408+
var attributes = new KeyValuePair<string, object>[]
409+
{
410+
new KeyValuePair<string, object>("attribute1", "test1"),
411+
new KeyValuePair<string, object>("attribute2", "123"),
412+
new KeyValuePair<string, object>("attribute3", true),
413+
};
414+
415+
// Act & Assert
416+
CanAddMultipleAttributesTest(attributes);
417+
}
418+
419+
private void CanAddMultipleAttributesTest<T>(IEnumerable<KeyValuePair<string, T>> attributes)
420+
{
421+
// Arrange
422+
var builder = new RenderTreeBuilder(new TestRenderer());
423+
424+
// Act
425+
builder.OpenElement(0, "myelement");
426+
builder.AddMultipleAttributes(0, attributes);
427+
builder.CloseElement();
428+
429+
// Assert
430+
var frames = builder.GetFrames().AsEnumerable().ToArray();
431+
432+
var i = 1;
433+
foreach (var attribute in attributes)
434+
{
435+
var frame = frames[i++];
436+
AssertFrame.Attribute(frame, attribute.Key, attribute.Value);
437+
}
438+
}
439+
248440
[Fact]
249441
public void CannotAddAttributeAtRoot()
250442
{

0 commit comments

Comments
 (0)