/
githubmirror
/
aspnetcore
Обзор
Документация
Войти
/
githubmirror
/
aspnetcore
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Components/Forms/test/FieldIdentifierTest.cs
327 строк
11 KB
Javier Calvarro Nelson
[Blazor] Pass the member info directly (#53874)
09 фев 2024, 11:07
Не верифицирован
09 фев 2024, 11:07
1b91cca
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Concurrent; using System.Linq.Expressions; using System.Reflection; namespace Microsoft.AspNetCore.Components.Forms; public class FieldIdentifierTest { [Fact] public void CannotUseNullModel() { var ex = Assert.Throws<ArgumentNullException>(() => new FieldIdentifier(null, "somefield")); Assert.Equal("model", ex.ParamName); } [Fact] public void CannotUseValueTypeModel() { var ex = Assert.Throws<ArgumentException>(() => new FieldIdentifier(DateTime.Now, "somefield")); Assert.Equal("model", ex.ParamName); Assert.StartsWith("The model must be a reference-typed object.", ex.Message); } [Fact] public void CannotUseNullFieldName() { var ex = Assert.Throws<ArgumentNullException>(() => new FieldIdentifier(new object(), null)); Assert.Equal("fieldName", ex.ParamName); } [Fact] public void CanUseEmptyFieldName() { var fieldIdentifier = new FieldIdentifier(new object(), string.Empty); Assert.Equal(string.Empty, fieldIdentifier.FieldName); } [Fact] public void CanGetModelAndFieldName() { // Arrange/Act var model = new object(); var fieldIdentifier = new FieldIdentifier(model, "someField"); // Assert Assert.Same(model, fieldIdentifier.Model); Assert.Equal("someField", fieldIdentifier.FieldName); } [Fact] public void DistinctModelsProduceDistinctHashCodesAndNonEquality() { // Arrange var fieldIdentifier1 = new FieldIdentifier(new object(), "field"); var fieldIdentifier2 = new FieldIdentifier(new object(), "field"); // Act/Assert Assert.NotEqual(fieldIdentifier1.GetHashCode(), fieldIdentifier2.GetHashCode()); Assert.False(fieldIdentifier1.Equals(fieldIdentifier2)); } [Fact] public void DistinctFieldNamesProduceDistinctHashCodesAndNonEquality() { // Arrange var model = new object(); var fieldIdentifier1 = new FieldIdentifier(model, "field1"); var fieldIdentifier2 = new FieldIdentifier(model, "field2"); // Act/Assert Assert.NotEqual(fieldIdentifier1.GetHashCode(), fieldIdentifier2.GetHashCode()); Assert.False(fieldIdentifier1.Equals(fieldIdentifier2)); } [Fact] public void FieldIdentifier_ForModelWithoutField_ProduceSameHashCodesAndEquality() { // Arrange var model = new object(); var fieldIdentifier1 = new FieldIdentifier(model, fieldName: string.Empty); var fieldIdentifier2 = new FieldIdentifier(model, fieldName: string.Empty); // Act/Assert Assert.Equal(fieldIdentifier1.GetHashCode(), fieldIdentifier2.GetHashCode()); Assert.True(fieldIdentifier1.Equals(fieldIdentifier2)); } [Fact] public void SameContentsProduceSameHashCodesAndEquality() { // Arrange var model = new object(); var fieldIdentifier1 = new FieldIdentifier(model, "field"); var fieldIdentifier2 = new FieldIdentifier(model, "field"); // Act/Assert Assert.Equal(fieldIdentifier1.GetHashCode(), fieldIdentifier2.GetHashCode()); Assert.True(fieldIdentifier1.Equals(fieldIdentifier2)); } [Fact] public void SameContents_WithOverridenEqualsAndGetHashCode_ProduceSameHashCodesAndEquality() { // Arrange var model = new EquatableModel(); var fieldIdentifier1 = new FieldIdentifier(model, nameof(EquatableModel.Property)); model.Property = "changed value"; // To show it makes no difference if the overridden `GetHashCode` result changes var fieldIdentifier2 = new FieldIdentifier(model, nameof(EquatableModel.Property)); // Act/Assert Assert.Equal(fieldIdentifier1.GetHashCode(), fieldIdentifier2.GetHashCode()); Assert.True(fieldIdentifier1.Equals(fieldIdentifier2)); } [Fact] public void FieldNamesAreCaseSensitive() { // Arrange var model = new object(); var fieldIdentifierLower = new FieldIdentifier(model, "field"); var fieldIdentifierPascal = new FieldIdentifier(model, "Field"); // Act/Assert Assert.Equal("field", fieldIdentifierLower.FieldName); Assert.Equal("Field", fieldIdentifierPascal.FieldName); Assert.NotEqual(fieldIdentifierLower.GetHashCode(), fieldIdentifierPascal.GetHashCode()); Assert.False(fieldIdentifierLower.Equals(fieldIdentifierPascal)); } [Fact] public void CanCreateFromExpression_Property() { var model = new TestModel(); var fieldIdentifier = FieldIdentifier.Create(() => model.StringProperty); Assert.Same(model, fieldIdentifier.Model); Assert.Equal(nameof(model.StringProperty), fieldIdentifier.FieldName); } [Fact] public void CanCreateFromExpression_PropertyUsesCache() { var models = new TestModel[] { new TestModel(), new TestModel() }; var cache = new ConcurrentDictionary<(Type ModelType, MemberInfo FieldName), Func<object, object>>(); var result = new TestModel[2]; for (var i = 0; i < models.Length; i++) { var model = models[i]; LambdaExpression expression = () => model.StringProperty; var body = expression.Body as MemberExpression; var value = FieldIdentifier.GetModelFromMemberAccess((MemberExpression)body.Expression, cache); result[i] = Assert.IsType<TestModel>(value); } Assert.Single(cache); Assert.Equal(models, result); } [Fact] public void CannotCreateFromExpression_NonMember() { var ex = Assert.Throws<ArgumentException>(() => FieldIdentifier.Create(() => new TestModel())); Assert.Equal($"The provided expression contains a NewExpression which is not supported. {nameof(FieldIdentifier)} only supports simple member accessors (fields, properties) of an object.", ex.Message); } [Fact] public void CanCreateFromExpression_Field() { var model = new TestModel(); var fieldIdentifier = FieldIdentifier.Create(() => model.StringField); Assert.Same(model, fieldIdentifier.Model); Assert.Equal(nameof(model.StringField), fieldIdentifier.FieldName); } [Fact] public void CanCreateFromExpression_WithCastToObject() { // This case is needed because, if a component is declared as receiving // an Expression<Func<object>>, then any value types will be implicitly cast var model = new TestModel(); Expression<Func<object>> accessor = () => model.IntProperty; var fieldIdentifier = FieldIdentifier.Create(accessor); Assert.Same(model, fieldIdentifier.Model); Assert.Equal(nameof(model.IntProperty), fieldIdentifier.FieldName); } [Fact] public void CanCreateFromExpression_MemberOfConstantExpression() { var fieldIdentifier = FieldIdentifier.Create(() => StringPropertyOnThisClass); Assert.Same(this, fieldIdentifier.Model); Assert.Equal(nameof(StringPropertyOnThisClass), fieldIdentifier.FieldName); } [Fact] public void CanCreateFromExpression_MemberOfChildObject() { var parentModel = new ParentModel { Child = new TestModel() }; var fieldIdentifier = FieldIdentifier.Create(() => parentModel.Child.StringField); Assert.Same(parentModel.Child, fieldIdentifier.Model); Assert.Equal(nameof(TestModel.StringField), fieldIdentifier.FieldName); } [Fact] public void CanCreateFromExpression_MemberOfIndexedCollectionEntry() { var models = new List<TestModel>() { null, new TestModel() }; var fieldIdentifier = FieldIdentifier.Create(() => models[1].StringField); Assert.Same(models[1], fieldIdentifier.Model); Assert.Equal(nameof(TestModel.StringField), fieldIdentifier.FieldName); } [Fact] public void CanCreateFromExpression_MemberOfObjectWithCast() { var model = new TestModel(); var fieldIdentifier = FieldIdentifier.Create(() => ((TestModel)(object)model).StringField); Assert.Same(model, fieldIdentifier.Model); Assert.Equal(nameof(TestModel.StringField), fieldIdentifier.FieldName); } [Fact] public void CanCreateFromExpression_DifferentCaseField() { var fieldIdentifier = FieldIdentifier.Create(() => model.Field); Assert.Same(model, fieldIdentifier.Model); Assert.Equal(nameof(model.Field), fieldIdentifier.FieldName); } private DifferentCaseFieldModel model = new() { Field = 1 }; #pragma warning disable CA1823 // This is used in the test above private DifferentCaseFieldModel Model = new() { field = 2 }; #pragma warning restore CA1823 // Avoid unused private fields [Fact] public void CanCreateFromExpression_DifferentCaseProperty() { var fieldIdentifier = FieldIdentifier.Create(() => Model2.Property); Assert.Same(Model2, fieldIdentifier.Model); Assert.Equal(nameof(Model2.Property), fieldIdentifier.FieldName); } protected DifferentCasePropertyModel Model2 { get; } = new() { property = 1 }; protected DifferentCasePropertyModel model2 { get; } = new() { Property = 2 }; [Fact] public void CanCreateFromExpression_DifferentCasePropertyAndField() { var fieldIdentifier = FieldIdentifier.Create(() => model3.Value); Assert.Same(model3, fieldIdentifier.Model); Assert.Equal(nameof(Model3.Value), fieldIdentifier.FieldName); } [Fact] public void CanCreateFromExpression_NonAsciiCharacters() { var fieldIdentifier = FieldIdentifier.Create(() => @ÖvrigAnställning.Ort); Assert.Same(@ÖvrigAnställning, fieldIdentifier.Model); Assert.Equal(nameof(@ÖvrigAnställning.Ort), fieldIdentifier.FieldName); } public DifferentCasePropertyFieldModel Model3 { get; } = new() { value = 1 }; public DifferentCasePropertyFieldModel model3 = new() { Value = 2 }; public ÖvrigAnställningModel @ÖvrigAnställning { get; set; } = new(); string StringPropertyOnThisClass { get; set; } class TestModel { public string StringProperty { get; set; } public int IntProperty { get; set; } #pragma warning disable 649 public string StringField; #pragma warning restore 649 } class ParentModel { public TestModel Child { get; set; } } class EquatableModel : IEquatable<EquatableModel> { public string Property { get; set; } = ""; public bool Equals(EquatableModel other) { return string.Equals(Property, other?.Property, StringComparison.Ordinal); } public override int GetHashCode() { return StringComparer.Ordinal.GetHashCode(Property); } } public class ÖvrigAnställningModel { public int Ort { get; set; } } private class DifferentCaseFieldModel { public int Field; public int field; } protected class DifferentCasePropertyModel { public int Property { get; set; } public int property { get; set; } } public class DifferentCasePropertyFieldModel { public int Value { get; set; } public int value; } }