public void CanConvertToReadOnlyDictionary() { // Arrange var entry2Value = new object(); var parameterCollection = new ParameterCollection(new[] { RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(3), RenderTreeFrame.Attribute(0, "entry 1", "value 1"), RenderTreeFrame.Attribute(0, "entry 2", entry2Value), }, 0); // Act IReadOnlyDictionary <string, object> dict = parameterCollection.ToDictionary(); // Assert Assert.Collection(dict, entry => { Assert.Equal("entry 1", entry.Key); Assert.Equal("value 1", entry.Value); }, entry => { Assert.Equal("entry 2", entry.Key); Assert.Same(entry2Value, entry.Value); }); }
public void RenderComponentAsync_CanPassParameters() { // Arrange var expectedHtml = new[] { "<", "p", ">", "<", "input", " ", "value", "=", "\"", "5", "\"", " />", "</", "p", ">" }; RenderFragment Content(ParameterCollection pc) => new RenderFragment((RenderTreeBuilder rtb) => { rtb.OpenElement(0, "p"); rtb.OpenElement(1, "input"); rtb.AddAttribute(2, "change", pc.GetValueOrDefault <Action <UIChangeEventArgs> >("update")); rtb.AddAttribute(3, "value", pc.GetValueOrDefault <int>("value")); rtb.CloseElement(); rtb.CloseElement(); }); var serviceProvider = new ServiceCollection() .AddSingleton(new Func <ParameterCollection, RenderFragment>(Content)) .BuildServiceProvider(); var htmlRenderer = GetHtmlRenderer(serviceProvider); Action <UIChangeEventArgs> change = (UIChangeEventArgs changeArgs) => throw new InvalidOperationException(); // Act var result = GetResult(Dispatcher.InvokeAsync(() => htmlRenderer.RenderComponentAsync <ComponentWithParameters>( new ParameterCollection(new[] { RenderTreeFrame.Element(0, string.Empty), RenderTreeFrame.Attribute(1, "update", change), RenderTreeFrame.Attribute(2, "value", 5) }, 0)))); // Assert Assert.Equal(expectedHtml, result); }
public void CanGetValueOrDefault_WithNonExistingValue() { // Arrange var parameterCollection = new ParameterCollection(new[] { RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2), RenderTreeFrame.Attribute(1, "some other entry", new object()) }, 0); // Act var result = parameterCollection.GetValueOrDefault <DateTime>("nonexisting entry"); // Assert Assert.Equal(default, result);
public void ThrowsIfTryGetExistingValueWithIncorrectType() { // Arrange var parameterCollection = new ParameterCollection(new[] { RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2), RenderTreeFrame.Attribute(1, "my entry", "hello") }, 0); // Act/Assert Assert.Throws <InvalidCastException>(() => { parameterCollection.TryGetValue <bool>("my entry", out var value); }); }
public void CanTryGetExistingValueWithCorrectType() { // Arrange var parameterCollection = new ParameterCollection(new[] { RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2), RenderTreeFrame.Attribute(1, "my entry", "hello") }, 0); // Act var didFind = parameterCollection.TryGetValue <string>("my entry", out var value); // Assert Assert.True(didFind); Assert.Equal("hello", value); }
public void CanTryGetNonExistingValue() { // Arrange var parameterCollection = new ParameterCollection(new[] { RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2), RenderTreeFrame.Attribute(1, "some other entry", new object()) }, 0); // Act var didFind = parameterCollection.TryGetValue <string>("nonexisting entry", out var value); // Assert Assert.False(didFind); Assert.Null(value); }
public void CanGetValueOrDefault_WithExistingValue() { // Arrange var myEntryValue = new object(); var parameterCollection = new ParameterCollection(new[] { RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2), RenderTreeFrame.Attribute(1, "my entry", myEntryValue), RenderTreeFrame.Attribute(1, "my other entry", new object()) }, 0); // Act var result = parameterCollection.GetValueOrDefault <object>("my entry"); // Assert Assert.Same(myEntryValue, result); }
public void CanGetValueOrDefault_WithNonExistingValue() { // Arrange var parameters = new ParameterView(ParameterViewLifetime.Unbound, new[] { RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2), RenderTreeFrame.Attribute(1, "some other entry", new object()) }, 0).WithCascadingParameters(new List <CascadingParameterState> { new CascadingParameterState("another entry", new TestCascadingValue(null)) }); // Act var result = parameters.GetValueOrDefault <DateTime>("nonexisting entry"); // Assert Assert.Equal(default, result);
public void CanGetValueOrDefault_WithMultipleMatchingValues() { // Arrange var myEntryValue = new object(); var parameterCollection = new ParameterCollection(new[] { RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(3), RenderTreeFrame.Attribute(1, "my entry", myEntryValue), RenderTreeFrame.Attribute(1, "my entry", new object()), }, 0); // Act var result = parameterCollection.GetValueOrDefault <object>("my entry"); // Assert: Picks first match Assert.Same(myEntryValue, result); }
/// <summary> /// Handles async click events by invoking the async <paramref name="handler"/> /// </summary> /// <param name="handler">The async handler to be invoked when the event occurs.</param> /// <returns></returns> protected RenderTreeFrame onclickAsync(Func <Task> handler) { return(RenderTreeFrame.Attribute(0, "onclick", _ => { // Run handler and handle any exceptions when any occurs. handler().ContinueWith(task => { if (task.Exception == null) { StateHasChanged(); } else { HandleException(task.Exception); } }); })); }
public void EnumerationStopsAtEndOfOwnerAttributes() { // Arrange var attribute1Value = new object(); var attribute2Value = new object(); var frames = new[] { RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(3), RenderTreeFrame.Attribute(1, "attribute 1", attribute1Value), RenderTreeFrame.Attribute(2, "attribute 2", attribute2Value), RenderTreeFrame.Element(3, "child element").WithElementSubtreeLength(2), RenderTreeFrame.Attribute(4, "child attribute", "some value") }; var parameterCollection = new ParameterCollection(frames, 0); // Assert Assert.Collection(ToEnumerable(parameterCollection), AssertParameter("attribute 1", attribute1Value), AssertParameter("attribute 2", attribute2Value)); }
public void EnumerationIncludesCascadingParameters() { // Arrange var attribute1Value = new object(); var attribute2Value = new object(); var attribute3Value = new object(); var parameterCollection = new ParameterCollection(new[] { RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(2), RenderTreeFrame.Attribute(1, "attribute 1", attribute1Value) }, 0).WithCascadingParameters(new List <CascadingParameterState> { new CascadingParameterState("attribute 2", new TestCascadingValue(attribute2Value)), new CascadingParameterState("attribute 3", new TestCascadingValue(attribute3Value)), }); // Assert Assert.Collection(ToEnumerable(parameterCollection), AssertParameter("attribute 1", attribute1Value), AssertParameter("attribute 2", attribute2Value), AssertParameter("attribute 3", attribute3Value)); }
public void EnumerationStopsAtEndOfOwnerDescendants() { // Arrange var attribute1Value = new object(); var attribute2Value = new object(); var frames = new[] { RenderTreeFrame.Element(0, "some element").WithElementSubtreeLength(3), RenderTreeFrame.Attribute(1, "attribute 1", attribute1Value), RenderTreeFrame.Attribute(2, "attribute 2", attribute2Value), // Although RenderTreeBuilder doesn't let you add orphaned attributes like this, // still want to verify that ParameterCollection doesn't attempt to read past the // end of the owner's descendants RenderTreeFrame.Attribute(3, "orphaned attribute", "value") }; var parameterCollection = new ParameterCollection(frames, 0); // Assert Assert.Collection(ToEnumerable(parameterCollection), AssertParameter("attribute 1", attribute1Value), AssertParameter("attribute 2", attribute2Value)); }
/// <summary> /// Handles click events by invoking <paramref name="handler"/>. /// </summary> /// <param name="handler">The handler to be invoked when the event occurs.</param> /// <returns>A <see cref="RenderTreeFrame"/> that represents the event handler.</returns> protected RenderTreeFrame onclick(Action handler) // Note that the 'sequence' value is updated later when inserted into the tree => RenderTreeFrame.Attribute(0, "onclick", _ => handler());
private static ArrayRange <RenderTreeFrame> ReadReferenceFrames(ReadOnlySpan <byte> data, string[] strings) { var result = new RenderTreeFrame[data.Length / ReferenceFrameSize]; for (var i = 0; i < data.Length; i += ReferenceFrameSize) { var frameData = data.Slice(i, ReferenceFrameSize); var type = (RenderTreeFrameType)BitConverter.ToInt32(frameData.Slice(0, 4)); // We want each frame to take up the same number of bytes, so that the // recipient can index into the array directly instead of having to // walk through it. // Since we can fit every frame type into 16 bytes, use that as the // common size. For smaller frames, we add padding to expand it to // 16 bytes. switch (type) { case RenderTreeFrameType.Attribute: var attributeName = ReadString(frameData.Slice(4, 4), strings); var attributeValue = ReadString(frameData.Slice(8, 4), strings); var attributeEventHandlerId = BitConverter.ToUInt64(frameData.Slice(12, 8)); result[i / ReferenceFrameSize] = RenderTreeFrame.Attribute(0, attributeName, attributeValue).WithAttributeEventHandlerId(attributeEventHandlerId); break; case RenderTreeFrameType.Component: var componentSubtreeLength = BitConverter.ToInt32(frameData.Slice(4, 4)); var componentId = BitConverter.ToInt32(frameData.Slice(8, 4)); // Nowhere to put this without creating a ComponentState result[i / ReferenceFrameSize] = RenderTreeFrame.ChildComponent(0, componentType: null) .WithComponentSubtreeLength(componentSubtreeLength) .WithComponent(new ComponentState(Renderer, componentId, new FakeComponent(), null)); break; case RenderTreeFrameType.ComponentReferenceCapture: // Client doesn't process these, skip. result[i / ReferenceFrameSize] = RenderTreeFrame.ComponentReferenceCapture(0, null, 0); break; case RenderTreeFrameType.Element: var elementSubtreeLength = BitConverter.ToInt32(frameData.Slice(4, 4)); var elementName = ReadString(frameData.Slice(8, 4), strings); result[i / ReferenceFrameSize] = RenderTreeFrame.Element(0, elementName).WithElementSubtreeLength(elementSubtreeLength); break; case RenderTreeFrameType.ElementReferenceCapture: var referenceCaptureId = ReadString(frameData.Slice(4, 4), strings); result[i / ReferenceFrameSize] = RenderTreeFrame.ElementReferenceCapture(0, null) .WithElementReferenceCaptureId(referenceCaptureId); break; case RenderTreeFrameType.Region: var regionSubtreeLength = BitConverter.ToInt32(frameData.Slice(4, 4)); result[i / ReferenceFrameSize] = RenderTreeFrame.Region(0).WithRegionSubtreeLength(regionSubtreeLength); break; case RenderTreeFrameType.Text: var text = ReadString(frameData.Slice(4, 4), strings); result[i / ReferenceFrameSize] = RenderTreeFrame.Text(0, text); break; case RenderTreeFrameType.Markup: var markup = ReadString(frameData.Slice(4, 4), strings); result[i / ReferenceFrameSize] = RenderTreeFrame.Markup(0, markup); break; default: throw new ArgumentException($"Unsupported frame type: {type}"); } } return(new ArrayRange <RenderTreeFrame>(result, result.Length)); }
/// <summary> /// Adds a parameter. /// </summary> /// <param name="name">The name of the parameter.</param> /// <param name="value">The value of the parameter.</param> public void Add(string name, object?value) { var nextIndex = _frames[0].ElementSubtreeLengthField++; _frames[nextIndex] = RenderTreeFrame.Attribute(0, name, value); }
/// <summary> /// Handles change events by invoking <paramref name="handler"/>. /// </summary> /// <param name="handler">The handler to be invoked when the event occurs. The handler will receive the new value as a parameter.</param> /// <returns>A <see cref="RenderTreeFrame"/> that represents the event handler.</returns> protected RenderTreeFrame onchange(Action <object> handler) // Note that the 'sequence' value is updated later when inserted into the tree => RenderTreeFrame.Attribute(0, "onchange", args => handler(((UIChangeEventArgs)args).Value));