Bugfix Issue #1705 (MAUI: 184): Allow null handling for BaseConverterOneWay<TFrom, TTo> (#1733)

* Fix typo ArgumenException for unit tests

* Add AllowsNullOrDefault handling for BaseConverterOneWay
Fix summary xml doc for ConvertBack of BaseConverterOneWay

* Add BaseConverterOneWay_Tests for new AllowsNullOrDefault

* Implement recommended changes
- Rename test converter to MockConverterOneWay
- Change ArgumentException to ArgumentNullException in BaseConverterOneWay<TFrom, TTo> when disallowing nulls
- Simplify unit test data generation and execution

* Update null check in BaseConverterOneWay<TFrom, TTo>

* Implement recommended changes

- Change check order back to original in BaseConverterOneWay<TFrom, TTo>
- Fix missing first paramName argument for ArgumentNullException in BaseConverterOneWay<TFrom, TTo>
- Refactor BaseConverterOneWay_Tests

* Rename property AllowsNullOrDefault to AllowsNull of BaseConverterOneWay<TFrom, TTo>

* Update IsNullOrEmptyConverter to inherit from BaseConverterOneWay<TFrom, TTo>

* Migrated more converters to base

* Revert compare converter changes

* Fixed unit tests and code review tidy up

* Switch to separate nullable converter base class

* Add null support to BaseConverter

NullableBaseConverter now completes symmetry with NullableBaseConverterOneWay.

Migrate converters to use NullableBaseConverter where possible.

Migrate tests to new approach.

* Remove Null-Forgiving Operator

* Rename converters to start with Base

* Code review improvement

* Add global.json

Ensures .NET 6.0 is the minimum version in use

* `dotnet format`

* Move global.json to root folder

* `dotnet format`

Co-authored-by: Pascal Ried <p.ried@comventure.de>
Co-authored-by: Shaun Lawrence <shaunrlawrence@gmail.com>
Co-authored-by: Pedro Jesus <pedrojesus.cefet@gmail.com>
Co-authored-by: Brandon Minnick <13558917+brminnick@users.noreply.github.com>
This commit is contained in:
Countryen 2021-12-03 15:37:41 +01:00 коммит произвёл GitHub
Родитель cbf4a19dc7
Коммит 35d7d5f762
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
116 изменённых файлов: 595 добавлений и 618 удалений

Просмотреть файл

@ -2,7 +2,7 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(MSBuildProjectExtension)' == '.csproj'">
<LangVersion>9.0</LangVersion>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<WarningsAsErrors>nullable</WarningsAsErrors>
</PropertyGroup>

6
global.json Normal file
Просмотреть файл

@ -0,0 +1,6 @@
{
"sdk": {
"version": "6.0.*",
"rollForward": "latestMajor"
}
}

Просмотреть файл

@ -90,7 +90,7 @@ namespace Xamarin.CommunityToolkit.Sample.WPF
Element.Lines.Clear();
}
var lines = Element.MultiLineMode ? e.Added : new StrokeCollection() {e.Added.First()};
var lines = Element.MultiLineMode ? e.Added : new StrokeCollection() { e.Added.First() };
foreach (var line in lines)
{
@ -100,7 +100,7 @@ namespace Xamarin.CommunityToolkit.Sample.WPF
Points = new ObservableCollection<Point>(points),
LineColor = Color.FromRgba(line.DrawingAttributes.Color.R, line.DrawingAttributes.Color.G,
line.DrawingAttributes.Color.B, line.DrawingAttributes.Color.A),
LineWidth = (float) line.DrawingAttributes.Width
LineWidth = (float)line.DrawingAttributes.Width
});
}
@ -127,12 +127,12 @@ namespace Xamarin.CommunityToolkit.Sample.WPF
var lines = Element.MultiLineMode
? Element.Lines
: Element.Lines.Any()
? new ObservableCollection<Line> {Element.Lines.LastOrDefault()}
? new ObservableCollection<Line> { Element.Lines.LastOrDefault() }
: new ObservableCollection<Line>();
foreach (var line in lines)
{
var stylusPoints = line.Points.Select(point => new StylusPoint(point.X, point.Y)).ToList();
if (stylusPoints is {Count: > 0})
if (stylusPoints is { Count: > 0 })
{
var stroke = new Stroke(new StylusPointCollection(stylusPoints))
{

Просмотреть файл

@ -21,6 +21,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
..\.editorconfig = ..\.editorconfig
..\Directory.Build.props = ..\Directory.Build.props
..\Xamarin.CommunityToolkit.ruleset = ..\Xamarin.CommunityToolkit.ruleset
..\global.json = ..\global.json
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.CommunityToolkit.Sample.WPF", "XCT.Sample.WPF\Xamarin.CommunityToolkit.Sample.WPF.csproj", "{C4D6CD2D-8DF4-4D46-936C-1AB31C87B5EA}"

Просмотреть файл

@ -22,4 +22,4 @@ namespace Xamarin.CommunityToolkit.Sample
MainPage = new BaseNavigationPage(new WelcomePage());
}
}
}
}

Просмотреть файл

@ -7,4 +7,4 @@
InitializeComponent();
}
}
}
}

Просмотреть файл

@ -3,5 +3,5 @@
public partial class AnimationBehaviorPage : BasePage
{
public AnimationBehaviorPage() => InitializeComponent();
}
}
}

Просмотреть файл

@ -4,4 +4,4 @@
{
public BoolToObjectConverterPage() => InitializeComponent();
}
}
}

Просмотреть файл

@ -4,4 +4,4 @@
{
public CompareConverterPage() => InitializeComponent();
}
}
}

Просмотреть файл

@ -4,4 +4,4 @@
{
public DoubleToIntConverterPage() => InitializeComponent();
}
}
}

Просмотреть файл

@ -1,7 +1,7 @@
namespace Xamarin.CommunityToolkit.Sample.Pages.Converters
{
public partial class EnumToBoolConverterPage
{
public EnumToBoolConverterPage() => InitializeComponent();
}
public partial class EnumToBoolConverterPage
{
public EnumToBoolConverterPage() => InitializeComponent();
}
}

Просмотреть файл

@ -4,4 +4,4 @@
{
public EnumToIntConverterPage() => InitializeComponent();
}
}
}

Просмотреть файл

@ -4,4 +4,4 @@
{
public EqualConverterPage() => InitializeComponent();
}
}
}

Просмотреть файл

@ -4,4 +4,4 @@
{
public IndexToArrayItemConverterPage() => InitializeComponent();
}
}
}

Просмотреть файл

@ -4,4 +4,4 @@
{
public IntToBoolConverterPage() => InitializeComponent();
}
}
}

Просмотреть файл

@ -4,4 +4,4 @@
{
public InvertedBoolConverterPage() => InitializeComponent();
}
}
}

Просмотреть файл

@ -4,4 +4,4 @@
{
public IsInRangeConverterPage() => InitializeComponent();
}
}
}

Просмотреть файл

@ -4,4 +4,4 @@
{
public IsNotNullOrEmptyConverterPage() => InitializeComponent();
}
}
}

Просмотреть файл

@ -7,4 +7,4 @@
InitializeComponent();
}
}
}
}

Просмотреть файл

@ -7,4 +7,4 @@
InitializeComponent();
}
}
}
}

Просмотреть файл

@ -4,4 +4,4 @@
{
public ListToStringConverterPage() => InitializeComponent();
}
}
}

Просмотреть файл

@ -4,4 +4,4 @@
{
public MathExpressionConverterPage() => InitializeComponent();
}
}
}

Просмотреть файл

@ -4,4 +4,4 @@
{
public NotEqualConverterPage() => InitializeComponent();
}
}
}

Просмотреть файл

@ -7,4 +7,4 @@
InitializeComponent();
}
}
}
}

Просмотреть файл

@ -4,4 +4,4 @@
{
public TextCaseConverterPage() => InitializeComponent();
}
}
}

Просмотреть файл

@ -4,4 +4,4 @@
{
public ShadowEffectPage() => InitializeComponent();
}
}
}

Просмотреть файл

@ -4,4 +4,4 @@
{
public StatusBarEffectPage() => InitializeComponent();
}
}
}

Просмотреть файл

@ -1,6 +1,6 @@
namespace Xamarin.CommunityToolkit.Sample.Pages.TestCases.Popups
{
public partial class SimplePopup
public partial class SimplePopup
{
public SimplePopup() => InitializeComponent();
}

Просмотреть файл

@ -13,4 +13,4 @@ namespace Xamarin.CommunityToolkit.Sample.Pages.TestCases
public ICommand LongPressCommand { get; }
}
}
}

Просмотреть файл

@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using Xamarin.Forms;
using Xamarin.CommunityToolkit.UI.Views;
using System.Collections.ObjectModel;
using System.Linq;
using Xamarin.CommunityToolkit.UI.Views;
using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.Sample.Pages.Views
{

Просмотреть файл

@ -15,4 +15,4 @@ namespace Xamarin.CommunityToolkit.Sample.Pages.Views.Popups
public static Size Large => new Size(0.9 * (DeviceDisplay.MainDisplayInfo.Width / DeviceDisplay.MainDisplayInfo.Density), 0.8 * (DeviceDisplay.MainDisplayInfo.Height / DeviceDisplay.MainDisplayInfo.Density));
}
}
}

Просмотреть файл

@ -1,6 +1,6 @@
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.CommunityToolkit.PlatformConfiguration.iOSSpecific;
using Xamarin.CommunityToolkit.PlatformConfiguration.iOSSpecific;
using Xamarin.CommunityToolkit.PlatformConfiguration.WindowsSpecific;
using Xamarin.Forms.PlatformConfiguration;
namespace Xamarin.CommunityToolkit.Sample.Pages.Views.Popups
{

Просмотреть файл

@ -13,4 +13,4 @@ namespace Xamarin.CommunityToolkit.Sample.Pages.Views
public ICommand UpdateTextCommand { get; }
= new Command<TextSwitcher>(textSwitcher => textSwitcher.Text = Path.GetRandomFileName());
}
}
}

Просмотреть файл

@ -88,5 +88,4 @@ namespace Xamarin.CommunityToolkit.Sample.ViewModels.Animations
CreateAnimation = createAnimation;
}
}
}
}

Просмотреть файл

@ -121,4 +121,4 @@ namespace Xamarin.CommunityToolkit.Sample.ViewModels.Converters
"A group of converters that convert a Color to your strings values (RGB, HEX, HSL, etc)"),
};
}
}
}

Просмотреть файл

@ -10,4 +10,4 @@
set => SetProperty(ref index, value);
}
}
}
}

Просмотреть файл

@ -14,4 +14,4 @@ namespace Xamarin.CommunityToolkit.Sample.ViewModels.Converters
set => SetProperty(ref selectedState, value);
}
}
}
}

Просмотреть файл

@ -9,7 +9,7 @@ namespace Xamarin.CommunityToolkit.Sample.ViewModels.Converters
const string img1 = "button.png";
const string img2 = "logo.png";
const string imagesPath = "Images";
string defaultNamespace;
string? imageName;
@ -38,4 +38,4 @@ namespace Xamarin.CommunityToolkit.Sample.ViewModels.Converters
string BuildEmbededImagePath(string imgName)
=> $"{defaultNamespace}.{imagesPath}.{imgName}";
}
}
}

Просмотреть файл

@ -14,4 +14,4 @@
}
}
}
}
}

Просмотреть файл

@ -10,4 +10,4 @@
set => SetProperty(ref index, value);
}
}
}
}

Просмотреть файл

@ -29,4 +29,4 @@ namespace Xamarin.CommunityToolkit.Sample.ViewModels.Converters
set => SetProperty(ref selectedItem, value);
}
}
}
}

Просмотреть файл

@ -15,4 +15,4 @@ namespace Xamarin.CommunityToolkit.Sample.ViewModels.Effects
"A XAML extension that helps to display images from embedded resources"),
};
}
}
}

Просмотреть файл

@ -69,8 +69,8 @@ namespace Xamarin.CommunityToolkit.Sample.ViewModels.Markup
public ICommand OpenHelpCommand { get; }
void Back()
{
}
{
}
void Like(Tweet tweet) => tweet.IsLikedByMe = !tweet.IsLikedByMe;

Просмотреть файл

@ -1,7 +1,7 @@
using System.Windows.Input;
using Xamarin.Forms;
using Xamarin.CommunityToolkit.Sample.Pages.TestCases.Popups;
using Xamarin.CommunityToolkit.Extensions;
using Xamarin.CommunityToolkit.Sample.Pages.TestCases.Popups;
using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.Sample.ViewModels.TestCases.Popups
{
@ -32,4 +32,4 @@ namespace Xamarin.CommunityToolkit.Sample.ViewModels.TestCases.Popups
await Navigation.PopModalAsync();
}
}
}
}

Просмотреть файл

@ -6,7 +6,7 @@ namespace Xamarin.CommunityToolkit.Sample.ViewModels.TestCases
{
public class TabViewItemBindingViewModel : BaseViewModel
{
public static TabViewItemBindingViewModel Current { get; } = new ();
public static TabViewItemBindingViewModel Current { get; } = new();
int countClick;

Просмотреть файл

@ -58,4 +58,4 @@ namespace Xamarin.CommunityToolkit.Sample.ViewModels.Views
}
}
}
}
}

Просмотреть файл

@ -6,4 +6,4 @@
public string Message { get; } = "This is a native popup with a Xamarin.Forms View being rendered. The behaviors of the popup will confirm to 100% native look and feel, but still allows you to use your Xamarin.Forms controls.";
}
}
}

Просмотреть файл

@ -23,4 +23,4 @@ namespace Xamarin.CommunityToolkit.Sample.ViewModels.Views.Popups
Navigation.ShowPopup(popup);
}
}
}
}

Просмотреть файл

@ -76,4 +76,4 @@ namespace Xamarin.CommunityToolkit.Sample.ViewModels.Views.Popups
BottomRight = 8
}
}
}
}

Просмотреть файл

@ -6,4 +6,4 @@
public string Message { get; } = "This is a native popup with a Xamarin.Forms View being rendered. The behaviors of the popup will confirm to 100% native look and feel, but still allows you to use your Xamarin.Forms controls.";
}
}
}

Просмотреть файл

@ -24,4 +24,4 @@ namespace Xamarin.CommunityToolkit.Sample.ViewModels.Views.Tabs
public LazyTestViewModel() => Title = "Lazy Tab Sample";
}
}
}

Просмотреть файл

@ -14,4 +14,4 @@ namespace Xamarin.CommunityToolkit.Sample.ViewModels.Views.Tabs
set => SetProperty(ref loadedViews, value);
}
}
}
}

Просмотреть файл

@ -66,4 +66,4 @@ namespace Xamarin.CommunityToolkit.Sample.ViewModels.Views
"The popup control renders native popups from the shared code. This page demonstrates a variety of different techniques for displaying native popups.")
};
}
}
}

Просмотреть файл

@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using NUnit.Framework;
using Xamarin.CommunityToolkit.Converters;
using Xamarin.CommunityToolkit.UnitTests.Mocks;
using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.UnitTests.Converters
{
[TestOf(typeof(BaseConverterOneWay<string, Color>))]
public class BaseConverterOneWay_Tests
{
[TestCaseSource(nameof(GetValidTestData))]
public void MockConverterOneWayConvert((bool ShouldAllowNull, string? Value, Color ExpectedResult) testCase)
{
var mockConverterOneWay = CreateConverter(testCase.ShouldAllowNull);
var result = mockConverterOneWay.Convert(testCase.Value, typeof(Color), null, CultureInfo.CurrentCulture);
Assert.AreEqual(result, testCase.ExpectedResult);
}
[TestCaseSource(nameof(GetInvalidTestData))]
public void MockConverterOneWayConvertInvalidValuesThrowException((bool ShouldAllowNull, string? Value, Type ExpectedExceptionType) testCase)
{
var mockConverterOneWay = CreateConverter(testCase.ShouldAllowNull);
Assert.Throws(testCase.ExpectedExceptionType, () => mockConverterOneWay.Convert(testCase.Value, typeof(Color), null, CultureInfo.CurrentCulture));
}
static IValueConverter CreateConverter(bool shouldAllowNull) =>
shouldAllowNull ? new MockNullableConverterOneWay() : new MockConverterOneWay();
static IEnumerable<(bool ShouldAllowNull, string? Value, Color ExpectedResult)> GetValidTestData()
{
yield return (true, "Red", Color.Red);
yield return (true, "Blue", Color.Blue);
yield return (true, null, Color.Black);
yield return (false, "Red", Color.Red);
yield return (false, "Blue", Color.Blue);
}
static IEnumerable<(bool ShouldAllowNull, string? Value, Type ExpectedExceptionType)> GetInvalidTestData()
{
yield return (true, "red", typeof(ArgumentException));
yield return (true, "Green", typeof(ArgumentException));
yield return (true, "red", typeof(ArgumentException));
yield return (true, "Green", typeof(ArgumentException));
yield return (false, null, typeof(ArgumentNullException));
}
}
}

Просмотреть файл

@ -37,7 +37,7 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
}
[TestCase("")]
public void BoolToObjectInValidValuesThrowArgumenException(object value)
public void BoolToObjectInValidValuesThrowArgumentException(object value)
{
var boolObjectConverter = new BoolToObjectConverter();
Assert.Throws<ArgumentException>(() => boolObjectConverter.Convert(value, typeof(BoolToObjectConverter_Tests), null, CultureInfo.CurrentCulture));

Просмотреть файл

@ -18,18 +18,17 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
var expectedValue = ImageSource.FromStream(() => memoryStream);
var byteArrayToImageSourceConverter = new ByteArrayToImageSourceConverter();
var byteArrayToImageSourceConverter = CreateConverter();
var result = byteArrayToImageSourceConverter.Convert(byteArray, typeof(ByteArrayToImageSourceConverter), null, CultureInfo.CurrentCulture);
Assert.IsTrue(StreamEquals(GetStreamFromImageSource((ImageSource?)result), memoryStream));
}
[TestCase("Random String Value")]
public void InvalidConverterValuesReturnsNull(object value)
{
var byteArrayToImageSourceConverter = new ByteArrayToImageSourceConverter();
var byteArrayToImageSourceConverter = CreateConverter();
Assert.Throws<ArgumentException>(() => byteArrayToImageSourceConverter.Convert(value, typeof(ByteArrayToImageSourceConverter), null, CultureInfo.CurrentCulture));
}
@ -63,5 +62,7 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
return true;
}
static IValueConverter CreateConverter() => new ByteArrayToImageSourceConverter();
}
}

Просмотреть файл

@ -11,6 +11,72 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
public const string TrueTestObject = nameof(TrueTestObject);
public const string FalseTestObject = nameof(FalseTestObject);
[TestCaseSource(nameof(GetTestData))]
public void CompareConverterConvert(IComparable value, CompareConverter.OperatorType comparisonOperator, IComparable comparingValue, object trueObject, object falseObject, object expectedResult)
{
var compareConverter = new CompareConverter
{
TrueObject = trueObject,
FalseObject = falseObject,
ComparisonOperator = comparisonOperator,
ComparingValue = comparingValue
};
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
var result = compareConverter.Convert(value, typeof(BoolToObjectConverter_Tests), null, CultureInfo.CurrentCulture);
#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type.
Assert.AreEqual(result, expectedResult);
}
static IEnumerable<object?[]> GetThrowArgumentExceptionTestData()
{
yield return new object?[] { new { Name = "Not IComparable" } };
yield return new object?[] { null };
}
[TestCaseSource(nameof(GetThrowArgumentExceptionTestData))]
public void CompareConverterInValidValuesThrowArgumentException(object value)
{
var compareConverter = new CompareConverter()
{
ComparingValue = 20d
};
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
Assert.Throws<ArgumentException>(() => compareConverter.Convert(value, typeof(BoolToObjectConverter_Tests), null, CultureInfo.CurrentCulture));
#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type.
}
[TestCase(20d, null, TrueTestObject, FalseTestObject)]
[TestCase(20d, 20d, TrueTestObject, null)]
[TestCase(20d, 20d, null, FalseTestObject)]
public void CompareConverterInValidValuesThrowArgumentNullException(object value, IComparable comparingValue, object trueObject, object falseObject)
{
var compareConverter = new CompareConverter()
{
ComparingValue = comparingValue,
FalseObject = falseObject,
TrueObject = trueObject
};
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
Assert.Throws<ArgumentNullException>(() => compareConverter.Convert(value, typeof(BoolToObjectConverter_Tests), null, CultureInfo.CurrentCulture));
#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type.
}
[TestCase(20d, (CompareConverter.OperatorType)10, 20d)]
public void CompareConverterInValidValuesThrowArgumentOutOfRangeException(object value, CompareConverter.OperatorType comparisonOperator, IComparable comparingValue)
{
var compareConverter = new CompareConverter
{
ComparisonOperator = comparisonOperator,
ComparingValue = comparingValue
};
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
Assert.Throws<ArgumentOutOfRangeException>(() => compareConverter.Convert(value, typeof(BoolToObjectConverter_Tests), null, CultureInfo.CurrentCulture));
#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type.
}
static IEnumerable<object?[]> GetTestData()
{
@ -35,7 +101,6 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
yield return new object?[] { 20d, CompareConverter.OperatorType.Smaller, 10d, TrueTestObject, FalseTestObject, FalseTestObject };
yield return new object?[] { 20d, CompareConverter.OperatorType.SmallerOrEqual, 10d, TrueTestObject, FalseTestObject, FalseTestObject };
yield return new object?[] { 20d, CompareConverter.OperatorType.Greater, 20d, null, null, false };
yield return new object?[] { 20d, CompareConverter.OperatorType.GreaterOrEqual, 20d, null, null, true };
yield return new object?[] { 20d, CompareConverter.OperatorType.Equal, 20d, null, null, true };
@ -57,64 +122,5 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
yield return new object?[] { 10d, CompareConverter.OperatorType.Smaller, 20d, null, null, true };
yield return new object?[] { 10d, CompareConverter.OperatorType.SmallerOrEqual, 20d, null, null, true };
}
[TestCaseSource(nameof(GetTestData))]
public void CompareConverterConvert(IComparable value, CompareConverter.OperatorType comparisonOperator, IComparable comparingValue, object trueObject, object falseObject, object expectedResult)
{
var compareConverter = new CompareConverter
{
TrueObject = trueObject,
FalseObject = falseObject,
ComparisonOperator = comparisonOperator,
ComparingValue = comparingValue
};
var result = compareConverter.Convert(value, typeof(BoolToObjectConverter_Tests), null!, CultureInfo.CurrentCulture);
Assert.AreEqual(result, expectedResult);
}
static IEnumerable<object?[]> GetThrowArgumenExceptionTestData()
{
yield return new object?[] { new { Name = "Not IComparable" } };
yield return new object?[] { null };
}
[TestCaseSource(nameof(GetThrowArgumenExceptionTestData))]
public void CompareConverterInValidValuesThrowArgumenException(object value)
{
var compareConverter = new CompareConverter()
{
ComparingValue = 20d
};
Assert.Throws<ArgumentException>(() => compareConverter.Convert(value, typeof(BoolToObjectConverter_Tests), null!, CultureInfo.CurrentCulture));
}
[TestCase(20d, null, TrueTestObject, FalseTestObject)]
[TestCase(20d, 20d, TrueTestObject, null)]
[TestCase(20d, 20d, null, FalseTestObject)]
public void CompareConverterInValidValuesThrowArgumentNullException(object value, IComparable comparingValue, object trueObject, object falseObject)
{
var compareConverter = new CompareConverter()
{
ComparingValue = comparingValue,
FalseObject = falseObject,
TrueObject = trueObject
};
Assert.Throws<ArgumentNullException>(() => compareConverter.Convert(value, typeof(BoolToObjectConverter_Tests), null!, CultureInfo.CurrentCulture));
}
[TestCase(20d, (CompareConverter.OperatorType)10, 20d)]
public void CompareConverterInValidValuesThrowArgumentOutOfRangeException(object value, CompareConverter.OperatorType comparisonOperator, IComparable comparingValue)
{
var compareConverter = new CompareConverter
{
ComparisonOperator = comparisonOperator,
ComparingValue = comparingValue
};
Assert.Throws<ArgumentOutOfRangeException>(() => compareConverter.Convert(value, typeof(BoolToObjectConverter_Tests), null!, CultureInfo.CurrentCulture));
}
}
}

Просмотреть файл

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using NUnit.Framework;
using Xamarin.CommunityToolkit.Converters;
using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.UnitTests.Converters
{
@ -17,35 +18,12 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
static readonly DateTimeOffset testDateTimeOffsetLocal = new DateTimeOffset(2020, 08, 25, 13, 37, 00, DateTimeOffset.Now.Offset);
static readonly DateTimeOffset testDateTimeOffsetUtc = new DateTimeOffset(2020, 08, 25, 13, 37, 00, DateTimeOffset.UtcNow.Offset);
public static IEnumerable<object[]> GetData() =>
new List<object[]>
{
new object[] { testDateTimeOffsetNow, testDateTimeNow },
new object[] { DateTimeOffset.MinValue, DateTime.MinValue },
new object[] { DateTimeOffset.MaxValue, DateTime.MaxValue },
new object[] { testDateTimeOffsetLocal, testDateTimeLocal },
new object[] { testDateTimeOffsetUtc, testDateTimeUtc },
new object[] { testDateTimeOffsetUtc, testDateTimeUnspecified },
};
public static IEnumerable<object[]> GetDataReverse() =>
new List<object[]>
{
new object[] { testDateTimeNow, testDateTimeOffsetNow },
new object[] { DateTime.MinValue, DateTimeOffset.MinValue },
new object[] { DateTime.MaxValue, DateTimeOffset.MaxValue },
new object[] { testDateTimeLocal, testDateTimeOffsetLocal },
new object[] { testDateTimeUtc, testDateTimeOffsetUtc },
new object[] { testDateTimeUnspecified, testDateTimeOffsetUtc },
};
[TestCaseSource(nameof(GetData))]
public void DateTimeOffsetConverter(DateTimeOffset value, DateTime expectedResult)
{
var dateTimeOffsetConverter = new DateTimeOffsetConverter();
var dateTimeOffsetConverter = CreateConverter();
var result = dateTimeOffsetConverter.Convert(value, typeof(DateTimeOffsetConverter_Tests), null,
CultureInfo.CurrentCulture);
var result = dateTimeOffsetConverter.Convert(value, typeof(DateTimeOffsetConverter_Tests), null, CultureInfo.CurrentCulture);
Assert.AreEqual(expectedResult, result);
}
@ -53,10 +31,9 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
[TestCaseSource(nameof(GetDataReverse))]
public void DateTimeOffsetConverterBack(DateTime value, DateTimeOffset expectedResult)
{
var dateTimeOffsetConverter = new DateTimeOffsetConverter();
var dateTimeOffsetConverter = CreateConverter();
var result = dateTimeOffsetConverter.ConvertBack(value, typeof(DateTimeOffsetConverter_Tests), null,
CultureInfo.CurrentCulture);
var result = dateTimeOffsetConverter.ConvertBack(value, typeof(DateTimeOffsetConverter_Tests), null, CultureInfo.CurrentCulture);
Assert.AreEqual(expectedResult, result);
}
@ -64,21 +41,39 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
[Test]
public void DateTimeOffsetConverter_GivenInvalidParameters_ThrowsException()
{
var dateTimeOffsetConverter = new DateTimeOffsetConverter();
var dateTimeOffsetConverter = CreateConverter();
Assert.Throws<ArgumentException>(() => dateTimeOffsetConverter.Convert("Not a DateTimeOffset",
typeof(DateTimeOffsetConverter_Tests), null,
CultureInfo.CurrentCulture));
Assert.Throws<ArgumentException>(() => dateTimeOffsetConverter.Convert("Not a DateTimeOffset", typeof(DateTimeOffsetConverter_Tests), null, CultureInfo.CurrentCulture));
}
[Test]
public void DateTimeOffsetConverterBack_GivenInvalidParameters_ThrowsException()
{
var dateTimeOffsetConverter = new DateTimeOffsetConverter();
var dateTimeOffsetConverter = CreateConverter();
Assert.Throws<ArgumentException>(() => dateTimeOffsetConverter.ConvertBack("Not a DateTime",
typeof(DateTimeOffsetConverter_Tests), null,
CultureInfo.CurrentCulture));
Assert.Throws<ArgumentException>(() => dateTimeOffsetConverter.ConvertBack("Not a DateTime", typeof(DateTimeOffsetConverter_Tests), null, CultureInfo.CurrentCulture));
}
static IValueConverter CreateConverter() => new DateTimeOffsetConverter();
static IEnumerable<object[]> GetData() => new List<object[]>
{
new object[] { testDateTimeOffsetNow, testDateTimeNow },
new object[] { DateTimeOffset.MinValue, DateTime.MinValue },
new object[] { DateTimeOffset.MaxValue, DateTime.MaxValue },
new object[] { testDateTimeOffsetLocal, testDateTimeLocal },
new object[] { testDateTimeOffsetUtc, testDateTimeUtc },
new object[] { testDateTimeOffsetUtc, testDateTimeUnspecified },
};
static IEnumerable<object[]> GetDataReverse() => new List<object[]>
{
new object[] { testDateTimeNow, testDateTimeOffsetNow },
new object[] { DateTime.MinValue, DateTimeOffset.MinValue },
new object[] { DateTime.MaxValue, DateTimeOffset.MaxValue },
new object[] { testDateTimeLocal, testDateTimeOffsetLocal },
new object[] { testDateTimeUtc, testDateTimeOffsetUtc },
new object[] { testDateTimeUnspecified, testDateTimeOffsetUtc },
};
}
}

Просмотреть файл

@ -31,7 +31,7 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
}
[TestCase("")]
public void DoubleToIntInValidValuesThrowArgumenException(object value)
public void DoubleToIntInValidValuesThrowArgumentException(object value)
{
var doubleToIntConverter = new DoubleToIntConverter();
Assert.Throws<ArgumentException>(() => doubleToIntConverter.Convert(value, typeof(BoolToObjectConverter_Tests), null, CultureInfo.CurrentCulture));

Просмотреть файл

@ -21,7 +21,7 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
[TestCase(null, null)]
[TestCase(null, 100)]
public void IndexToArrayInValidValuesThrowArgumenException(object value, object position)
public void IndexToArrayInValidValuesThrowArgumentException(object value, object position)
{
var indexToArrayConverter = new IndexToArrayItemConverter();
Assert.Throws<ArgumentException>(() => indexToArrayConverter.Convert(position, typeof(IndexToArrayItemConverter), value, CultureInfo.CurrentCulture));
@ -29,7 +29,7 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
[TestCase(new int[] { 1, 2, 3, 4, 5 }, 100)]
[TestCase(new int[] { 1, 2, 3, 4, 5 }, -1)]
public void IndexToArrayInValidValuesThrowArgumenOutOfRangeException(object value, object position)
public void IndexToArrayInValidValuesThrowArgumentOutOfRangeException(object value, object position)
{
var indexToArrayConverter = new IndexToArrayItemConverter();
Assert.Throws<ArgumentOutOfRangeException>(() => indexToArrayConverter.Convert(position, typeof(IndexToArrayItemConverter), value, CultureInfo.CurrentCulture));

Просмотреть файл

@ -2,6 +2,7 @@
using System.Globalization;
using NUnit.Framework;
using Xamarin.CommunityToolkit.Converters;
using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.UnitTests.Converters
{
@ -11,7 +12,7 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
[TestCase(0, false)]
public void IndexToArrayConverter(int value, bool expectedResult)
{
var intToBoolConverter = new IntToBoolConverter();
var intToBoolConverter = CreateConverter();
var result = intToBoolConverter.Convert(value, typeof(IntToBoolConverter_Tests), null, CultureInfo.CurrentCulture);
@ -22,7 +23,7 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
[TestCase(false, 0)]
public void IndexToArrayConverterBack(bool value, int expectedResult)
{
var intToBoolConverter = new IntToBoolConverter();
var intToBoolConverter = CreateConverter();
var result = intToBoolConverter.ConvertBack(value, typeof(IntToBoolConverter_Tests), null, CultureInfo.CurrentCulture);
@ -31,20 +32,34 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
[TestCase(2.5)]
[TestCase("")]
[TestCase(null)]
public void InValidConverterValuesThrowArgumenException(object value)
public void InvalidConverterValuesThrowArgumentException(object value)
{
var intToBoolConverter = new IntToBoolConverter();
Assert.Throws<ArgumentException>(() => intToBoolConverter.Convert(value, typeof(IndexToArrayItemConverter), null, CultureInfo.CurrentCulture));
var intToBoolConverter = CreateConverter();
Assert.Throws<ArgumentException>(() => intToBoolConverter.Convert(value, typeof(IntToBoolConverter_Tests), null, CultureInfo.CurrentCulture));
}
[TestCase(2.5)]
[TestCase("")]
[TestCase(null)]
public void InValidConverterBackValuesThrowArgumenException(object value)
public void InvalidConverterBackValuesThrowArgumentException(object value)
{
var intToBoolConverter = new IntToBoolConverter();
Assert.Throws<ArgumentException>(() => intToBoolConverter.ConvertBack(value, typeof(IndexToArrayItemConverter), null, CultureInfo.CurrentCulture));
var intToBoolConverter = CreateConverter();
Assert.Throws<ArgumentException>(() => intToBoolConverter.ConvertBack(value, typeof(IntToBoolConverter_Tests), null, CultureInfo.CurrentCulture));
}
[Test]
public void NullConverterValuesThrowArgumentException()
{
var intToBoolConverter = CreateConverter();
Assert.Throws<ArgumentNullException>(() => intToBoolConverter.Convert(null, typeof(IntToBoolConverter_Tests), null, CultureInfo.CurrentCulture));
}
[Test]
public void NullConverterBackValuesThrowArgumentException()
{
var intToBoolConverter = CreateConverter();
Assert.Throws<ArgumentNullException>(() => intToBoolConverter.ConvertBack(null, typeof(IntToBoolConverter_Tests), null, CultureInfo.CurrentCulture));
}
static IValueConverter CreateConverter() => new IntToBoolConverter();
}
}

Просмотреть файл

@ -2,6 +2,7 @@
using System.Globalization;
using NUnit.Framework;
using Xamarin.CommunityToolkit.Converters;
using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.UnitTests.Converters
{
@ -11,7 +12,7 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
[TestCase(false, true)]
public void InverterBoolConverter(bool value, bool expectedResult)
{
var inverterBoolConverter = new InvertedBoolConverter();
var inverterBoolConverter = CreateConverter();
var result = inverterBoolConverter.Convert(value, typeof(InvertedBoolConverter_Tests), null, CultureInfo.CurrentCulture);
@ -20,11 +21,19 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
[TestCase(2)]
[TestCase("")]
[TestCase(null)]
public void InValidConverterValuesThrowArgumenException(object value)
public void InvalidConverterValuesThrowArgumentException(object value)
{
var inverterBoolConverter = new InvertedBoolConverter();
var inverterBoolConverter = CreateConverter();
Assert.Throws<ArgumentException>(() => inverterBoolConverter.Convert(value, typeof(IndexToArrayItemConverter), null, CultureInfo.CurrentCulture));
}
[Test]
public void NullThrowsArgumentNullException()
{
var inverterBoolConverter = CreateConverter();
Assert.Throws<ArgumentNullException>(() => inverterBoolConverter.Convert(null, typeof(IndexToArrayItemConverter), null, CultureInfo.CurrentCulture));
}
static IValueConverter CreateConverter() => new InvertedBoolConverter();
}
}

Просмотреть файл

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using NUnit.Framework;
using Xamarin.CommunityToolkit.Converters;
using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.UnitTests.Converters
{
@ -20,19 +21,15 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
public static IEnumerable<object?[]> GetDataForException() => new List<object?[]>
{
new object?[] { null, 2, 3 },
new object?[] { 1, null, 3 },
new object?[] { 1, 2, null },
new object?[] { null, 2, 3, typeof(ArgumentNullException) },
new object?[] { 1, null, 3, typeof(ArgumentException) },
new object?[] { 1, 2, null, typeof(ArgumentException) },
};
[TestCaseSource(nameof(GetData))]
public void IsInRangeConverter(object value, object minValue, object maxValue, bool expectedResult)
{
var isInRangeConverter = new IsInRangeConverter
{
MinValue = minValue,
MaxValue = maxValue
};
var isInRangeConverter = CreateConverter(maxValue, minValue);
var result = isInRangeConverter.Convert(value, typeof(IsInRangeConverter_Tests), null, CultureInfo.CurrentCulture);
@ -40,14 +37,17 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
}
[TestCaseSource(nameof(GetDataForException))]
public void IsInRangeConverterInvalidValuesThrowArgumenException(object value, object minValue, object maxValue)
public void IsInRangeConverterInvalidValuesThrowArgumentException(object value, object minValue, object maxValue, Type expectedExceptionType)
{
var isInRangeConverter = new IsInRangeConverter
var isInRangeConverter = CreateConverter(maxValue, minValue);
Assert.Throws(expectedExceptionType, () => isInRangeConverter.Convert(value, typeof(IsInRangeConverter_Tests), null, CultureInfo.CurrentCulture));
}
static IValueConverter CreateConverter(object maxValue, object minValue) =>
new IsInRangeConverter
{
MinValue = minValue,
MaxValue = maxValue
};
Assert.Throws<ArgumentException>(() => isInRangeConverter.Convert(value, typeof(IsInRangeConverter_Tests), null, CultureInfo.CurrentCulture));
}
}
}

Просмотреть файл

@ -1,6 +1,7 @@
using System.Globalization;
using NUnit.Framework;
using Xamarin.CommunityToolkit.Converters;
using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.UnitTests.Converters
{
@ -12,7 +13,7 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
[TestCase("", false)]
public void IsNotNullOrEmptyConverter(object value, bool expectedResult)
{
var isNotNullOrEmptyConverter = new IsNotNullOrEmptyConverter();
IValueConverter isNotNullOrEmptyConverter = new IsNotNullOrEmptyConverter();
var result = isNotNullOrEmptyConverter.Convert(value, typeof(IsNotNullOrEmptyConverter_Tests), null, CultureInfo.CurrentCulture);

Просмотреть файл

@ -1,6 +1,7 @@
using System.Globalization;
using NUnit.Framework;
using Xamarin.CommunityToolkit.Converters;
using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.UnitTests.Converters
{
@ -12,7 +13,7 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
[TestCase(typeof(IsNullOrEmptyConverter), false)]
public void IsNullOrEmptyConverter(object value, bool expectedResult)
{
var isNullOrEmptyConverter = new IsNullOrEmptyConverter();
IValueConverter isNullOrEmptyConverter = new IsNullOrEmptyConverter();
var result = isNullOrEmptyConverter.Convert(value, typeof(IsNotNullOrEmptyConverter_Tests), null, CultureInfo.CurrentCulture);

Просмотреть файл

@ -16,24 +16,26 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
// We know it's deprecated, still good to test it
#pragma warning disable CS0618 // Type or member is obsolete
new object[] { new SelectedItemChangedEventArgs(expectedValue), expectedValue },
new object?[] { null, null },
new object?[] { null, null },
#pragma warning restore CS0618 // Type or member is obsolete
};
[TestCaseSource(nameof(GetData))]
public void ItemSelectedEventArgsConverter(SelectedItemChangedEventArgs value, object expectedResult)
{
var itemSelectedEventArgsConverter = new ItemSelectedEventArgsConverter();
var itemSelectedEventArgsConverter = CreateConverter();
var result = itemSelectedEventArgsConverter.Convert(value, typeof(ItemSelectedEventArgsConverter), null, CultureInfo.CurrentCulture);
Assert.AreEqual(result, expectedResult);
}
[TestCase("Random String")]
public void InvalidConverterValuesThrowsArgumenException(object value)
public void InvalidConverterValuesThrowsArgumentException(object value)
{
var itemSelectedEventArgsConverter = new ItemSelectedEventArgsConverter();
var itemSelectedEventArgsConverter = CreateConverter();
Assert.Throws<ArgumentException>(() => itemSelectedEventArgsConverter.Convert(value, typeof(ItemSelectedEventArgsConverter), null, CultureInfo.CurrentCulture));
}
static IValueConverter CreateConverter() => new ItemSelectedEventArgsConverter();
}
}

Просмотреть файл

@ -16,14 +16,14 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
// We know it's deprecated, still good to test it
#pragma warning disable CS0618 // Type or member is obsolete
new object?[] { new ItemTappedEventArgs(null, expectedValue), expectedValue },
new object?[] { new ItemTappedEventArgs(null, null), null },
new object?[] { new ItemTappedEventArgs(null, null), null },
#pragma warning restore CS0618 // Type or member is obsolete
};
[TestCaseSource(nameof(GetData))]
public void ItemTappedEventArgsConverter(ItemTappedEventArgs value, object expectedResult)
{
var itemTappedEventArgsConverter = new ItemTappedEventArgsConverter();
var itemTappedEventArgsConverter = CreateConverter();
var result = itemTappedEventArgsConverter.Convert(value, typeof(ItemTappedEventArgsConverter), null, CultureInfo.CurrentCulture);
@ -31,10 +31,12 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
}
[TestCase("Random String")]
public void InValidConverterValuesThrowArgumenException(object value)
public void InValidConverterValuesThrowArgumentException(object value)
{
var itemTappedEventArgsConverter = new ItemTappedEventArgsConverter();
var itemTappedEventArgsConverter = CreateConverter();
Assert.Throws<ArgumentException>(() => itemTappedEventArgsConverter.Convert(value, typeof(ItemTappedEventArgsConverter), null, CultureInfo.CurrentCulture));
}
static IValueConverter CreateConverter() => new ItemTappedEventArgsConverter();
}
}

Просмотреть файл

@ -4,6 +4,7 @@ using System.Globalization;
using System.Linq;
using NUnit.Framework;
using Xamarin.CommunityToolkit.Converters;
using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.UnitTests.Converters
{
@ -20,7 +21,7 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
[TestCaseSource(nameof(GetData))]
public void ListIsNotNullOrEmptyConverter(object value, bool expectedResult)
{
var listIsNotNullOrEmptyConverter = new ListIsNotNullOrEmptyConverter();
var listIsNotNullOrEmptyConverter = CreateConverter();
var result = listIsNotNullOrEmptyConverter.Convert(value, typeof(ListIsNotNullOrEmptyConverter), null, CultureInfo.CurrentCulture);
@ -28,11 +29,13 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
}
[TestCase(0)]
public void InValidConverterValuesThrowArgumenException(object value)
public void InValidConverterValuesThrowArgumentException(object value)
{
var listIsNotNullOrEmptyConverter = new ListIsNotNullOrEmptyConverter();
var listIsNotNullOrEmptyConverter = CreateConverter();
Assert.Throws<ArgumentException>(() => listIsNotNullOrEmptyConverter.Convert(value, typeof(ListIsNotNullOrEmptyConverter), null, CultureInfo.CurrentCulture));
}
static IValueConverter CreateConverter() => new ListIsNotNullOrEmptyConverter();
}
}

Просмотреть файл

@ -4,6 +4,7 @@ using System.Globalization;
using System.Linq;
using NUnit.Framework;
using Xamarin.CommunityToolkit.Converters;
using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.UnitTests.Converters
{
@ -20,19 +21,21 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
[TestCaseSource(nameof(GetData))]
public void ListIsNullOrEmptyConverter(object value, bool expectedResult)
{
var listIstNullOrEmptyConverter = new ListIsNullOrEmptyConverter();
var listIsNullOrEmptyConverter = CreateConverter();
var result = listIstNullOrEmptyConverter.Convert(value, typeof(ListIsNullOrEmptyConverter), null, CultureInfo.CurrentCulture);
var result = listIsNullOrEmptyConverter.Convert(value, typeof(ListIsNullOrEmptyConverter), null, CultureInfo.CurrentCulture);
Assert.AreEqual(result, expectedResult);
}
[TestCase(0)]
public void InValidConverterValuesThrowArgumenException(object value)
public void InValidConverterValuesThrowArgumentException(object value)
{
var listIstNullOrEmptyConverter = new ListIsNullOrEmptyConverter();
var listIsNullOrEmptyConverter = CreateConverter();
Assert.Throws<ArgumentException>(() => listIstNullOrEmptyConverter.Convert(value, typeof(ListIsNullOrEmptyConverter), null, CultureInfo.CurrentCulture));
Assert.Throws<ArgumentException>(() => listIsNullOrEmptyConverter.Convert(value, typeof(ListIsNullOrEmptyConverter), null, CultureInfo.CurrentCulture));
}
static IValueConverter CreateConverter() => new ListIsNullOrEmptyConverter();
}
}

Просмотреть файл

@ -29,7 +29,7 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
}
[TestCase(0)]
public void InValidConverterValuesThrowArgumenException(object value)
public void InValidConverterValuesThrowArgumentException(object value)
{
var listToStringConverter = new ListToStringConverter();
@ -37,7 +37,7 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
}
[TestCase(0)]
public void InValidConverterParametersThrowArgumenException(object parameter)
public void InValidConverterParametersThrowArgumentException(object parameter)
{
var listToStringConverter = new ListToStringConverter();

Просмотреть файл

@ -30,7 +30,7 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
}
[TestCase(0)]
public void InValidConverterValuesThrowArgumenException(object value)
public void InValidConverterValuesThrowArgumentException(object value)
{
var listToStringConverter = new ListToStringConverter();
@ -38,7 +38,7 @@ namespace Xamarin.CommunityToolkit.UnitTests.Converters
}
[TestCase(0)]
public void InValidConverterParametersThrowArgumenException(object parameter)
public void InValidConverterParametersThrowArgumentException(object parameter)
{
var listToStringConverter = new ListToStringConverter();

Просмотреть файл

@ -0,0 +1,33 @@
using System;
using Xamarin.CommunityToolkit.Converters;
using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.UnitTests.Mocks
{
/// <summary>
/// Mock to test the <see cref="BaseNullableConverterOneWay{TFrom, TTo}"/> internals.
/// </summary>
public class MockNullableConverterOneWay : BaseNullableConverterOneWay<string, Color>
{
public override Color ConvertFrom(string? value) => value switch
{
null => Color.Black,
"Red" => Color.Red,
"Blue" => Color.Blue,
_ => throw new ArgumentException($"{value} unknown.")
};
}
/// <summary>
/// Mock to test the <see cref="BaseConverterOneWay{TFrom, TTo}"/> internals.
/// </summary>
public class MockConverterOneWay : BaseConverterOneWay<string, Color>
{
public override Color ConvertFrom(string value) => value switch
{
"Red" => Color.Red,
"Blue" => Color.Blue,
_ => throw new ArgumentException($"{value} unknown.")
};
}
}

Просмотреть файл

@ -32,6 +32,7 @@ namespace Xamarin.CommunityToolkit.UnitTests.ObjectModel.ICommandTests.AsyncComm
// Assert
Assert.Throws<InvalidCommandParameterException>(() => command.Execute(true));
}
[Test]
public void IAsyncCommand_Execute_InvalidNullableTypeParameter()
{

Просмотреть файл

@ -18,6 +18,7 @@ namespace Xamarin.CommunityToolkit.UnitTests.ObjectModel.ICommandTests
protected Task NoParameterTask() => Task.Delay(Delay);
protected Task IntParameterTask(int delay) => Task.Delay(delay);
protected Task NullableParameterTask(int? delay) => Task.Delay(delay ?? 0);
protected Task StringParameterTask(string? text) => Task.Delay(Delay);

Просмотреть файл

@ -8,7 +8,7 @@ namespace Xamarin.CommunityToolkit.Converters
/// </summary>
/// <typeparam name="TFrom">Type of the input value.</typeparam>
/// <typeparam name="TTo">Type of the output value.</typeparam>
public abstract class BaseConverter<TFrom, TTo> : BaseConverterOneWay<TFrom, TTo>
public abstract class BaseConverter<TFrom, TTo> : BaseConverterOneWay<TFrom, TTo> where TFrom : notnull where TTo : notnull
{
/// <summary>
/// Converts the incoming value from <see cref="TTo"/>[] and returns the object of a type <see cref="TFrom"/>.
@ -18,8 +18,11 @@ namespace Xamarin.CommunityToolkit.Converters
/// <param name="parameter">Additional parameter for the converter to handle. This is not implemented.</param>
/// <param name="culture">The culture to use in the converter. This is not implemented.</param>
/// <returns>An object of the type <see cref="TFrom"/></returns>
public sealed override object? ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
public sealed override object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is null)
throw new ArgumentNullException(nameof(value), $"value needs to be of type {typeof(TFrom)}, but is null. If type {typeof(TFrom)} should be nullable, inherit from {nameof(BaseNullableConverter<TFrom, TTo>)} instead");
if (value is not TTo valueFrom)
throw new ArgumentException($"value needs to be of type {typeof(TTo)}", nameof(value));
@ -36,4 +39,38 @@ namespace Xamarin.CommunityToolkit.Converters
/// <returns>An object of type <see cref="TFrom"/>.</returns>
public abstract TFrom ConvertBackTo(TTo value);
}
/// <summary>
/// Abstract class used to implement converters that supports null and implements the ConvertBack logic.
/// </summary>
/// <typeparam name="TFrom">Type of the input value.</typeparam>
/// <typeparam name="TTo">Type of the output value.</typeparam>
public abstract class BaseNullableConverter<TFrom, TTo> : BaseNullableConverterOneWay<TFrom, TTo>
{
/// <summary>
/// Converts the incoming value from <see cref="TTo"/>[] and returns the object of a type <see cref="TFrom"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <param name="targetType">The type of the binding target property. This is not implemented.</param>
/// <param name="parameter">Additional parameter for the converter to handle. This is not implemented.</param>
/// <param name="culture">The culture to use in the converter. This is not implemented.</param>
/// <returns>An object of the type <see cref="TFrom"/></returns>
public sealed override object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is not TTo valueFrom)
throw new ArgumentException($"value needs to be of type {typeof(TTo)}", nameof(value));
if (targetType != typeof(TFrom) && !(typeof(TFrom) != typeof(string)))
throw new ArgumentException($"targetType needs to be typeof {typeof(TFrom)}", nameof(targetType));
return ConvertBackTo(valueFrom);
}
/// <summary>
/// Method that will be called by <see cref="ConvertBack(object, Type, object, CultureInfo)"/>.
/// </summary>
/// <param name="value">Value to be converted from <see cref="TTo"/> to <see cref="TFrom"/>.</param>
/// <returns>An object of type <see cref="TFrom"/>.</returns>
public abstract TFrom? ConvertBackTo(TTo? value);
}
}

Просмотреть файл

@ -6,31 +6,14 @@ using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.Converters
{
/// <summary>
/// Abstract class used to implement converters that implements the ConvertBack logic.
/// Abstract class used to implement converters that do not implement the ConvertBack logic.
/// </summary>
/// <typeparam name="TFrom">Type of the input value</typeparam>
/// <typeparam name="TTo">Type of the output value</typeparam>
public abstract class BaseConverterOneWay<TFrom, TTo> : ValueConverterExtension, IValueConverter
where TFrom : notnull
where TTo : notnull
{
/// <summary>
/// Converts the incoming value from <see cref="TFrom"/>[] and returns the object of a type <see cref="TTo"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <param name="targetType">The type of the binding target property. This is not implemented.</param>
/// <param name="parameter">Additional parameter for the converter to handle. This is not implemented.</param>
/// <param name="culture">The culture to use in the converter. This is not implemented.</param>
/// <returns>An object of type <see cref="TTo"/>.</returns>
public object? Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is not TFrom valueFrom)
throw new ArgumentException($"value needs to be of type {typeof(TFrom)}");
if (targetType != typeof(TTo) && !(typeof(TFrom) != typeof(string)))
throw new ArgumentException($"targetType needs to be typeof {typeof(TTo)}");
return ConvertFrom(valueFrom);
}
/// <summary>
/// Method that will be called by <see cref="Convert(object, Type, object, CultureInfo)"/>.
/// </summary>
@ -40,7 +23,59 @@ namespace Xamarin.CommunityToolkit.Converters
/// <summary>
/// Not implemented, use <see cref="BaseConverter{TFrom, TTo}"/>
/// </summary>
public virtual object? ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
=> throw new NotImplementedException("Impossible to revert to original value. Consider setting BindingMode to OneWay.");
=> throw new NotSupportedException("Impossible to revert to original value. Consider setting BindingMode to OneWay.");
/// <inheritdoc/>
object? IValueConverter.Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is null)
throw new ArgumentNullException(nameof(value), $"value needs to be of type {typeof(TFrom)}, but is null. If type {typeof(TFrom)} should be nullable, inherit from {nameof(BaseNullableConverterOneWay<TFrom, TTo>)} instead");
if (value is not TFrom valueFrom)
throw new ArgumentException($"value needs to be of type {typeof(TFrom)}");
if (targetType != typeof(TTo) && !(typeof(TFrom) != typeof(string)))
throw new ArgumentException($"targetType needs to be typeof {typeof(TTo)}");
return ConvertFrom(valueFrom);
}
}
/// <summary>
/// Abstract class used to implement converters that support null and do not implement the ConvertBack logic.
/// </summary>
/// <typeparam name="TFrom">Type of the input value</typeparam>
/// <typeparam name="TTo">Type of the output value</typeparam>
public abstract class BaseNullableConverterOneWay<TFrom, TTo> : ValueConverterExtension, IValueConverter
{
/// <summary>
/// Method that will be called by <see cref="Convert(object, Type, object, CultureInfo)"/>.
/// </summary>
/// <param name="value">Value to be converted from <see cref="TFrom"/> to <see cref="TTo"/>.</param>
/// <returns>An object of type <see cref="TTo"/>.</returns>
public abstract TTo? ConvertFrom(TFrom? value);
/// <summary>
/// Not implemented, use <see cref="BaseConverter{TFrom, TTo}"/>
/// </summary>
public virtual object? ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
=> throw new NotSupportedException("Impossible to revert to original value. Consider setting BindingMode to OneWay.");
/// <inheritdoc/>
object? IValueConverter.Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is null)
return ConvertFrom(default);
if (value is not TFrom valueFrom)
throw new ArgumentException($"value needs to be of type {typeof(TFrom)}");
if (targetType != typeof(TTo) && !(typeof(TFrom) != typeof(string)))
throw new ArgumentException($"targetType needs to be typeof {typeof(TTo)}");
return ConvertFrom(valueFrom);
}
}
}

Просмотреть файл

@ -1,8 +1,6 @@
using System;
using System.Globalization;
using System.IO;
using System.Threading;
using Xamarin.CommunityToolkit.Extensions.Internals;
using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.Converters
@ -10,36 +8,14 @@ namespace Xamarin.CommunityToolkit.Converters
/// <summary>
/// Converts the incoming value from <see cref="byte"/>[] and returns the object of a type <see cref="ImageSource"/> or vice versa.
/// </summary>
public class ByteArrayToImageSourceConverter : ValueConverterExtension, IValueConverter
public class ByteArrayToImageSourceConverter : BaseNullableConverter<byte[], ImageSource?>
{
/// <summary>
/// Converts the incoming value from <see cref="byte"/>[] and returns the object of a type <see cref="ImageSource"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <param name="targetType">The type of the binding target property. This is not implemented.</param>
/// <param name="parameter">Additional parameter for the converter to handle. This is not implemented.</param>
/// <param name="culture">The culture to use in the converter. This is not implemented.</param>
/// <returns>An object of type <see cref="ImageSource"/>.</returns>
public object? Convert(object? value, Type? targetType, object? parameter, CultureInfo? culture)
{
if (value == null)
return null;
if (value is byte[] imageBytes)
return ImageSource.FromStream(() => new MemoryStream(imageBytes));
throw new ArgumentException("Expected value to be of type byte[].", nameof(value));
}
/// <summary>
/// Converts the incoming value from <see cref="StreamImageSource"/> and returns a <see cref="byte"/>[].
/// </summary>
/// <param name="value">The value to convert.</param>
/// <param name="targetType">The type of the binding target property. This is not implemented.</param>
/// <param name="parameter">Additional parameter for the converter to handle. This is not implemented.</param>
/// <param name="culture">The culture to use in the converter. This is not implemented.</param>
/// <returns>An object of type <see cref="ImageSource"/>.</returns>
public object? ConvertBack(object? value, Type? targetType, object? parameter, CultureInfo? culture)
public override byte[]? ConvertBackTo(ImageSource? value)
{
if (value == null)
return null;
@ -59,5 +35,18 @@ namespace Xamarin.CommunityToolkit.Converters
throw new ArgumentException("Expected value to be of type StreamImageSource.", nameof(value));
}
/// <summary>
/// Converts the incoming value from <see cref="byte"/>[] and returns the object of a type <see cref="ImageSource"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <returns>An object of type <see cref="ImageSource"/>.</returns>
public override ImageSource? ConvertFrom(byte[]? value)
{
if (value == null)
return null;
return ImageSource.FromStream(() => new MemoryStream(value));
}
}
}

Просмотреть файл

@ -1,6 +1,3 @@
using System;
using System.Globalization;
using Xamarin.CommunityToolkit.Extensions;
using Xamarin.Forms;

Просмотреть файл

@ -1,43 +1,29 @@
using System;
using Xamarin.CommunityToolkit.Extensions.Internals;
using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.Converters
{
/// <summary>
/// Converts <see cref="DateTimeOffset"/> to <see cref="DateTime"/> and back.
/// </summary>
public class DateTimeOffsetConverter : ValueConverterExtension, IValueConverter
public class DateTimeOffsetConverter : BaseConverter<DateTimeOffset, DateTime>
{
/// <summary>
/// Converts <see cref="DateTimeOffset"/> to <see cref="DateTime"/>
/// </summary>
/// <param name="value">The value to convert.</param>
/// <param name="targetType">The type of the binding target property. This is not implemented.</param>
/// <param name="parameter">Additional parameter for the converter to handle. This is not implemented.</param>
/// <param name="culture">The culture to use in the converter. This is not implemented.</param>
/// <returns>The <see cref="DateTime"/> value.</returns>
public object Convert(object? value, Type targetType, object? parameter, System.Globalization.CultureInfo culture)
=> value is DateTimeOffset dateTimeOffset
? dateTimeOffset.DateTime
: throw new ArgumentException("Value is not a valid DateTimeOffset", nameof(value));
/// <summary>
/// Converts <see cref="DateTime"/> back to <see cref="DateTimeOffset"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <param name="targetType">The type of the binding target property. This is not implemented.</param>
/// <param name="parameter">Additional parameter for the converter to handle. This is not implemented.</param>
/// <param name="culture">The culture to use in the converter. This is not implemented..</param>
/// <returns>The <see cref="DateTimeOffset"/> value.</returns>
public object ConvertBack(object? value, Type targetType, object? parameter, System.Globalization.CultureInfo culture)
=> value is DateTime dateTime
? dateTime.Kind switch
{
DateTimeKind.Local => new DateTimeOffset(dateTime, DateTimeOffset.Now.Offset),
DateTimeKind.Utc => new DateTimeOffset(dateTime, DateTimeOffset.UtcNow.Offset),
_ => new DateTimeOffset(dateTime, TimeSpan.Zero),
}
: throw new ArgumentException("Value is not a valid DateTime", nameof(value));
public override DateTimeOffset ConvertBackTo(DateTime value) => value.Kind switch
{
DateTimeKind.Local => new DateTimeOffset(DateTime.SpecifyKind(value, DateTimeKind.Unspecified), DateTimeOffset.Now.Offset),
DateTimeKind.Utc => new DateTimeOffset(value, DateTimeOffset.UtcNow.Offset),
_ => new DateTimeOffset(value, TimeSpan.Zero)
};
/// <summary>
/// Converts <see cref="DateTimeOffset"/> to <see cref="DateTime"/>
/// </summary>
/// <param name="value">The value to convert.</param>
/// <returns>The <see cref="DateTime"/> value.</returns>
public override DateTime ConvertFrom(DateTimeOffset value) => value.DateTime;
}
}

Просмотреть файл

@ -1,6 +1,4 @@
using System;
using System.Globalization;
using Xamarin.Forms;
using Xamarin.Forms;
#if NETSTANDARD1_0 || UAP10_0
using System.Reflection;
#endif
@ -10,31 +8,23 @@ namespace Xamarin.CommunityToolkit.Converters
/// <summary>
/// Converts embedded image resource ID to it ImageSource.
/// </summary>
public class ImageResourceConverter : IValueConverter
public class ImageResourceConverter : BaseNullableConverterOneWay<string, ImageSource>
{
/// <summary>
/// Converts embedded image resource ID to it ImageSource.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <param name="targetType">The type of the binding target property. This is not implemented.</param>
/// <param name="parameter">Additional parameter for the converter to handle. This is not implemented.</param>
/// <param name="culture">The culture to use in the converter. This is not implemented.</param>
/// <returns>The ImageSource related to the provided resource ID of the embedded image. If it's null it will returns null.</returns>
public object? Convert(object value, Type targetType, object parameter, CultureInfo culture)
public override ImageSource? ConvertFrom(string? value)
{
if (value == null)
return null;
if (value is not string imageId)
throw new ArgumentException("Value is not a string", nameof(value));
return ImageSource.FromResource(imageId, Application.Current.GetType()
return ImageSource.FromResource(value, Application.Current.GetType()
#if NETSTANDARD1_0 || UAP10_0
.GetTypeInfo()
#endif
.Assembly);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
}
}

Просмотреть файл

@ -1,42 +1,22 @@
using System;
using System.Globalization;
using Xamarin.CommunityToolkit.Extensions.Internals;
using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.Converters
namespace Xamarin.CommunityToolkit.Converters
{
/// <summary>
/// Converts an <see cref="int"/> to corresponding <see cref="bool"/> and vice versa.
/// </summary>
public class IntToBoolConverter : ValueConverterExtension, IValueConverter
public class IntToBoolConverter : BaseConverter<int, bool>
{
/// <summary>
/// Converts an <see cref="int"/> to corresponding <see cref="bool"/>.
/// </summary>
/// <param name="value"><see cref="int"/> value.</param>
/// <param name="targetType">The type of the binding target property. This is not implemented.</param>
/// <param name="parameter">Additional parameter for the converter to handle. This is not implemented.</param>
/// <param name="culture">The culture to use in the converter. This is not implemented.</param>
/// <returns>False if the value is 0, otherwise if the value is anything but 0 it returns True.</returns>
public object Convert(object? value, Type? targetType, object? parameter, CultureInfo? culture)
=> value is int result
? result != 0
: throw new ArgumentException("Value is not a valid integer", nameof(value));
/// <summary>
/// Converts back <see cref="bool"/> to corresponding <see cref="int"/>.
/// </summary>
/// <param name="value"><see cref="bool"/> value.</param>
/// <param name="targetType">The type of the binding target property. This is not implemented.</param>
/// <param name="parameter">Additional parameter for the converter to handle. This is not implemented.</param>
/// <param name="culture">The culture to use in the converter. This is not implemented.</param>
/// <returns>0 if the value is False, otherwise 1 if the value is True.</returns>
public object ConvertBack(object? value, Type? targetType, object? parameter, CultureInfo? culture)
{
if (value is bool result)
return result ? 1 : 0;
public override int ConvertBackTo(bool value) => value ? 1 : 0;
throw new ArgumentException("Value is not a valid boolean", nameof(value));
}
/// <summary>
/// Converts an <see cref="int"/> to corresponding <see cref="bool"/>.
/// </summary>
/// <param name="value"><see cref="int"/> value.</param>
/// <returns>False if the value is 0, otherwise if the value is anything but 0 it returns True.</returns>
public override bool ConvertFrom(int value) => value != 0;
}
}

Просмотреть файл

@ -1,48 +1,22 @@
using System;
using System.Globalization;
using Xamarin.CommunityToolkit.Extensions.Internals;
using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.Converters
namespace Xamarin.CommunityToolkit.Converters
{
/// <summary>
/// Converts true to false and false to true. Simple as that!
/// </summary>
public class InvertedBoolConverter : ValueConverterExtension, IValueConverter
public class InvertedBoolConverter : BaseConverter<bool, bool>
{
/// <summary>
/// Converts a <see cref="bool"/> to its inverse value.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <param name="targetType">The type of the binding target property. This is not implemented.</param>
/// <param name="parameter">Additional parameter for the converter to handle. This is not implemented.</param>
/// <param name="culture">The culture to use in the converter. This is not implemented.</param>
/// <returns>An inverted <see cref="bool"/> from the one coming in.</returns>
public object Convert(object? value, Type? targetType, object? parameter, CultureInfo? culture)
=> InverseBool(value);
public override bool ConvertBackTo(bool value) => ConvertFrom(value);
/// <summary>
/// Converts a <see cref="bool"/> to its inverse value.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <param name="targetType">The type of the binding target property. This is not implemented.</param>
/// <param name="parameter">Additional parameter for the converter to handle. This is not implemented.</param>
/// <param name="culture">The culture to use in the converter. This is not implemented.</param>
/// <returns>An inverted <see cref="bool"/> from the one coming in.</returns>
public object ConvertBack(object? value, Type? targetType, object? parameter, CultureInfo? culture)
=> InverseBool(value);
/// <summary>
/// Inverses an incoming <see cref="bool"/>.
/// </summary>
/// <param name="value">The value to inverse.</param>
/// <returns>The inverted value of the incoming <see cref="bool"/>.</returns>
bool InverseBool(object? value)
{
if (value is bool result)
return !result;
throw new ArgumentException("Value is not a valid boolean", nameof(value));
}
public override bool ConvertFrom(bool value) => !value;
}
}

Просмотреть файл

@ -1,6 +1,4 @@
using System;
using System.Globalization;
using Xamarin.CommunityToolkit.Extensions.Internals;
using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.Converters
@ -8,13 +6,18 @@ namespace Xamarin.CommunityToolkit.Converters
/// <summary>
/// Checks if the value is between minValue and maxValue, returning true if the value is within the range and false if the value is out of the range.
/// </summary>
public class IsInRangeConverter : ValueConverterExtension, IValueConverter
public class IsInRangeConverter : BaseConverterOneWay<IComparable, bool>
{
/// <summary>
/// Backing BindableProperty for the <see cref="MinValue"/> property.
/// </summary>
public static readonly BindableProperty MinValueProperty = BindableProperty.Create(nameof(MinValue), typeof(object), typeof(IsInRangeConverter));
/// <summary>
/// Backing BindableProperty for the <see cref="MaxValue"/> property.
/// </summary>
public static readonly BindableProperty MaxValueProperty = BindableProperty.Create(nameof(MaxValue), typeof(object), typeof(IsInRangeConverter));
/// <summary>
/// Gets or sets the minimum value of the range for the <see cref="IsInRangeConverter"/>. This is a bindable property.
/// </summary>
@ -24,11 +27,6 @@ namespace Xamarin.CommunityToolkit.Converters
set => SetValue(MinValueProperty, value);
}
/// <summary>
/// Backing BindableProperty for the <see cref="MaxValue"/> property.
/// </summary>
public static readonly BindableProperty MaxValueProperty = BindableProperty.Create(nameof(MaxValue), typeof(object), typeof(IsInRangeConverter));
/// <summary>
/// Gets or sets the maximum value of the range for the <see cref="IsInRangeConverter"/>. This is a bindable property.
/// </summary>
@ -42,33 +40,16 @@ namespace Xamarin.CommunityToolkit.Converters
/// Checks if the value is between minValue and maxValue, returning true if the value is within the range and false if the value is out of the range.
/// </summary>
/// <param name="value">The object to compare.</param>
/// <param name="targetType">The type of the binding target property. This is not implemented.</param>
/// <param name="parameter">Additional parameter for the converter to handle. This is not implemented.</param>
/// <param name="culture">The culture to use in the converter. This is not implemented.</param>
/// <returns>True if <paramref name="value"/> and <paramref name="parameter"/> are equal, False if they are not equal.</returns>
public object Convert(object value, Type targetType, object? parameter, CultureInfo culture)
public override bool ConvertFrom(IComparable value)
{
if (value is not IComparable comparable)
throw new ArgumentException("is expected to implement IComparable interface.", nameof(value));
if (MinValue is not IComparable)
throw new ArgumentException("is expected to implement IComparable interface.", nameof(MinValue));
if (MaxValue is not IComparable)
throw new ArgumentException("is expected to implement IComparable interface.", nameof(MaxValue));
return comparable.CompareTo(MinValue) >= 0 && comparable.CompareTo(MaxValue) <= 0;
return value.CompareTo(MinValue) >= 0 && value.CompareTo(MaxValue) <= 0;
}
/// <summary>
/// This method is not implemented and will throw a <see cref="NotImplementedException"/>.
/// </summary>
/// <param name="value">N/A</param>
/// <param name="targetType">N/A</param>
/// <param name="parameter">N/A</param>
/// <param name="culture">N/A</param>
/// <returns>N/A</returns>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) =>
throw new NotImplementedException();
}
}

Просмотреть файл

@ -1,35 +1,15 @@
using System;
using System.Globalization;
using Xamarin.CommunityToolkit.Extensions.Internals;
using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.Converters
namespace Xamarin.CommunityToolkit.Converters
{
/// <summary>
/// Converts the incoming value to a <see cref="bool"/> indicating whether or not the value is not null and not empty.
/// </summary>
public class IsNotNullOrEmptyConverter : ValueConverterExtension, IValueConverter
public class IsNotNullOrEmptyConverter : BaseNullableConverterOneWay<object, bool>
{
/// <summary>
/// Converts the incoming value to a <see cref="bool"/> indicating whether or not the value is not null and not empty.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <param name="targetType">The type of the binding target property. This is not implemented.</param>
/// <param name="parameter">Additional parameter for the converter to handle. This is not implemented.</param>
/// <param name="culture">The culture to use in the converter. This is not implemented.</param>
/// <returns>A <see cref="bool"/> indicating if the incoming value is not null and not empty.</returns>
public object Convert(object? value, Type? targetType, object? parameter, CultureInfo? culture) =>
!IsNullOrEmptyConverter.ConvertInternal(value);
/// <summary>
/// This method is not implemented and will throw a <see cref="NotImplementedException"/>.
/// </summary>
/// <param name="value">N/A</param>
/// <param name="targetType">N/A</param>
/// <param name="parameter">N/A</param>
/// <param name="culture">N/A</param>
/// <returns>N/A</returns>
public object? ConvertBack(object? value, Type? targetType, object? parameter, CultureInfo? culture)
=> throw new NotImplementedException();
public override bool ConvertFrom(object? value) => !IsNullOrEmptyConverter.ConvertInternal(value);
}
}

Просмотреть файл

@ -1,37 +1,18 @@
using System;
using System.Globalization;
using Xamarin.CommunityToolkit.Extensions.Internals;
using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.Converters
namespace Xamarin.CommunityToolkit.Converters
{
/// <summary>
/// Converts the incoming value to a <see cref="bool"/> indicating whether or not the value is null or empty.
/// </summary>
public class IsNullOrEmptyConverter : ValueConverterExtension, IValueConverter
public class IsNullOrEmptyConverter : BaseNullableConverterOneWay<object, bool>
{
/// <summary>
/// Converts the incoming value to a <see cref="bool"/> indicating whether or not the value is null or empty.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <param name="targetType">The type of the binding target property. This is not implemented.</param>
/// <param name="parameter">Additional parameter for the converter to handle. This is not implemented.</param>
/// <param name="culture">The culture to use in the converter. This is not implemented.</param>
/// <returns>A <see cref="bool"/> indicating if the incoming value is null or empty.</returns>
public object Convert(object? value, Type? targetType, object? parameter, CultureInfo? culture) => ConvertInternal(value);
public override bool ConvertFrom(object? value) => ConvertInternal(value);
internal static bool ConvertInternal(object? value) =>
value == null || (value is string str && string.IsNullOrWhiteSpace(str));
/// <summary>
/// This method is not implemented and will throw a <see cref="NotImplementedException"/>.
/// </summary>
/// <param name="value">N/A</param>
/// <param name="targetType">N/A</param>
/// <param name="parameter">N/A</param>
/// <param name="culture">N/A</param>
/// <returns>N/A</returns>
public object ConvertBack(object? value, Type? targetType, object? parameter, CultureInfo? culture)
=> throw new NotImplementedException();
}
}

Просмотреть файл

@ -1,42 +1,17 @@
using System;
using System.Globalization;
using Xamarin.CommunityToolkit.Extensions.Internals;
using Xamarin.Forms;
using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.Converters
{
/// <summary>
/// Converts/Extracts the incoming value from <see cref="SelectedItemChangedEventArgs"/> object and returns the value of <see cref="SelectedItemChangedEventArgs.SelectedItem"/> property from it.
/// </summary>
public class ItemSelectedEventArgsConverter : ValueConverterExtension, IValueConverter
public class ItemSelectedEventArgsConverter : BaseNullableConverterOneWay<SelectedItemChangedEventArgs, object>
{
/// <summary>
/// Converts/Extracts the incoming value from <see cref="SelectedItemChangedEventArgs"/> object and returns the value of <see cref="SelectedItemChangedEventArgs.SelectedItem"/> property from it.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <param name="targetType">The type of the binding target property. This is not implemented.</param>
/// <param name="parameter">Additional parameter for the converter to handle. This is not implemented.</param>
/// <param name="culture">The culture to use in the converter. This is not implemented.</param>
/// <returns>A <see cref="SelectedItemChangedEventArgs.SelectedItem"/> object from object of type <see cref="SelectedItemChangedEventArgs"/>.</returns>
public object? Convert(object? value, Type? targetType, object? parameter, CultureInfo? culture)
{
if (value == null)
return null;
return value is SelectedItemChangedEventArgs selectedItemChangedEventArgs
? selectedItemChangedEventArgs.SelectedItem
: throw new ArgumentException("Expected value to be of type SelectedItemChangedEventArgs", nameof(value));
}
/// <summary>
/// This method is not implemented and will throw a <see cref="NotImplementedException"/>.
/// </summary>
/// <param name="value">N/A</param>
/// <param name="targetType">N/A</param>
/// <param name="parameter">N/A</param>
/// <param name="culture">N/A</param>
/// <returns>N/A</returns>
public object? ConvertBack(object? value, Type? targetType, object? parameter, CultureInfo? culture)
=> throw new NotImplementedException();
public override object? ConvertFrom(SelectedItemChangedEventArgs? value) => value?.SelectedItem;
}
}

Просмотреть файл

@ -1,42 +1,17 @@
using System;
using System.Globalization;
using Xamarin.CommunityToolkit.Extensions.Internals;
using Xamarin.Forms;
using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.Converters
{
/// <summary>
/// Converts/Extracts the incoming value from <see cref="ItemTappedEventArgs"/> object and returns the value of <see cref="ItemTappedEventArgs.Item"/> property from it.
/// </summary>
public class ItemTappedEventArgsConverter : ValueConverterExtension, IValueConverter
public class ItemTappedEventArgsConverter : BaseNullableConverterOneWay<ItemTappedEventArgs, object>
{
/// <summary>
/// Converts/Extracts the incoming value from <see cref="ItemTappedEventArgs"/> object and returns the value of <see cref="ItemTappedEventArgs.Item"/> property from it.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <param name="targetType">The type of the binding target property. This is not implemented.</param>
/// <param name="parameter">Additional parameter for the converter to handle. This is not implemented.</param>
/// <param name="culture">The culture to use in the converter. This is not implemented.</param>
/// <returns>A <see cref="ItemTappedEventArgs.Item"/> object from object of type <see cref="ItemTappedEventArgs"/>.</returns>
public object? Convert(object? value, Type? targetType, object? parameter, CultureInfo? culture)
{
if (value == null)
return null;
return value is ItemTappedEventArgs itemTappedEventArgs
? itemTappedEventArgs.Item
: throw new ArgumentException("Expected value to be of type ItemTappedEventArgs", nameof(value));
}
/// <summary>
/// This method is not implemented and will throw a <see cref="NotImplementedException"/>.
/// </summary>
/// <param name="value">N/A</param>
/// <param name="targetType">N/A</param>
/// <param name="parameter">N/A</param>
/// <param name="culture">N/A</param>
/// <returns>N/A</returns>
public object? ConvertBack(object? value, Type? targetType, object? parameter, CultureInfo? culture)
=> throw new NotImplementedException();
public override object? ConvertFrom(ItemTappedEventArgs? value) => value?.Item;
}
}

Просмотреть файл

@ -1,35 +1,17 @@
using System;
using System.Globalization;
using Xamarin.CommunityToolkit.Extensions.Internals;
using Xamarin.Forms;
using System.Collections;
namespace Xamarin.CommunityToolkit.Converters
{
/// <summary>
/// Converts the incoming value to a <see cref="bool"/> indicating whether or not the value is not null and not empty.
/// </summary>
public class ListIsNotNullOrEmptyConverter : ValueConverterExtension, IValueConverter
public class ListIsNotNullOrEmptyConverter : BaseNullableConverterOneWay<IEnumerable, bool>
{
/// <summary>
/// Converts the incoming value to a <see cref="bool"/> indicating whether or not the value is not null and not empty.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <param name="targetType">The type of the binding target property. This is not implemented.</param>
/// <param name="parameter">Additional parameter for the converter to handle. This is not implemented.</param>
/// <param name="culture">The culture to use in the converter. This is not implemented.</param>
/// <returns>A <see cref="bool"/> indicating if the incoming value is not null and not empty.</returns>
public object Convert(object? value, Type? targetType, object? parameter, CultureInfo? culture) =>
!ListIsNullOrEmptyConverter.ConvertInternal(value);
/// <summary>
/// This method is not implemented and will throw a <see cref="NotImplementedException"/>.
/// </summary>
/// <param name="value">N/A</param>
/// <param name="targetType">N/A</param>
/// <param name="parameter">N/A</param>
/// <param name="culture">N/A</param>
/// <returns>N/A</returns>
public object ConvertBack(object? value, Type? targetType, object? parameter, CultureInfo? culture)
=> throw new NotImplementedException();
public override bool ConvertFrom(IEnumerable? value) => !ListIsNullOrEmptyConverter.ConvertInternal(value);
}
}

Просмотреть файл

@ -1,46 +1,25 @@
using System;
using System.Collections;
using System.Globalization;
using Xamarin.CommunityToolkit.Extensions.Internals;
using Xamarin.Forms;
using System.Collections;
namespace Xamarin.CommunityToolkit.Converters
{
/// <summary>
/// Converts the incoming value to a <see cref="bool"/> indicating whether or not the value is null or empty.
/// </summary>
public class ListIsNullOrEmptyConverter : ValueConverterExtension, IValueConverter
public class ListIsNullOrEmptyConverter : BaseNullableConverterOneWay<IEnumerable, bool>
{
/// <summary>
/// Converts the incoming value to a <see cref="bool"/> indicating whether or not the value is null or empty.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <param name="targetType">The type of the binding target property. This is not implemented.</param>
/// <param name="parameter">Additional parameter for the converter to handle. This is not implemented.</param>
/// <param name="culture">The culture to use in the converter. This is not implemented.</param>
/// <returns>A <see cref="bool"/> indicating if the incoming value is null or empty.</returns>
public object Convert(object? value, Type? targetType, object? parameter, CultureInfo? culture) => ConvertInternal(value);
public override bool ConvertFrom(IEnumerable? value) => ConvertInternal(value);
internal static bool ConvertInternal(object? value)
internal static bool ConvertInternal(IEnumerable? value)
{
if (value == null)
return true;
if (value is IEnumerable list)
return !list.GetEnumerator().MoveNext();
throw new ArgumentException("Value is not a valid IEnumerable or null", nameof(value));
return !value.GetEnumerator().MoveNext();
}
/// <summary>
/// This method is not implemented and will throw a <see cref="NotImplementedException"/>.
/// </summary>
/// <param name="value">N/A</param>
/// <param name="targetType">N/A</param>
/// <param name="parameter">N/A</param>
/// <param name="culture">N/A</param>
/// <returns>N/A</returns>
public object? ConvertBack(object? value, Type? targetType, object? parameter, CultureInfo? culture)
=> throw new NotImplementedException();
}
}

Просмотреть файл

@ -120,6 +120,7 @@ namespace Xamarin.CommunityToolkit.UI.Views
get => (double)GetValue(VolumeProperty);
set => SetValue(VolumeProperty, value);
}
public double Speed
{
get => (double)GetValue(SpeedProperty);

Просмотреть файл

@ -5,7 +5,7 @@ using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.UI.Views
{
partial class SnackBar
internal partial class SnackBar
{
internal partial ValueTask Show(VisualElement sender, SnackBarOptions arguments) => throw new PlatformNotSupportedException();
}

Просмотреть файл

@ -5,7 +5,7 @@ using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.UI.Views
{
partial class SnackBar
internal partial class SnackBar
{
internal partial ValueTask Show(VisualElement sender, SnackBarOptions arguments);

Просмотреть файл

@ -6,7 +6,7 @@ using EButton = ElmSharp.Button;
namespace Xamarin.CommunityToolkit.UI.Views
{
partial class SnackBar
internal partial class SnackBar
{
internal partial ValueTask Show(Forms.VisualElement sender, SnackBarOptions arguments)
{

Просмотреть файл

@ -1,9 +1,9 @@
using System;
using NUnit.Framework;
using Xamarin.Forms;
using System.Linq;
using System.Windows.Input;
using NUnit.Framework;
using Xamarin.CommunityToolkit.Markup.UnitTests.BindableObjectViews;
using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.Markup.UnitTests
{
@ -88,7 +88,7 @@ namespace Xamarin.CommunityToolkit.Markup.UnitTests
Label.TextColorProperty,
nameof(viewModel.IsRed),
assertConverterInstanceIsAnyNotNull: true,
assertConvert: c => c.AssertConvert<bool?, Color>(true, Color.Red).AssertConvert<bool?,Color>(false, Color.Transparent)
assertConvert: c => c.AssertConvert<bool?, Color>(true, Color.Red).AssertConvert<bool?, Color>(false, Color.Transparent)
);
}

Просмотреть файл

@ -173,4 +173,4 @@ namespace Xamarin.CommunityToolkit.Markup.UnitTests
internal static IMultiValueConverter AssertConvert<TConvertedValue>(this IMultiValueConverter converter, object[] values, TConvertedValue expectedConvertedValue, bool twoWay = false, bool backOnly = false, CultureInfo? culture = null)
=> AssertConvert<TConvertedValue>(converter, values, null, expectedConvertedValue, twoWay, backOnly, culture);
}
}
}

Просмотреть файл

@ -9,9 +9,10 @@ using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.Markup.UnitTests
{
#pragma warning disable SA1200 // Using directives should be placed correctly
using Xamarin.CommunityToolkit.Markup.UnitTests.DefaultBindablePropertiesViews;
// These usings are placed here to avoid ambiguities
using Xamarin.Forms.Shapes;
using Xamarin.CommunityToolkit.Markup.UnitTests.DefaultBindablePropertiesViews;
#pragma warning restore SA1200 // Using directives should be placed correctly
[TestFixture]
@ -220,11 +221,11 @@ namespace Xamarin.CommunityToolkit.Markup.UnitTests
namespace Xamarin.CommunityToolkit.Markup.UnitTests.DefaultBindablePropertiesViews // This namespace simulates derived controls defined in a separate app, for use in the tests in this file only
#pragma warning restore SA1403 // File may only contain a single namespace
{
#pragma warning disable SA1200 // Using directives should be placed correctly
#pragma warning disable SA1200 // Using directives should be placed correctly
// These usings are placed here to avoid ambiguities
using System.Windows.Input;
using Xamarin.Forms;
#pragma warning restore SA1200 // Using directives should be placed correctly
#pragma warning restore SA1200 // Using directives should be placed correctly
class DerivedFromBoxView : BoxView { }

Просмотреть файл

@ -19,7 +19,7 @@ namespace Xamarin.CommunityToolkit.Markup.UnitTests
{
var grid = new Forms.Grid
{
RowDefinitions = Rows.Define(Auto, Star, Stars (starsValue), 20)
RowDefinitions = Rows.Define(Auto, Star, Stars(starsValue), 20)
};
Assert.That(grid.RowDefinitions.Count, Is.EqualTo(4));
@ -35,9 +35,9 @@ namespace Xamarin.CommunityToolkit.Markup.UnitTests
var grid = new Forms.Grid
{
RowDefinitions = Rows.Define(
(Row.First , Auto),
(Row.First, Auto),
(Row.Second, Star),
(Row.Third , Stars (starsValue)),
(Row.Third, Stars(starsValue)),
(Row.Fourth, 20)
)
};
@ -63,7 +63,7 @@ namespace Xamarin.CommunityToolkit.Markup.UnitTests
{
var grid = new Forms.Grid
{
ColumnDefinitions = Columns.Define(Auto, Star, Stars (starsValue), 20, 40)
ColumnDefinitions = Columns.Define(Auto, Star, Stars(starsValue), 20, 40)
};
Assert.That(grid.ColumnDefinitions.Count, Is.EqualTo(5));
@ -80,11 +80,11 @@ namespace Xamarin.CommunityToolkit.Markup.UnitTests
var grid = new Forms.Grid
{
ColumnDefinitions = Columns.Define(
(Col.First , Auto),
(Col.First, Auto),
(Col.Second, Star),
(Col.Third , Stars(starsValue)),
(Col.Third, Stars(starsValue)),
(Col.Fourth, 20),
(Col.Fifth , 40)
(Col.Fifth, 40)
)
};

Просмотреть файл

@ -1,6 +1,6 @@
using NUnit.Framework;
using Xamarin.Forms;
using Xamarin.CommunityToolkit.Markup.LeftToRight;
using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.Markup.UnitTests
{

Просмотреть файл

@ -1,6 +1,6 @@
using NUnit.Framework;
using Xamarin.Forms;
using Xamarin.CommunityToolkit.Markup.RightToLeft;
using Xamarin.Forms;
namespace Xamarin.CommunityToolkit.Markup.UnitTests
{

Просмотреть файл

@ -74,4 +74,4 @@ namespace Xamarin.CommunityToolkit.Markup.UnitTests
Assert.That(bindable.GetPropertyIfSet(property, property.DefaultValue), Is.EqualTo(expectedValue));
}
}
}
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше