Skip to content

Commit e8d1cf8

Browse files
kronicglennawatson
andauthored
feature: Add IValidationText abstraction (#462)
* 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]>
1 parent afa35ec commit e8d1cf8

24 files changed

+456
-215
lines changed

src/ReactiveUI.Validation.AndroidSupport/ReactiveUI.Validation.AndroidSupport.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="MSBuild.Sdk.Extras">
22

33
<PropertyGroup>
4-
<TargetFramework>MonoAndroid11.0</TargetFramework>
4+
<TargetFramework>MonoAndroid12.0</TargetFramework>
55
<PackageDescription>Provides ReactiveUI.Validation extensions for the Android Support Library</PackageDescription>
66
<PackageId>ReactiveUI.Validation.AndroidSupport</PackageId>
77
<NoWarn>$(NoWarn);CS1591</NoWarn>

src/ReactiveUI.Validation.AndroidX/ReactiveUI.Validation.AndroidX.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
<Project Sdk="MSBuild.Sdk.Extras">
1+
<Project Sdk="MSBuild.Sdk.Extras">
22

33
<PropertyGroup>
4-
<TargetFrameworks>MonoAndroid11.0;MonoAndroid12.0</TargetFrameworks>
4+
<TargetFrameworks>MonoAndroid12.0;net6.0-android</TargetFrameworks>
55
<PackageDescription>Provides ReactiveUI.Validation extensions for the AndroidX Library</PackageDescription>
66
<PackageId>ReactiveUI.Validation.AndroidX</PackageId>
77
<NoWarn>$(NoWarn);CS1591</NoWarn>

src/ReactiveUI.Validation.Tests/API/ApiApprovalTests.ValidationProject.net6.0.approved.txt

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,18 @@ namespace ReactiveUI.Validation.Abstractions
99
}
1010
namespace ReactiveUI.Validation.Collections
1111
{
12-
public class ValidationText : System.Collections.Generic.IEnumerable<string>, System.Collections.IEnumerable
12+
public interface IValidationText : System.Collections.Generic.IEnumerable<string>, System.Collections.Generic.IReadOnlyCollection<string>, System.Collections.Generic.IReadOnlyList<string>, System.Collections.IEnumerable
1313
{
14-
public static readonly ReactiveUI.Validation.Collections.ValidationText Empty;
15-
public static readonly ReactiveUI.Validation.Collections.ValidationText None;
16-
public int Count { get; }
17-
public string this[int index] { get; }
18-
public System.Collections.Generic.IEnumerator<string> GetEnumerator() { }
19-
public string ToSingleLine(string? separator = ",") { }
20-
public static ReactiveUI.Validation.Collections.ValidationText Create(System.Collections.Generic.IEnumerable<ReactiveUI.Validation.Collections.ValidationText>? validationTexts) { }
21-
public static ReactiveUI.Validation.Collections.ValidationText Create(System.Collections.Generic.IEnumerable<string>? validationTexts) { }
22-
public static ReactiveUI.Validation.Collections.ValidationText Create(params string?[]? validationTexts) { }
14+
string ToSingleLine(string? separator = ",");
15+
}
16+
public static class ValidationText
17+
{
18+
public static readonly ReactiveUI.Validation.Collections.IValidationText Empty;
19+
public static readonly ReactiveUI.Validation.Collections.IValidationText None;
20+
public static ReactiveUI.Validation.Collections.IValidationText Create(System.Collections.Generic.IEnumerable<ReactiveUI.Validation.Collections.IValidationText>? validationTexts) { }
21+
public static ReactiveUI.Validation.Collections.IValidationText Create(System.Collections.Generic.IEnumerable<string?>? validationTexts) { }
22+
public static ReactiveUI.Validation.Collections.IValidationText Create(string? validationText) { }
23+
public static ReactiveUI.Validation.Collections.IValidationText Create(params string?[]? validationTexts) { }
2324
}
2425
}
2526
namespace ReactiveUI.Validation.Comparators
@@ -43,7 +44,7 @@ namespace ReactiveUI.Validation.Components.Abstractions
4344
public interface IValidationComponent
4445
{
4546
bool IsValid { get; }
46-
ReactiveUI.Validation.Collections.ValidationText? Text { get; }
47+
ReactiveUI.Validation.Collections.IValidationText? Text { get; }
4748
System.IObservable<ReactiveUI.Validation.States.IValidationState> ValidationStatusChange { get; }
4849
}
4950
}
@@ -55,7 +56,7 @@ namespace ReactiveUI.Validation.Components
5556
public bool IsValid { get; }
5657
public System.Collections.Generic.IEnumerable<string> Properties { get; }
5758
public int PropertyCount { get; }
58-
public ReactiveUI.Validation.Collections.ValidationText? Text { get; }
59+
public ReactiveUI.Validation.Collections.IValidationText? Text { get; }
5960
public System.IObservable<ReactiveUI.Validation.States.IValidationState> ValidationStatusChange { get; }
6061
protected void AddProperty<TProp>(System.Linq.Expressions.Expression<System.Func<TViewModel, TProp>> property) { }
6162
public bool ContainsPropertyName(string propertyName, bool exclusively = false) { }
@@ -74,11 +75,11 @@ namespace ReactiveUI.Validation.Components
7475
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
7576
{
7677
protected ObservableValidationBase(System.IObservable<ReactiveUI.Validation.States.IValidationState> observable) { }
77-
protected ObservableValidationBase(TViewModel viewModel, System.IObservable<TValue> observable, System.Func<TViewModel, TValue, bool> isValidFunc, System.Func<TViewModel, TValue, bool, ReactiveUI.Validation.Collections.ValidationText> messageFunc) { }
78+
protected ObservableValidationBase(TViewModel viewModel, System.IObservable<TValue> observable, System.Func<TViewModel, TValue, bool> isValidFunc, System.Func<TViewModel, TValue, bool, ReactiveUI.Validation.Collections.IValidationText> messageFunc) { }
7879
public bool IsValid { get; }
7980
public System.Collections.Generic.IEnumerable<string> Properties { get; }
8081
public int PropertyCount { get; }
81-
public ReactiveUI.Validation.Collections.ValidationText? Text { get; }
82+
public ReactiveUI.Validation.Collections.IValidationText? Text { get; }
8283
public System.IObservable<ReactiveUI.Validation.States.IValidationState> ValidationStatusChange { get; }
8384
protected void AddProperty<TProp>(System.Linq.Expressions.Expression<System.Func<TViewModel, TProp>> property) { }
8485
public bool ContainsPropertyName(string propertyName, bool exclusively = false) { }
@@ -110,7 +111,7 @@ namespace ReactiveUI.Validation.Contexts
110111
{
111112
public ValidationContext(System.Reactive.Concurrency.IScheduler? scheduler = null) { }
112113
public bool IsValid { get; }
113-
public ReactiveUI.Validation.Collections.ValidationText Text { get; }
114+
public ReactiveUI.Validation.Collections.IValidationText Text { get; }
114115
public System.IObservable<bool> Valid { get; }
115116
public System.IObservable<ReactiveUI.Validation.States.IValidationState> ValidationStatusChange { get; }
116117
public System.Collections.ObjectModel.ReadOnlyObservableCollection<ReactiveUI.Validation.Components.Abstractions.IValidationComponent> Validations { get; }
@@ -180,7 +181,7 @@ namespace ReactiveUI.Validation.Formatters.Abstractions
180181
{
181182
public interface IValidationTextFormatter<out TOut>
182183
{
183-
TOut Format(ReactiveUI.Validation.Collections.ValidationText validationText);
184+
TOut Format(ReactiveUI.Validation.Collections.IValidationText validationText);
184185
}
185186
}
186187
namespace ReactiveUI.Validation.Formatters
@@ -189,7 +190,7 @@ namespace ReactiveUI.Validation.Formatters
189190
{
190191
public SingleLineFormatter(string? separator = null) { }
191192
public static ReactiveUI.Validation.Formatters.SingleLineFormatter Default { get; }
192-
public string Format(ReactiveUI.Validation.Collections.ValidationText? validationText) { }
193+
public string Format(ReactiveUI.Validation.Collections.IValidationText? validationText) { }
193194
}
194195
}
195196
namespace ReactiveUI.Validation.Helpers
@@ -207,7 +208,7 @@ namespace ReactiveUI.Validation.Helpers
207208
{
208209
public ValidationHelper(ReactiveUI.Validation.Components.Abstractions.IValidationComponent validation, System.IDisposable? cleanup = null) { }
209210
public bool IsValid { get; }
210-
public ReactiveUI.Validation.Collections.ValidationText? Message { get; }
211+
public ReactiveUI.Validation.Collections.IValidationText? Message { get; }
211212
public System.IObservable<ReactiveUI.Validation.States.IValidationState> ValidationChanged { get; }
212213
public void Dispose() { }
213214
protected virtual void Dispose(bool disposing) { }
@@ -218,15 +219,15 @@ namespace ReactiveUI.Validation.States
218219
public interface IValidationState
219220
{
220221
bool IsValid { get; }
221-
ReactiveUI.Validation.Collections.ValidationText Text { get; }
222+
ReactiveUI.Validation.Collections.IValidationText Text { get; }
222223
}
223224
public class ValidationState : ReactiveUI.Validation.States.IValidationState
224225
{
225-
public static readonly ReactiveUI.Validation.States.ValidationState Valid;
226-
public ValidationState(bool isValid, ReactiveUI.Validation.Collections.ValidationText text) { }
226+
public static readonly ReactiveUI.Validation.States.IValidationState Valid;
227+
public ValidationState(bool isValid, ReactiveUI.Validation.Collections.IValidationText text) { }
227228
public ValidationState(bool isValid, string text) { }
228229
public bool IsValid { get; }
229-
public ReactiveUI.Validation.Collections.ValidationText Text { get; }
230+
public ReactiveUI.Validation.Collections.IValidationText Text { get; }
230231
}
231232
}
232233
namespace ReactiveUI.Validation.ValidationBindings.Abstractions
@@ -257,4 +258,4 @@ namespace ReactiveUI.Validation.ValidationBindings
257258
where TView : ReactiveUI.IViewFor<TViewModel>
258259
where TViewModel : class, ReactiveUI.IReactiveObject, ReactiveUI.Validation.Abstractions.IValidatableViewModel { }
259260
}
260-
}
261+
}

src/ReactiveUI.Validation.Tests/NotifyDataErrorInfoTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,6 @@ private class PrefixFormatter : IValidationTextFormatter<string>
295295

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

298-
public string Format(ValidationText validationText) => $"{_prefix} {validationText.ToSingleLine()}";
298+
public string Format(IValidationText validationText) => $"{_prefix} {validationText.ToSingleLine()}";
299299
}
300-
}
300+
}

src/ReactiveUI.Validation.Tests/ValidationBindingTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -787,7 +787,7 @@ public CustomValidationState(bool isValid, string message)
787787
Text = isValid ? ValidationText.Empty : ValidationText.Create(message);
788788
}
789789

790-
public ValidationText Text { get; }
790+
public IValidationText Text { get; }
791791

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

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

801-
public string Format(ValidationText validationText) => _text;
801+
public string Format(IValidationText validationText) => _text;
802802
}
803-
}
803+
}

src/ReactiveUI.Validation.Tests/ValidationTextTests.cs

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public class ValidationTextTests
2323
[Fact]
2424
public void NoneValidationTextIsEmpty()
2525
{
26-
ValidationText vt = ValidationText.None;
26+
IValidationText vt = ValidationText.None;
2727

2828
Assert.Equal(0, vt.Count);
2929

@@ -40,7 +40,7 @@ public void NoneValidationTextIsEmpty()
4040
[Fact]
4141
public void EmptyValidationTextIsSingleEmpty()
4242
{
43-
ValidationText vt = ValidationText.Empty;
43+
IValidationText vt = ValidationText.Empty;
4444

4545
Assert.Equal(1, vt.Count);
4646

@@ -58,7 +58,7 @@ public void EmptyValidationTextIsSingleEmpty()
5858
[Fact]
5959
public void ParameterlessCreateReturnsNone()
6060
{
61-
ValidationText vt = ValidationText.Create();
61+
IValidationText vt = ValidationText.Create();
6262

6363
Assert.Same(ValidationText.None, vt);
6464
}
@@ -69,18 +69,18 @@ public void ParameterlessCreateReturnsNone()
6969
[Fact]
7070
public void CreateEmptyStringEnumerableReturnsNone()
7171
{
72-
ValidationText vt = ValidationText.Create((IEnumerable<string>)Array.Empty<string>());
72+
IValidationText vt = ValidationText.Create((IEnumerable<string>)Array.Empty<string>());
7373

7474
Assert.Same(ValidationText.None, vt);
7575
}
7676

7777
/// <summary>
78-
/// Verifies that calling <see cref="ValidationText.Create(IEnumerable{ValidationText})"/> with an empty enumerable <see cref="ValidationText.None"/>.
78+
/// Verifies that calling <see cref="ValidationText.Create(IEnumerable{IValidationText})"/> with an empty enumerable <see cref="ValidationText.None"/>.
7979
/// </summary>
8080
[Fact]
8181
public void CreateEmptyValidationTextEnumerableReturnsNone()
8282
{
83-
ValidationText vt = ValidationText.Create(Array.Empty<ValidationText>());
83+
IValidationText vt = ValidationText.Create(Array.Empty<IValidationText>());
8484

8585
Assert.Same(ValidationText.None, vt);
8686
}
@@ -91,7 +91,7 @@ public void CreateEmptyValidationTextEnumerableReturnsNone()
9191
[Fact]
9292
public void CreateNullReturnsNone()
9393
{
94-
ValidationText vt = ValidationText.Create((string)null);
94+
IValidationText vt = ValidationText.Create((string)null);
9595

9696
Assert.Same(ValidationText.None, vt);
9797
}
@@ -102,18 +102,18 @@ public void CreateNullReturnsNone()
102102
[Fact]
103103
public void CreateNullStringEnumerableReturnsNone()
104104
{
105-
ValidationText vt = ValidationText.Create((IEnumerable<string>)null);
105+
IValidationText vt = ValidationText.Create((IEnumerable<string>)null);
106106

107107
Assert.Same(ValidationText.None, vt);
108108
}
109109

110110
/// <summary>
111-
/// Verifies that calling <see cref="ValidationText.Create(IEnumerable{ValidationText})"/> with <see langword="null"/> returns <see cref="ValidationText.None"/>.
111+
/// Verifies that calling <see cref="ValidationText.Create(IEnumerable{IValidationText})"/> with <see langword="null"/> returns <see cref="ValidationText.None"/>.
112112
/// </summary>
113113
[Fact]
114114
public void CreateNullValidationTextEnumerableReturnsNone()
115115
{
116-
ValidationText vt = ValidationText.Create((IEnumerable<ValidationText>)null);
116+
IValidationText vt = ValidationText.Create((IEnumerable<IValidationText>)null);
117117

118118
Assert.Same(ValidationText.None, vt);
119119
}
@@ -124,18 +124,18 @@ public void CreateNullValidationTextEnumerableReturnsNone()
124124
[Fact]
125125
public void CreateNullItemStringEnumerableReturnsNone()
126126
{
127-
ValidationText vt = ValidationText.Create((IEnumerable<string>)new string[] { null });
127+
IValidationText vt = ValidationText.Create((IEnumerable<string>)new string[] { null });
128128

129129
Assert.Same(ValidationText.None, vt);
130130
}
131131

132132
/// <summary>
133-
/// Verifies that calling <see cref="ValidationText.Create(IEnumerable{ValidationText})"/> with an enumerable containing <see cref="ValidationText.None"/> returns <see cref="ValidationText.None"/>.
133+
/// Verifies that calling <see cref="ValidationText.Create(IEnumerable{IValidationText})"/> with an enumerable containing <see cref="ValidationText.None"/> returns <see cref="ValidationText.None"/>.
134134
/// </summary>
135135
[Fact]
136136
public void CreateNoneItemValidationTextEnumerableReturnsNone()
137137
{
138-
ValidationText vt = ValidationText.Create(new[] { ValidationText.None });
138+
IValidationText vt = ValidationText.Create(new[] { ValidationText.None });
139139

140140
Assert.Same(ValidationText.None, vt);
141141
}
@@ -146,7 +146,7 @@ public void CreateNoneItemValidationTextEnumerableReturnsNone()
146146
[Fact]
147147
public void CreateNoneItemStringEnumerableReturnsNone()
148148
{
149-
ValidationText vt = ValidationText.Create(ValidationText.None);
149+
IValidationText vt = ValidationText.Create(ValidationText.None);
150150

151151
Assert.Same(ValidationText.None, vt);
152152
}
@@ -157,7 +157,7 @@ public void CreateNoneItemStringEnumerableReturnsNone()
157157
[Fact]
158158
public void CreateStringEmptyReturnsEmpty()
159159
{
160-
ValidationText vt = ValidationText.Create(string.Empty);
160+
IValidationText vt = ValidationText.Create(string.Empty);
161161

162162
Assert.Same(ValidationText.Empty, vt);
163163
}
@@ -168,7 +168,7 @@ public void CreateStringEmptyReturnsEmpty()
168168
[Fact]
169169
public void CreateSingleStringEmptyReturnsEmpty()
170170
{
171-
ValidationText vt = ValidationText.Create((IEnumerable<string>)new[] { string.Empty });
171+
IValidationText vt = ValidationText.Create((IEnumerable<string>)new[] { string.Empty });
172172

173173
Assert.Same(ValidationText.Empty, vt);
174174
}
@@ -179,41 +179,41 @@ public void CreateSingleStringEmptyReturnsEmpty()
179179
[Fact]
180180
public void CreateValidationTextEmptyReturnsEmpty()
181181
{
182-
ValidationText vt = ValidationText.Create(new[] { ValidationText.Empty });
182+
IValidationText vt = ValidationText.Create(new[] { ValidationText.Empty });
183183

184184
Assert.Same(ValidationText.Empty, vt);
185185
}
186186

187187
/// <summary>
188-
/// Verifies that calling <see cref="ValidationText.Create(IEnumerable{ValidationText})"/> with an enumerable containing two <see cref="ValidationText.None"/> returns <see cref="ValidationText.None"/>.
188+
/// Verifies that calling <see cref="ValidationText.Create(IEnumerable{IValidationText})"/> with an enumerable containing two <see cref="ValidationText.None"/> returns <see cref="ValidationText.None"/>.
189189
/// </summary>
190190
[Fact]
191191
public void CombineValidationTextNoneReturnsNone()
192192
{
193-
ValidationText vt = ValidationText.Create(new[] { ValidationText.None, ValidationText.None });
193+
IValidationText vt = ValidationText.Create(new[] { ValidationText.None, ValidationText.None });
194194

195195
Assert.Same(ValidationText.None, vt);
196196
}
197197

198198
/// <summary>
199-
/// 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"/>.
199+
/// 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"/>.
200200
/// </summary>
201201
[Fact]
202202
public void CombineValidationTextEmptyAndNoneReturnsEmpty()
203203
{
204-
ValidationText vt = ValidationText.Create(new[] { ValidationText.None, ValidationText.Empty });
204+
IValidationText vt = ValidationText.Create(new[] { ValidationText.None, ValidationText.Empty });
205205

206206
Assert.Same(ValidationText.Empty, vt);
207207
}
208208

209209
/// <summary>
210-
/// Verifies that calling <see cref="ValidationText.Create(IEnumerable{ValidationText})"/> with an enumerable containing two <see cref="ValidationText.Empty"/>
210+
/// Verifies that calling <see cref="ValidationText.Create(IEnumerable{IValidationText})"/> with an enumerable containing two <see cref="ValidationText.Empty"/>
211211
/// returns a single <see cref="ValidationText"/> with two empty strings.
212212
/// </summary>
213213
[Fact]
214214
public void CombineValidationTextEmptyReturnsTwoEmpty()
215215
{
216-
ValidationText vt = ValidationText.Create(new[] { ValidationText.Empty, ValidationText.Empty });
216+
IValidationText vt = ValidationText.Create(new[] { ValidationText.Empty, ValidationText.Empty });
217217

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

228228
Assert.Equal("|", vt.ToSingleLine("|"));
229229
}
230-
}
230+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (c) 2022 .NET Foundation and Contributors. All rights reserved.
2+
// Licensed to the .NET Foundation under one or more agreements.
3+
// The .NET Foundation licenses this file to you under the MIT license.
4+
// See the LICENSE file in the project root for full license information.
5+
6+
using System.Collections;
7+
using System.Collections.Generic;
8+
9+
namespace ReactiveUI.Validation.Collections;
10+
11+
internal sealed class ArrayValidationText : IValidationText
12+
{
13+
private readonly string[] _texts;
14+
15+
internal ArrayValidationText(string[] texts) => _texts = texts;
16+
17+
public int Count => _texts.Length;
18+
19+
public string this[int index] => _texts[index];
20+
21+
public IEnumerator<string> GetEnumerator() => ((IEnumerable<string>)_texts).GetEnumerator();
22+
23+
IEnumerator IEnumerable.GetEnumerator() => _texts.GetEnumerator();
24+
25+
public string ToSingleLine(string? separator) => string.Join(separator, _texts);
26+
}

0 commit comments

Comments
 (0)