441 lines
16 KiB
C#
441 lines
16 KiB
C#
// Copyright (c) .NET Foundation. All rights reserved.
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
using Microsoft.AspNetCore.Blazor.Components;
|
|
using Microsoft.AspNetCore.Blazor.Rendering;
|
|
using Microsoft.AspNetCore.Blazor.Test.Helpers;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Xunit;
|
|
|
|
namespace Microsoft.AspNetCore.Blazor.Test
|
|
{
|
|
public class CascadingParameterStateTest
|
|
{
|
|
[Fact]
|
|
public void FindCascadingParameters_IfHasNoParameters_ReturnsNull()
|
|
{
|
|
// Arrange
|
|
var componentState = CreateComponentState(new ComponentWithNoParams());
|
|
|
|
// Act
|
|
var result = CascadingParameterState.FindCascadingParameters(componentState);
|
|
|
|
// Assert
|
|
Assert.Null(result);
|
|
}
|
|
|
|
[Fact]
|
|
public void FindCascadingParameters_IfHasNoCascadingParameters_ReturnsNull()
|
|
{
|
|
// Arrange
|
|
var componentState = CreateComponentState(new ComponentWithNoCascadingParams());
|
|
|
|
// Act
|
|
var result = CascadingParameterState.FindCascadingParameters(componentState);
|
|
|
|
// Assert
|
|
Assert.Null(result);
|
|
}
|
|
|
|
[Fact]
|
|
public void FindCascadingParameters_IfHasNoAncestors_ReturnsNull()
|
|
{
|
|
// Arrange
|
|
var componentState = CreateComponentState(new ComponentWithCascadingParams());
|
|
|
|
// Act
|
|
var result = CascadingParameterState.FindCascadingParameters(componentState);
|
|
|
|
// Assert
|
|
Assert.Null(result);
|
|
}
|
|
|
|
[Fact]
|
|
public void FindCascadingParameters_IfHasNoMatchesInAncestors_ReturnsNull()
|
|
{
|
|
// Arrange: Build the ancestry list
|
|
var states = CreateAncestry(
|
|
new ComponentWithNoParams(),
|
|
CreateCascadingValueComponent("Hello"),
|
|
new ComponentWithNoParams(),
|
|
new ComponentWithCascadingParams());
|
|
|
|
// Act
|
|
var result = CascadingParameterState.FindCascadingParameters(states.Last());
|
|
|
|
// Assert
|
|
Assert.Null(result);
|
|
}
|
|
|
|
[Fact]
|
|
public void FindCascadingParameters_IfHasPartialMatchesInAncestors_ReturnsMatches()
|
|
{
|
|
// Arrange
|
|
var states = CreateAncestry(
|
|
new ComponentWithNoParams(),
|
|
CreateCascadingValueComponent(new ValueType2()),
|
|
new ComponentWithNoParams(),
|
|
new ComponentWithCascadingParams());
|
|
|
|
// Act
|
|
var result = CascadingParameterState.FindCascadingParameters(states.Last());
|
|
|
|
// Assert
|
|
Assert.Collection(result, match =>
|
|
{
|
|
Assert.Equal(nameof(ComponentWithCascadingParams.CascadingParam2), match.LocalValueName);
|
|
Assert.Same(states[1].Component, match.ValueSupplier);
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void FindCascadingParameters_IfHasMultipleMatchesInAncestors_ReturnsMatches()
|
|
{
|
|
// Arrange
|
|
var states = CreateAncestry(
|
|
new ComponentWithNoParams(),
|
|
CreateCascadingValueComponent(new ValueType2()),
|
|
new ComponentWithNoParams(),
|
|
CreateCascadingValueComponent(new ValueType1()),
|
|
new ComponentWithCascadingParams());
|
|
|
|
// Act
|
|
var result = CascadingParameterState.FindCascadingParameters(states.Last());
|
|
|
|
// Assert
|
|
Assert.Collection(result.OrderBy(x => x.LocalValueName),
|
|
match => {
|
|
Assert.Equal(nameof(ComponentWithCascadingParams.CascadingParam1), match.LocalValueName);
|
|
Assert.Same(states[3].Component, match.ValueSupplier);
|
|
},
|
|
match => {
|
|
Assert.Equal(nameof(ComponentWithCascadingParams.CascadingParam2), match.LocalValueName);
|
|
Assert.Same(states[1].Component, match.ValueSupplier);
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void FindCascadingParameters_InheritedParameters_ReturnsMatches()
|
|
{
|
|
// Arrange
|
|
var states = CreateAncestry(
|
|
CreateCascadingValueComponent(new ValueType1()),
|
|
CreateCascadingValueComponent(new ValueType3()),
|
|
new ComponentWithInheritedCascadingParams());
|
|
|
|
// Act
|
|
var result = CascadingParameterState.FindCascadingParameters(states.Last());
|
|
|
|
// Assert
|
|
Assert.Collection(result.OrderBy(x => x.LocalValueName),
|
|
match => {
|
|
Assert.Equal(nameof(ComponentWithCascadingParams.CascadingParam1), match.LocalValueName);
|
|
Assert.Same(states[0].Component, match.ValueSupplier);
|
|
},
|
|
match => {
|
|
Assert.Equal(nameof(ComponentWithInheritedCascadingParams.CascadingParam3), match.LocalValueName);
|
|
Assert.Same(states[1].Component, match.ValueSupplier);
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void FindCascadingParameters_ComponentRequestsBaseType_ReturnsMatches()
|
|
{
|
|
// Arrange
|
|
var states = CreateAncestry(
|
|
CreateCascadingValueComponent(new CascadingValueTypeDerivedClass()),
|
|
new ComponentWithGenericCascadingParam<CascadingValueTypeBaseClass>());
|
|
|
|
// Act
|
|
var result = CascadingParameterState.FindCascadingParameters(states.Last());
|
|
|
|
// Assert
|
|
Assert.Collection(result, match => {
|
|
Assert.Equal(nameof(ComponentWithGenericCascadingParam<object>.LocalName), match.LocalValueName);
|
|
Assert.Same(states[0].Component, match.ValueSupplier);
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void FindCascadingParameters_ComponentRequestsImplementedInterface_ReturnsMatches()
|
|
{
|
|
// Arrange
|
|
var states = CreateAncestry(
|
|
CreateCascadingValueComponent(new CascadingValueTypeDerivedClass()),
|
|
new ComponentWithGenericCascadingParam<ICascadingValueTypeDerivedClassInterface>());
|
|
|
|
// Act
|
|
var result = CascadingParameterState.FindCascadingParameters(states.Last());
|
|
|
|
// Assert
|
|
Assert.Collection(result, match => {
|
|
Assert.Equal(nameof(ComponentWithGenericCascadingParam<object>.LocalName), match.LocalValueName);
|
|
Assert.Same(states[0].Component, match.ValueSupplier);
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void FindCascadingParameters_ComponentRequestsDerivedType_ReturnsNull()
|
|
{
|
|
// Arrange
|
|
var states = CreateAncestry(
|
|
CreateCascadingValueComponent(new CascadingValueTypeBaseClass()),
|
|
new ComponentWithGenericCascadingParam<CascadingValueTypeDerivedClass>());
|
|
|
|
// Act
|
|
var result = CascadingParameterState.FindCascadingParameters(states.Last());
|
|
|
|
// Assert
|
|
Assert.Null(result);
|
|
}
|
|
|
|
[Fact]
|
|
public void FindCascadingParameters_TypeAssignmentIsValidForNullValue_ReturnsMatches()
|
|
{
|
|
// Arrange
|
|
var states = CreateAncestry(
|
|
CreateCascadingValueComponent((CascadingValueTypeDerivedClass)null),
|
|
new ComponentWithGenericCascadingParam<CascadingValueTypeBaseClass>());
|
|
|
|
// Act
|
|
var result = CascadingParameterState.FindCascadingParameters(states.Last());
|
|
|
|
// Assert
|
|
Assert.Collection(result, match => {
|
|
Assert.Equal(nameof(ComponentWithGenericCascadingParam<object>.LocalName), match.LocalValueName);
|
|
Assert.Same(states[0].Component, match.ValueSupplier);
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void FindCascadingParameters_TypeAssignmentIsInvalidForNullValue_ReturnsNull()
|
|
{
|
|
// Arrange
|
|
var states = CreateAncestry(
|
|
CreateCascadingValueComponent((object)null),
|
|
new ComponentWithGenericCascadingParam<ValueType1>());
|
|
|
|
// Act
|
|
var result = CascadingParameterState.FindCascadingParameters(states.Last());
|
|
|
|
// Assert
|
|
Assert.Null(result);
|
|
}
|
|
|
|
[Fact]
|
|
public void FindCascadingParameters_SupplierSpecifiesNameButConsumerDoesNot_ReturnsNull()
|
|
{
|
|
// Arrange
|
|
var states = CreateAncestry(
|
|
CreateCascadingValueComponent(new ValueType1(), "MatchOnName"),
|
|
new ComponentWithCascadingParams());
|
|
|
|
// Act
|
|
var result = CascadingParameterState.FindCascadingParameters(states.Last());
|
|
|
|
// Assert
|
|
Assert.Null(result);
|
|
}
|
|
|
|
[Fact]
|
|
public void FindCascadingParameters_ConsumerSpecifiesNameButSupplierDoesNot_ReturnsNull()
|
|
{
|
|
// Arrange
|
|
var states = CreateAncestry(
|
|
CreateCascadingValueComponent(new ValueType1()),
|
|
new ComponentWithNamedCascadingParam());
|
|
|
|
// Act
|
|
var result = CascadingParameterState.FindCascadingParameters(states.Last());
|
|
|
|
// Assert
|
|
Assert.Null(result);
|
|
}
|
|
|
|
[Fact]
|
|
public void FindCascadingParameters_MismatchingNameButMatchingType_ReturnsNull()
|
|
{
|
|
// Arrange
|
|
var states = CreateAncestry(
|
|
CreateCascadingValueComponent(new ValueType1(), "MismatchName"),
|
|
new ComponentWithNamedCascadingParam());
|
|
|
|
// Act
|
|
var result = CascadingParameterState.FindCascadingParameters(states.Last());
|
|
|
|
// Assert
|
|
Assert.Null(result);
|
|
}
|
|
|
|
[Fact]
|
|
public void FindCascadingParameters_MatchingNameButMismatchingType_ReturnsNull()
|
|
{
|
|
// Arrange
|
|
var states = CreateAncestry(
|
|
CreateCascadingValueComponent(new ValueType2(), "MatchOnName"),
|
|
new ComponentWithNamedCascadingParam());
|
|
|
|
// Act
|
|
var result = CascadingParameterState.FindCascadingParameters(states.Last());
|
|
|
|
// Assert
|
|
Assert.Null(result);
|
|
}
|
|
|
|
[Fact]
|
|
public void FindCascadingParameters_MatchingNameAndType_ReturnsMatches()
|
|
{
|
|
// Arrange
|
|
var states = CreateAncestry(
|
|
CreateCascadingValueComponent(new ValueType1(), "matchonNAME"), // To show it's case-insensitive
|
|
new ComponentWithNamedCascadingParam());
|
|
|
|
// Act
|
|
var result = CascadingParameterState.FindCascadingParameters(states.Last());
|
|
|
|
// Assert
|
|
Assert.Collection(result, match => {
|
|
Assert.Equal(nameof(ComponentWithNamedCascadingParam.SomeLocalName), match.LocalValueName);
|
|
Assert.Same(states[0].Component, match.ValueSupplier);
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void FindCascadingParameters_MultipleMatchingAncestors_ReturnsClosestMatches()
|
|
{
|
|
// Arrange
|
|
var states = CreateAncestry(
|
|
CreateCascadingValueComponent(new ValueType1()),
|
|
CreateCascadingValueComponent(new ValueType2()),
|
|
CreateCascadingValueComponent(new ValueType1()),
|
|
CreateCascadingValueComponent(new ValueType2()),
|
|
new ComponentWithCascadingParams());
|
|
|
|
// Act
|
|
var result = CascadingParameterState.FindCascadingParameters(states.Last());
|
|
|
|
// Assert
|
|
Assert.Collection(result.OrderBy(x => x.LocalValueName),
|
|
match => {
|
|
Assert.Equal(nameof(ComponentWithCascadingParams.CascadingParam1), match.LocalValueName);
|
|
Assert.Same(states[2].Component, match.ValueSupplier);
|
|
},
|
|
match => {
|
|
Assert.Equal(nameof(ComponentWithCascadingParams.CascadingParam2), match.LocalValueName);
|
|
Assert.Same(states[3].Component, match.ValueSupplier);
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void FindCascadingParameters_CanOverrideNonNullValueWithNull()
|
|
{
|
|
// Arrange
|
|
var states = CreateAncestry(
|
|
CreateCascadingValueComponent(new ValueType1()),
|
|
CreateCascadingValueComponent((ValueType1)null),
|
|
new ComponentWithCascadingParams());
|
|
|
|
// Act
|
|
var result = CascadingParameterState.FindCascadingParameters(states.Last());
|
|
|
|
// Assert
|
|
Assert.Collection(result.OrderBy(x => x.LocalValueName),
|
|
match => {
|
|
Assert.Equal(nameof(ComponentWithCascadingParams.CascadingParam1), match.LocalValueName);
|
|
Assert.Same(states[1].Component, match.ValueSupplier);
|
|
Assert.Null(match.ValueSupplier.CurrentValue);
|
|
});
|
|
}
|
|
|
|
static ComponentState[] CreateAncestry(params IComponent[] components)
|
|
{
|
|
var result = new ComponentState[components.Length];
|
|
|
|
for (var i = 0; i < components.Length; i++)
|
|
{
|
|
result[i] = CreateComponentState(
|
|
components[i],
|
|
i == 0 ? null : result[i - 1]);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static ComponentState CreateComponentState(
|
|
IComponent component, ComponentState parentComponentState = null)
|
|
{
|
|
return new ComponentState(new TestRenderer(), 0, component, parentComponentState);
|
|
}
|
|
|
|
static CascadingValue<T> CreateCascadingValueComponent<T>(T value, string name = null)
|
|
{
|
|
var supplier = new CascadingValue<T>();
|
|
supplier.Init(new RenderHandle(new TestRenderer(), 0));
|
|
|
|
var supplierParams = new Dictionary<string, object>
|
|
{
|
|
{ "Value", value }
|
|
};
|
|
|
|
if (name != null)
|
|
{
|
|
supplierParams.Add("Name", name);
|
|
}
|
|
|
|
supplier.SetParameters(supplierParams);
|
|
return supplier;
|
|
}
|
|
|
|
class ComponentWithNoParams : TestComponentBase
|
|
{
|
|
}
|
|
|
|
class ComponentWithNoCascadingParams : TestComponentBase
|
|
{
|
|
[Parameter] bool SomeRegularParameter { get; set; }
|
|
}
|
|
|
|
class ComponentWithCascadingParams : TestComponentBase
|
|
{
|
|
[Parameter] bool RegularParam { get; set; }
|
|
[CascadingParameter] internal ValueType1 CascadingParam1 { get; set; }
|
|
[CascadingParameter] internal ValueType2 CascadingParam2 { get; set; }
|
|
}
|
|
|
|
class ComponentWithInheritedCascadingParams : ComponentWithCascadingParams
|
|
{
|
|
[CascadingParameter] internal ValueType3 CascadingParam3 { get; set; }
|
|
}
|
|
|
|
class ComponentWithGenericCascadingParam<T> : TestComponentBase
|
|
{
|
|
[CascadingParameter] internal T LocalName { get; set; }
|
|
}
|
|
|
|
class ComponentWithNamedCascadingParam : TestComponentBase
|
|
{
|
|
[CascadingParameter(Name = "MatchOnName")]
|
|
internal ValueType1 SomeLocalName { get; set; }
|
|
}
|
|
|
|
class TestComponentBase : IComponent
|
|
{
|
|
public void Init(RenderHandle renderHandle)
|
|
=> throw new NotImplementedException();
|
|
|
|
public void SetParameters(ParameterCollection parameters)
|
|
=> throw new NotImplementedException();
|
|
}
|
|
|
|
class ValueType1 { }
|
|
class ValueType2 { }
|
|
class ValueType3 { }
|
|
|
|
class CascadingValueTypeBaseClass { }
|
|
class CascadingValueTypeDerivedClass : CascadingValueTypeBaseClass, ICascadingValueTypeDerivedClassInterface { }
|
|
interface ICascadingValueTypeDerivedClassInterface { }
|
|
}
|
|
}
|