Skip to content

Commit

Permalink
feature: Add IValidationText abstraction (#462)
Browse files Browse the repository at this point in the history
* Add IValidationText abstraction

* Fix stylecop

* fix return to pool

* cache InitialValidationStates

* -

* IValidationText as IReadOnlyList

* remove ros

* simplify ValidationContext

* remove usings

* add and use ReadOnlyCollectionPooled

* Fix ordering to match stylecop rules

* Update ReadOnlyCollectionPooled.cs

* Update ReactiveUI.Validation.csproj

* Update ReactiveUI.Validation.AndroidX.csproj

* Update ReactiveUI.Validation.AndroidSupport.csproj

* Update ReadOnlyCollectionPooled.cs

* Update ArrayPoolExtensions.cs

* Update ApiApprovalTests.ValidationProject.net6.0.approved.txt

* Update ApiApprovalTests.ValidationProject.net6.0.approved.txt

* Update ApiApprovalTests.ValidationProject.net6.0.approved.txt

Co-authored-by: Glenn <[email protected]>
  • Loading branch information
kronic and glennawatson authored Jun 28, 2022
1 parent afa35ec commit e8d1cf8
Show file tree
Hide file tree
Showing 24 changed files with 456 additions and 215 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="MSBuild.Sdk.Extras">

<PropertyGroup>
<TargetFramework>MonoAndroid11.0</TargetFramework>
<TargetFramework>MonoAndroid12.0</TargetFramework>
<PackageDescription>Provides ReactiveUI.Validation extensions for the Android Support Library</PackageDescription>
<PackageId>ReactiveUI.Validation.AndroidSupport</PackageId>
<NoWarn>$(NoWarn);CS1591</NoWarn>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="MSBuild.Sdk.Extras">
<Project Sdk="MSBuild.Sdk.Extras">

<PropertyGroup>
<TargetFrameworks>MonoAndroid11.0;MonoAndroid12.0</TargetFrameworks>
<TargetFrameworks>MonoAndroid12.0;net6.0-android</TargetFrameworks>
<PackageDescription>Provides ReactiveUI.Validation extensions for the AndroidX Library</PackageDescription>
<PackageId>ReactiveUI.Validation.AndroidX</PackageId>
<NoWarn>$(NoWarn);CS1591</NoWarn>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,18 @@ namespace ReactiveUI.Validation.Abstractions
}
namespace ReactiveUI.Validation.Collections
{
public class ValidationText : System.Collections.Generic.IEnumerable<string>, System.Collections.IEnumerable
public interface IValidationText : System.Collections.Generic.IEnumerable<string>, System.Collections.Generic.IReadOnlyCollection<string>, System.Collections.Generic.IReadOnlyList<string>, System.Collections.IEnumerable
{
public static readonly ReactiveUI.Validation.Collections.ValidationText Empty;
public static readonly ReactiveUI.Validation.Collections.ValidationText None;
public int Count { get; }
public string this[int index] { get; }
public System.Collections.Generic.IEnumerator<string> GetEnumerator() { }
public string ToSingleLine(string? separator = ",") { }
public static ReactiveUI.Validation.Collections.ValidationText Create(System.Collections.Generic.IEnumerable<ReactiveUI.Validation.Collections.ValidationText>? validationTexts) { }
public static ReactiveUI.Validation.Collections.ValidationText Create(System.Collections.Generic.IEnumerable<string>? validationTexts) { }
public static ReactiveUI.Validation.Collections.ValidationText Create(params string?[]? validationTexts) { }
string ToSingleLine(string? separator = ",");
}
public static class ValidationText
{
public static readonly ReactiveUI.Validation.Collections.IValidationText Empty;
public static readonly ReactiveUI.Validation.Collections.IValidationText None;
public static ReactiveUI.Validation.Collections.IValidationText Create(System.Collections.Generic.IEnumerable<ReactiveUI.Validation.Collections.IValidationText>? validationTexts) { }
public static ReactiveUI.Validation.Collections.IValidationText Create(System.Collections.Generic.IEnumerable<string?>? validationTexts) { }
public static ReactiveUI.Validation.Collections.IValidationText Create(string? validationText) { }
public static ReactiveUI.Validation.Collections.IValidationText Create(params string?[]? validationTexts) { }
}
}
namespace ReactiveUI.Validation.Comparators
Expand All @@ -43,7 +44,7 @@ namespace ReactiveUI.Validation.Components.Abstractions
public interface IValidationComponent
{
bool IsValid { get; }
ReactiveUI.Validation.Collections.ValidationText? Text { get; }
ReactiveUI.Validation.Collections.IValidationText? Text { get; }
System.IObservable<ReactiveUI.Validation.States.IValidationState> ValidationStatusChange { get; }
}
}
Expand All @@ -55,7 +56,7 @@ namespace ReactiveUI.Validation.Components
public bool IsValid { get; }
public System.Collections.Generic.IEnumerable<string> Properties { get; }
public int PropertyCount { get; }
public ReactiveUI.Validation.Collections.ValidationText? Text { get; }
public ReactiveUI.Validation.Collections.IValidationText? Text { get; }
public System.IObservable<ReactiveUI.Validation.States.IValidationState> ValidationStatusChange { get; }
protected void AddProperty<TProp>(System.Linq.Expressions.Expression<System.Func<TViewModel, TProp>> property) { }
public bool ContainsPropertyName(string propertyName, bool exclusively = false) { }
Expand All @@ -74,11 +75,11 @@ namespace ReactiveUI.Validation.Components
public abstract class ObservableValidationBase<TViewModel, TValue> : ReactiveUI.ReactiveObject, ReactiveUI.Validation.Components.Abstractions.IPropertyValidationComponent, ReactiveUI.Validation.Components.Abstractions.IValidatesProperties, ReactiveUI.Validation.Components.Abstractions.IValidationComponent, System.IDisposable
{
protected ObservableValidationBase(System.IObservable<ReactiveUI.Validation.States.IValidationState> observable) { }
protected ObservableValidationBase(TViewModel viewModel, System.IObservable<TValue> observable, System.Func<TViewModel, TValue, bool> isValidFunc, System.Func<TViewModel, TValue, bool, ReactiveUI.Validation.Collections.ValidationText> messageFunc) { }
protected ObservableValidationBase(TViewModel viewModel, System.IObservable<TValue> observable, System.Func<TViewModel, TValue, bool> isValidFunc, System.Func<TViewModel, TValue, bool, ReactiveUI.Validation.Collections.IValidationText> messageFunc) { }
public bool IsValid { get; }
public System.Collections.Generic.IEnumerable<string> Properties { get; }
public int PropertyCount { get; }
public ReactiveUI.Validation.Collections.ValidationText? Text { get; }
public ReactiveUI.Validation.Collections.IValidationText? Text { get; }
public System.IObservable<ReactiveUI.Validation.States.IValidationState> ValidationStatusChange { get; }
protected void AddProperty<TProp>(System.Linq.Expressions.Expression<System.Func<TViewModel, TProp>> property) { }
public bool ContainsPropertyName(string propertyName, bool exclusively = false) { }
Expand Down Expand Up @@ -110,7 +111,7 @@ namespace ReactiveUI.Validation.Contexts
{
public ValidationContext(System.Reactive.Concurrency.IScheduler? scheduler = null) { }
public bool IsValid { get; }
public ReactiveUI.Validation.Collections.ValidationText Text { get; }
public ReactiveUI.Validation.Collections.IValidationText Text { get; }
public System.IObservable<bool> Valid { get; }
public System.IObservable<ReactiveUI.Validation.States.IValidationState> ValidationStatusChange { get; }
public System.Collections.ObjectModel.ReadOnlyObservableCollection<ReactiveUI.Validation.Components.Abstractions.IValidationComponent> Validations { get; }
Expand Down Expand Up @@ -180,7 +181,7 @@ namespace ReactiveUI.Validation.Formatters.Abstractions
{
public interface IValidationTextFormatter<out TOut>
{
TOut Format(ReactiveUI.Validation.Collections.ValidationText validationText);
TOut Format(ReactiveUI.Validation.Collections.IValidationText validationText);
}
}
namespace ReactiveUI.Validation.Formatters
Expand All @@ -189,7 +190,7 @@ namespace ReactiveUI.Validation.Formatters
{
public SingleLineFormatter(string? separator = null) { }
public static ReactiveUI.Validation.Formatters.SingleLineFormatter Default { get; }
public string Format(ReactiveUI.Validation.Collections.ValidationText? validationText) { }
public string Format(ReactiveUI.Validation.Collections.IValidationText? validationText) { }
}
}
namespace ReactiveUI.Validation.Helpers
Expand All @@ -207,7 +208,7 @@ namespace ReactiveUI.Validation.Helpers
{
public ValidationHelper(ReactiveUI.Validation.Components.Abstractions.IValidationComponent validation, System.IDisposable? cleanup = null) { }
public bool IsValid { get; }
public ReactiveUI.Validation.Collections.ValidationText? Message { get; }
public ReactiveUI.Validation.Collections.IValidationText? Message { get; }
public System.IObservable<ReactiveUI.Validation.States.IValidationState> ValidationChanged { get; }
public void Dispose() { }
protected virtual void Dispose(bool disposing) { }
Expand All @@ -218,15 +219,15 @@ namespace ReactiveUI.Validation.States
public interface IValidationState
{
bool IsValid { get; }
ReactiveUI.Validation.Collections.ValidationText Text { get; }
ReactiveUI.Validation.Collections.IValidationText Text { get; }
}
public class ValidationState : ReactiveUI.Validation.States.IValidationState
{
public static readonly ReactiveUI.Validation.States.ValidationState Valid;
public ValidationState(bool isValid, ReactiveUI.Validation.Collections.ValidationText text) { }
public static readonly ReactiveUI.Validation.States.IValidationState Valid;
public ValidationState(bool isValid, ReactiveUI.Validation.Collections.IValidationText text) { }
public ValidationState(bool isValid, string text) { }
public bool IsValid { get; }
public ReactiveUI.Validation.Collections.ValidationText Text { get; }
public ReactiveUI.Validation.Collections.IValidationText Text { get; }
}
}
namespace ReactiveUI.Validation.ValidationBindings.Abstractions
Expand Down Expand Up @@ -257,4 +258,4 @@ namespace ReactiveUI.Validation.ValidationBindings
where TView : ReactiveUI.IViewFor<TViewModel>
where TViewModel : class, ReactiveUI.IReactiveObject, ReactiveUI.Validation.Abstractions.IValidatableViewModel { }
}
}
}
4 changes: 2 additions & 2 deletions src/ReactiveUI.Validation.Tests/NotifyDataErrorInfoTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,6 @@ private class PrefixFormatter : IValidationTextFormatter<string>

public PrefixFormatter(string prefix) => _prefix = prefix;

public string Format(ValidationText validationText) => $"{_prefix} {validationText.ToSingleLine()}";
public string Format(IValidationText validationText) => $"{_prefix} {validationText.ToSingleLine()}";
}
}
}
6 changes: 3 additions & 3 deletions src/ReactiveUI.Validation.Tests/ValidationBindingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -787,7 +787,7 @@ public CustomValidationState(bool isValid, string message)
Text = isValid ? ValidationText.Empty : ValidationText.Create(message);
}

public ValidationText Text { get; }
public IValidationText Text { get; }

public bool IsValid { get; }
}
Expand All @@ -798,6 +798,6 @@ private class ConstFormatter : IValidationTextFormatter<string>

public ConstFormatter(string text) => _text = text;

public string Format(ValidationText validationText) => _text;
public string Format(IValidationText validationText) => _text;
}
}
}
48 changes: 24 additions & 24 deletions src/ReactiveUI.Validation.Tests/ValidationTextTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class ValidationTextTests
[Fact]
public void NoneValidationTextIsEmpty()
{
ValidationText vt = ValidationText.None;
IValidationText vt = ValidationText.None;

Assert.Equal(0, vt.Count);

Expand All @@ -40,7 +40,7 @@ public void NoneValidationTextIsEmpty()
[Fact]
public void EmptyValidationTextIsSingleEmpty()
{
ValidationText vt = ValidationText.Empty;
IValidationText vt = ValidationText.Empty;

Assert.Equal(1, vt.Count);

Expand All @@ -58,7 +58,7 @@ public void EmptyValidationTextIsSingleEmpty()
[Fact]
public void ParameterlessCreateReturnsNone()
{
ValidationText vt = ValidationText.Create();
IValidationText vt = ValidationText.Create();

Assert.Same(ValidationText.None, vt);
}
Expand All @@ -69,18 +69,18 @@ public void ParameterlessCreateReturnsNone()
[Fact]
public void CreateEmptyStringEnumerableReturnsNone()
{
ValidationText vt = ValidationText.Create((IEnumerable<string>)Array.Empty<string>());
IValidationText vt = ValidationText.Create((IEnumerable<string>)Array.Empty<string>());

Assert.Same(ValidationText.None, vt);
}

/// <summary>
/// Verifies that calling <see cref="ValidationText.Create(IEnumerable{ValidationText})"/> with an empty enumerable <see cref="ValidationText.None"/>.
/// Verifies that calling <see cref="ValidationText.Create(IEnumerable{IValidationText})"/> with an empty enumerable <see cref="ValidationText.None"/>.
/// </summary>
[Fact]
public void CreateEmptyValidationTextEnumerableReturnsNone()
{
ValidationText vt = ValidationText.Create(Array.Empty<ValidationText>());
IValidationText vt = ValidationText.Create(Array.Empty<IValidationText>());

Assert.Same(ValidationText.None, vt);
}
Expand All @@ -91,7 +91,7 @@ public void CreateEmptyValidationTextEnumerableReturnsNone()
[Fact]
public void CreateNullReturnsNone()
{
ValidationText vt = ValidationText.Create((string)null);
IValidationText vt = ValidationText.Create((string)null);

Assert.Same(ValidationText.None, vt);
}
Expand All @@ -102,18 +102,18 @@ public void CreateNullReturnsNone()
[Fact]
public void CreateNullStringEnumerableReturnsNone()
{
ValidationText vt = ValidationText.Create((IEnumerable<string>)null);
IValidationText vt = ValidationText.Create((IEnumerable<string>)null);

Assert.Same(ValidationText.None, vt);
}

/// <summary>
/// Verifies that calling <see cref="ValidationText.Create(IEnumerable{ValidationText})"/> with <see langword="null"/> returns <see cref="ValidationText.None"/>.
/// Verifies that calling <see cref="ValidationText.Create(IEnumerable{IValidationText})"/> with <see langword="null"/> returns <see cref="ValidationText.None"/>.
/// </summary>
[Fact]
public void CreateNullValidationTextEnumerableReturnsNone()
{
ValidationText vt = ValidationText.Create((IEnumerable<ValidationText>)null);
IValidationText vt = ValidationText.Create((IEnumerable<IValidationText>)null);

Assert.Same(ValidationText.None, vt);
}
Expand All @@ -124,18 +124,18 @@ public void CreateNullValidationTextEnumerableReturnsNone()
[Fact]
public void CreateNullItemStringEnumerableReturnsNone()
{
ValidationText vt = ValidationText.Create((IEnumerable<string>)new string[] { null });
IValidationText vt = ValidationText.Create((IEnumerable<string>)new string[] { null });

Assert.Same(ValidationText.None, vt);
}

/// <summary>
/// Verifies that calling <see cref="ValidationText.Create(IEnumerable{ValidationText})"/> with an enumerable containing <see cref="ValidationText.None"/> returns <see cref="ValidationText.None"/>.
/// Verifies that calling <see cref="ValidationText.Create(IEnumerable{IValidationText})"/> with an enumerable containing <see cref="ValidationText.None"/> returns <see cref="ValidationText.None"/>.
/// </summary>
[Fact]
public void CreateNoneItemValidationTextEnumerableReturnsNone()
{
ValidationText vt = ValidationText.Create(new[] { ValidationText.None });
IValidationText vt = ValidationText.Create(new[] { ValidationText.None });

Assert.Same(ValidationText.None, vt);
}
Expand All @@ -146,7 +146,7 @@ public void CreateNoneItemValidationTextEnumerableReturnsNone()
[Fact]
public void CreateNoneItemStringEnumerableReturnsNone()
{
ValidationText vt = ValidationText.Create(ValidationText.None);
IValidationText vt = ValidationText.Create(ValidationText.None);

Assert.Same(ValidationText.None, vt);
}
Expand All @@ -157,7 +157,7 @@ public void CreateNoneItemStringEnumerableReturnsNone()
[Fact]
public void CreateStringEmptyReturnsEmpty()
{
ValidationText vt = ValidationText.Create(string.Empty);
IValidationText vt = ValidationText.Create(string.Empty);

Assert.Same(ValidationText.Empty, vt);
}
Expand All @@ -168,7 +168,7 @@ public void CreateStringEmptyReturnsEmpty()
[Fact]
public void CreateSingleStringEmptyReturnsEmpty()
{
ValidationText vt = ValidationText.Create((IEnumerable<string>)new[] { string.Empty });
IValidationText vt = ValidationText.Create((IEnumerable<string>)new[] { string.Empty });

Assert.Same(ValidationText.Empty, vt);
}
Expand All @@ -179,41 +179,41 @@ public void CreateSingleStringEmptyReturnsEmpty()
[Fact]
public void CreateValidationTextEmptyReturnsEmpty()
{
ValidationText vt = ValidationText.Create(new[] { ValidationText.Empty });
IValidationText vt = ValidationText.Create(new[] { ValidationText.Empty });

Assert.Same(ValidationText.Empty, vt);
}

/// <summary>
/// Verifies that calling <see cref="ValidationText.Create(IEnumerable{ValidationText})"/> with an enumerable containing two <see cref="ValidationText.None"/> returns <see cref="ValidationText.None"/>.
/// Verifies that calling <see cref="ValidationText.Create(IEnumerable{IValidationText})"/> with an enumerable containing two <see cref="ValidationText.None"/> returns <see cref="ValidationText.None"/>.
/// </summary>
[Fact]
public void CombineValidationTextNoneReturnsNone()
{
ValidationText vt = ValidationText.Create(new[] { ValidationText.None, ValidationText.None });
IValidationText vt = ValidationText.Create(new[] { ValidationText.None, ValidationText.None });

Assert.Same(ValidationText.None, vt);
}

/// <summary>
/// Verifies that calling <see cref="ValidationText.Create(IEnumerable{ValidationText})"/> with an enumerable containing <see cref="ValidationText.None"/> and <see cref="ValidationText.Empty"/> returns <see cref="ValidationText.Empty"/>.
/// Verifies that calling <see cref="ValidationText.Create(IEnumerable{IValidationText})"/> with an enumerable containing <see cref="ValidationText.None"/> and <see cref="ValidationText.Empty"/> returns <see cref="ValidationText.Empty"/>.
/// </summary>
[Fact]
public void CombineValidationTextEmptyAndNoneReturnsEmpty()
{
ValidationText vt = ValidationText.Create(new[] { ValidationText.None, ValidationText.Empty });
IValidationText vt = ValidationText.Create(new[] { ValidationText.None, ValidationText.Empty });

Assert.Same(ValidationText.Empty, vt);
}

/// <summary>
/// Verifies that calling <see cref="ValidationText.Create(IEnumerable{ValidationText})"/> with an enumerable containing two <see cref="ValidationText.Empty"/>
/// Verifies that calling <see cref="ValidationText.Create(IEnumerable{IValidationText})"/> with an enumerable containing two <see cref="ValidationText.Empty"/>
/// returns a single <see cref="ValidationText"/> with two empty strings.
/// </summary>
[Fact]
public void CombineValidationTextEmptyReturnsTwoEmpty()
{
ValidationText vt = ValidationText.Create(new[] { ValidationText.Empty, ValidationText.Empty });
IValidationText vt = ValidationText.Create(new[] { ValidationText.Empty, ValidationText.Empty });

Assert.NotSame(ValidationText.Empty, vt);
Assert.Equal(2, vt.Count);
Expand All @@ -227,4 +227,4 @@ public void CombineValidationTextEmptyReturnsTwoEmpty()

Assert.Equal("|", vt.ToSingleLine("|"));
}
}
}
26 changes: 26 additions & 0 deletions src/ReactiveUI.Validation/Collections/ArrayValidationText.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for full license information.

using System.Collections;
using System.Collections.Generic;

namespace ReactiveUI.Validation.Collections;

internal sealed class ArrayValidationText : IValidationText
{
private readonly string[] _texts;

internal ArrayValidationText(string[] texts) => _texts = texts;

public int Count => _texts.Length;

public string this[int index] => _texts[index];

public IEnumerator<string> GetEnumerator() => ((IEnumerable<string>)_texts).GetEnumerator();

IEnumerator IEnumerable.GetEnumerator() => _texts.GetEnumerator();

public string ToSingleLine(string? separator) => string.Join(separator, _texts);
}
Loading

0 comments on commit e8d1cf8

Please sign in to comment.