Skip to content

Commit 240ea47

Browse files
committed
moved stuff to core
1 parent a4d587e commit 240ea47

32 files changed

Lines changed: 286 additions & 586 deletions
Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
using System;
22

3-
namespace Bunit
3+
namespace Bunit.Rendering
44
{
5-
/// <summary>
6-
/// Represents an exception that is thrown when a search for a component did not succeed.
7-
/// </summary>
8-
public class ComponentNotFoundException : Exception
9-
{
10-
/// <summary>
11-
/// Creates an instance of the <see cref="ComponentNotFoundException"/> type.
12-
/// </summary>
13-
/// <param name="componentType">The type of component that was not found.</param>
14-
public ComponentNotFoundException(Type componentType) : base($"A component of type {componentType?.Name} was not found in the render tree.")
15-
{
16-
}
17-
}
5+
/// <summary>
6+
/// Represents an exception that is thrown when a search for a component did not succeed.
7+
/// </summary>
8+
public class ComponentNotFoundException : Exception
9+
{
10+
/// <summary>
11+
/// Creates an instance of the <see cref="ComponentNotFoundException"/> type.
12+
/// </summary>
13+
/// <param name="componentType">The type of component that was not found.</param>
14+
public ComponentNotFoundException(Type componentType) : base($"A component of type {componentType?.Name} was not found in the render tree.")
15+
{
16+
}
17+
}
1818
}
Lines changed: 69 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,87 @@
1-
using System;
1+
using System;
22
using System.Diagnostics.CodeAnalysis;
33

4-
namespace Bunit
4+
namespace Bunit.Rendering
55
{
6-
/// <summary>
7-
/// Represents a single parameter supplied to an <see cref="Microsoft.AspNetCore.Components.IComponent"/>
8-
/// component under test.
9-
/// </summary>
10-
[SuppressMessage("Usage", "CA2225:Operator overloads have named alternates", Justification = "<Pending>")]
11-
public readonly struct ComponentParameter : IEquatable<ComponentParameter>
12-
{
13-
/// <summary>
14-
/// Gets the name of the parameter. Can be null if the parameter is for an unnamed cascading value.
15-
/// </summary>
16-
public string? Name { get; }
6+
/// <summary>
7+
/// Represents a single parameter supplied to an <see cref="Microsoft.AspNetCore.Components.IComponent"/>
8+
/// component under test.
9+
/// </summary>
10+
[SuppressMessage("Usage", "CA2225:Operator overloads have named alternates", Justification = "<Pending>")]
11+
public readonly struct ComponentParameter : IEquatable<ComponentParameter>
12+
{
13+
/// <summary>
14+
/// Gets the name of the parameter. Can be null if the parameter is for an unnamed cascading value.
15+
/// </summary>
16+
public string? Name { get; }
1717

18-
/// <summary>
19-
/// Gets the value being supplied to the component.
20-
/// </summary>
21-
public object? Value { get; }
18+
/// <summary>
19+
/// Gets the value being supplied to the component.
20+
/// </summary>
21+
public object? Value { get; }
2222

23-
/// <summary>
24-
/// Gets a value to indicate whether the parameter is for use by a <see cref="Microsoft.AspNetCore.Components.CascadingValue{TValue}"/>.
25-
/// </summary>
26-
public bool IsCascadingValue { get; }
23+
/// <summary>
24+
/// Gets a value to indicate whether the parameter is for use by a <see cref="Microsoft.AspNetCore.Components.CascadingValue{TValue}"/>.
25+
/// </summary>
26+
public bool IsCascadingValue { get; }
2727

28-
private ComponentParameter(string? name, object? value, bool isCascadingValue)
29-
{
30-
if (isCascadingValue && value is null)
31-
throw new ArgumentNullException(nameof(value), "Cascading values cannot be set to null");
28+
private ComponentParameter(string? name, object? value, bool isCascadingValue)
29+
{
30+
if (isCascadingValue && value is null)
31+
throw new ArgumentNullException(nameof(value), "Cascading values cannot be set to null");
3232

33-
if (!isCascadingValue && name is null)
34-
throw new ArgumentNullException(nameof(name), "A parameters name cannot be set to null");
33+
if (!isCascadingValue && name is null)
34+
throw new ArgumentNullException(nameof(name), "A parameters name cannot be set to null");
3535

36-
Name = name;
37-
Value = value;
38-
IsCascadingValue = isCascadingValue;
39-
}
36+
Name = name;
37+
Value = value;
38+
IsCascadingValue = isCascadingValue;
39+
}
4040

41-
/// <summary>
42-
/// Create a parameter for a component under test.
43-
/// </summary>
44-
/// <param name="name">Name of the parameter to pass to the component</param>
45-
/// <param name="value">Value or null to pass the component</param>
46-
public static ComponentParameter CreateParameter(string name, object? value)
47-
=> new ComponentParameter(name, value, false);
41+
/// <summary>
42+
/// Create a parameter for a component under test.
43+
/// </summary>
44+
/// <param name="name">Name of the parameter to pass to the component</param>
45+
/// <param name="value">Value or null to pass the component</param>
46+
public static ComponentParameter CreateParameter(string name, object? value)
47+
=> new ComponentParameter(name, value, false);
4848

49-
/// <summary>
50-
/// Create a Cascading Value parameter for a component under test.
51-
/// </summary>
52-
/// <param name="name">A optional name for the cascading value</param>
53-
/// <param name="value">The cascading value</param>
54-
public static ComponentParameter CreateCascadingValue(string? name, object value)
55-
=> new ComponentParameter(name, value, true);
49+
/// <summary>
50+
/// Create a Cascading Value parameter for a component under test.
51+
/// </summary>
52+
/// <param name="name">A optional name for the cascading value</param>
53+
/// <param name="value">The cascading value</param>
54+
public static ComponentParameter CreateCascadingValue(string? name, object value)
55+
=> new ComponentParameter(name, value, true);
5656

57-
/// <summary>
58-
/// Create a parameter for a component under test.
59-
/// </summary>
60-
/// <param name="input">A name/value pair for the parameter</param>
61-
public static implicit operator ComponentParameter((string name, object? value) input)
62-
=> CreateParameter(input.name, input.value);
57+
/// <summary>
58+
/// Create a parameter for a component under test.
59+
/// </summary>
60+
/// <param name="input">A name/value pair for the parameter</param>
61+
public static implicit operator ComponentParameter((string name, object? value) input)
62+
=> CreateParameter(input.name, input.value);
6363

64-
/// <summary>
65-
/// Create a parameter or cascading value for a component under test.
66-
/// </summary>
67-
/// <param name="input">A name/value/isCascadingValue triple for the parameter</param>
68-
public static implicit operator ComponentParameter((string? name, object? value, bool isCascadingValue) input)
69-
=> new ComponentParameter(input.name, input.value, input.isCascadingValue);
64+
/// <summary>
65+
/// Create a parameter or cascading value for a component under test.
66+
/// </summary>
67+
/// <param name="input">A name/value/isCascadingValue triple for the parameter</param>
68+
public static implicit operator ComponentParameter((string? name, object? value, bool isCascadingValue) input)
69+
=> new ComponentParameter(input.name, input.value, input.isCascadingValue);
7070

71-
/// <inheritdoc/>
72-
public bool Equals(ComponentParameter other)
73-
=> string.Equals(Name, other.Name, StringComparison.Ordinal) && Value == other.Value && IsCascadingValue == other.IsCascadingValue;
71+
/// <inheritdoc/>
72+
public bool Equals(ComponentParameter other)
73+
=> string.Equals(Name, other.Name, StringComparison.Ordinal) && Value == other.Value && IsCascadingValue == other.IsCascadingValue;
7474

75-
/// <inheritdoc/>
76-
public override bool Equals(object obj) => obj is ComponentParameter other && Equals(other);
75+
/// <inheritdoc/>
76+
public override bool Equals(object obj) => obj is ComponentParameter other && Equals(other);
7777

78-
/// <inheritdoc/>
79-
public override int GetHashCode() => HashCode.Combine(Name, Value, IsCascadingValue);
78+
/// <inheritdoc/>
79+
public override int GetHashCode() => HashCode.Combine(Name, Value, IsCascadingValue);
8080

81-
/// <inheritdoc/>
82-
public static bool operator ==(ComponentParameter left, ComponentParameter right) => left.Equals(right);
81+
/// <inheritdoc/>
82+
public static bool operator ==(ComponentParameter left, ComponentParameter right) => left.Equals(right);
8383

84-
/// <inheritdoc/>
85-
public static bool operator !=(ComponentParameter left, ComponentParameter right) => !(left == right);
86-
}
84+
/// <inheritdoc/>
85+
public static bool operator !=(ComponentParameter left, ComponentParameter right) => !(left == right);
86+
}
8787
}
Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using System;
22
using Microsoft.AspNetCore.Components.RenderTree;
33

4-
namespace Bunit
4+
namespace Bunit.Rendering
55
{
66
/// <summary>
77
/// Represents a render event for a <see cref="IRenderedFragmentCore"/> or generally from the <see cref="TestRendererOld"/>.
@@ -31,71 +31,65 @@ public RenderEvent(in RenderBatch renderBatch, TestRenderer renderer)
3131
/// </summary>
3232
/// <param name="renderedFragment">Component to check for updates to.</param>
3333
/// <returns>True if <see cref="RenderEvent"/> contains updates to component, false otherwise.</returns>
34-
public bool HasChangesTo(IRenderedFragmentCore renderedFragment)
35-
=> HasChangesTo((renderedFragment ?? throw new ArgumentNullException(nameof(renderedFragment))).ComponentId);
34+
public bool HasChangesTo(int componentId) => HasChangesToRoot(componentId);
3635

3736
/// <summary>
3837
/// Checks whether the <paramref name="renderedFragment"/> or one or more of
3938
/// its sub components was rendered during the <see cref="RenderEvent"/>.
4039
/// </summary>
4140
/// <param name="renderedFragment">Component to check if rendered.</param>
4241
/// <returns>True if the component or a sub component rendered, false otherwise.</returns>
43-
public bool DidComponentRender(IRenderedFragmentCore renderedFragment)
44-
=> DidComponentRender((renderedFragment ?? throw new ArgumentNullException(nameof(renderedFragment))).ComponentId);
42+
public bool DidComponentRender(int componentId) => DidComponentRenderRoot(componentId);
4543

46-
private bool HasChangesTo(int componentId)
44+
private bool HasChangesToRoot(int componentId)
4745
{
48-
for (int i = 0; i < _renderBatch.UpdatedComponents.Count; i++)
46+
for (var i = 0; i < _renderBatch.UpdatedComponents.Count; i++)
4947
{
5048
var update = _renderBatch.UpdatedComponents.Array[i];
5149
if (update.ComponentId == componentId && update.Edits.Count > 0)
5250
return true;
5351
}
54-
for (int i = 0; i < _renderBatch.DisposedEventHandlerIDs.Count; i++)
55-
{
52+
for (var i = 0; i < _renderBatch.DisposedEventHandlerIDs.Count; i++)
5653
if (_renderBatch.DisposedEventHandlerIDs.Array[i].Equals(componentId))
5754
return true;
58-
}
5955

6056
var renderFrames = _renderer.GetCurrentRenderTreeFrames(componentId);
6157
return HasChangedToChildren(renderFrames);
6258
}
6359

6460
private bool HasChangedToChildren(ArrayRange<RenderTreeFrame> componentRenderTreeFrames)
6561
{
66-
for (int i = 0; i < componentRenderTreeFrames.Count; i++)
62+
for (var i = 0; i < componentRenderTreeFrames.Count; i++)
6763
{
6864
var frame = componentRenderTreeFrames.Array[i];
6965
if (frame.FrameType == RenderTreeFrameType.Component)
70-
if (HasChangesTo(frame.ComponentId))
66+
if (HasChangesToRoot(frame.ComponentId))
7167
return true;
7268
}
7369
return false;
7470
}
7571

76-
private bool DidComponentRender(int componentId)
72+
private bool DidComponentRenderRoot(int componentId)
7773
{
78-
for (int i = 0; i < _renderBatch.UpdatedComponents.Count; i++)
74+
for (var i = 0; i < _renderBatch.UpdatedComponents.Count; i++)
7975
{
8076
var update = _renderBatch.UpdatedComponents.Array[i];
8177
if (update.ComponentId == componentId)
8278
return true;
8379
}
84-
for (int i = 0; i < _renderBatch.DisposedEventHandlerIDs.Count; i++)
85-
{
80+
for (var i = 0; i < _renderBatch.DisposedEventHandlerIDs.Count; i++)
8681
if (_renderBatch.DisposedEventHandlerIDs.Array[i].Equals(componentId))
8782
return true;
88-
}
8983
return DidChildComponentRender(_renderer.GetCurrentRenderTreeFrames(componentId));
9084
}
9185

9286
private bool DidChildComponentRender(ArrayRange<RenderTreeFrame> componentRenderTreeFrames)
9387
{
94-
for (int i = 0; i < componentRenderTreeFrames.Count; i++)
88+
for (var i = 0; i < componentRenderTreeFrames.Count; i++)
9589
{
9690
var frame = componentRenderTreeFrames.Array[i];
9791
if (frame.FrameType == RenderTreeFrameType.Component)
98-
if (DidComponentRender(frame.ComponentId))
92+
if (DidComponentRenderRoot(frame.ComponentId))
9993
return true;
10094
}
10195
return false;
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace Bunit.Rendering
5+
{
6+
public class RenderEventObservable : IObservable<RenderEvent>
7+
{
8+
protected HashSet<IObserver<RenderEvent>> Observers { get; } = new HashSet<IObserver<RenderEvent>>();
9+
10+
public virtual IDisposable Subscribe(IObserver<RenderEvent> observer)
11+
{
12+
if (!Observers.Contains(observer))
13+
Observers.Add(observer);
14+
return new Unsubscriber(this, observer);
15+
}
16+
17+
protected virtual void RemoveSubscription(IObserver<RenderEvent> observer)
18+
{
19+
Observers.Remove(observer);
20+
}
21+
22+
private sealed class Unsubscriber : IDisposable
23+
{
24+
private RenderEventObservable _observable;
25+
private IObserver<RenderEvent> _observer;
26+
27+
public Unsubscriber(RenderEventObservable observable, IObserver<RenderEvent> observer)
28+
{
29+
_observable = observable;
30+
_observer = observer;
31+
}
32+
33+
public void Dispose()
34+
{
35+
_observable.RemoveSubscription(_observer);
36+
}
37+
}
38+
}
39+
40+
public sealed class RenderEventFilter : RenderEventObservable, IObservable<RenderEvent>, IObserver<RenderEvent>
41+
{
42+
private readonly IObservable<RenderEvent> _source;
43+
private readonly Func<RenderEvent, bool> _forwardEvent;
44+
private IDisposable? _subscription;
45+
46+
public RenderEventFilter(IObservable<RenderEvent> source, Func<RenderEvent, bool> forwardEvent)
47+
{
48+
_source = source;
49+
_forwardEvent = forwardEvent;
50+
}
51+
52+
public override IDisposable Subscribe(IObserver<RenderEvent> observer)
53+
{
54+
if (_subscription is null)
55+
_subscription = _source.Subscribe(this);
56+
return base.Subscribe(observer);
57+
}
58+
59+
protected override void RemoveSubscription(IObserver<RenderEvent> observer)
60+
{
61+
base.RemoveSubscription(observer);
62+
if (Observers.Count == 0 && _subscription is { })
63+
{
64+
_subscription.Dispose();
65+
_subscription = null;
66+
}
67+
}
68+
69+
void IObserver<RenderEvent>.OnCompleted()
70+
{
71+
foreach (var observer in Observers)
72+
observer.OnCompleted();
73+
}
74+
void IObserver<RenderEvent>.OnError(Exception error)
75+
{
76+
foreach (var observer in Observers)
77+
observer.OnError(error);
78+
}
79+
80+
void IObserver<RenderEvent>.OnNext(RenderEvent renderEvent)
81+
{
82+
if (!_forwardEvent(renderEvent))
83+
return;
84+
foreach (var observer in Observers)
85+
observer.OnNext(renderEvent);
86+
}
87+
}
88+
89+
public sealed class RenderEventPublisher : RenderEventObservable, IObservable<RenderEvent>
90+
{
91+
private bool _isCompleted;
92+
93+
public void OnRender(in RenderEvent renderEvent)
94+
{
95+
if (_isCompleted)
96+
throw new InvalidOperationException($"Calling {nameof(OnRender)} is not allowed after {nameof(OnCompleted)} has been called.");
97+
foreach (var observer in Observers)
98+
observer.OnNext(renderEvent);
99+
}
100+
101+
public void OnCompleted()
102+
{
103+
_isCompleted = true;
104+
foreach (var observer in Observers)
105+
observer.OnCompleted();
106+
}
107+
}
108+
}

0 commit comments

Comments
 (0)