Skip to content
This repository was archived by the owner on May 1, 2024. It is now read-only.

Make parameters in CommandFactory class consistent #811

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,19 @@ public void Action_ValidExecuteParameter()
public void Action_NullCanExecuteParameter()
{
// Arrange
Func<bool> canExecute = null;

// Act

// Assert
Assert.Throws<ArgumentNullException>(() => CommandFactory.Create(NoParameterAction, null));
Assert.Throws<ArgumentNullException>(() => CommandFactory.Create(NoParameterAction, canExecute));
}

[Fact]
public void Action_ValidCanExecuteParameter()
{
// Arrange
var command = CommandFactory.Create(NoParameterAction, CanExecuteTrue);
var command = CommandFactory.Create(NoParameterAction, () => true);

// Act
command.Execute(null);
Expand Down Expand Up @@ -83,7 +84,7 @@ public void ActionObject_NullExecuteParameter()
public void ActionObject_ValidExecuteParameter()
{
// Arrange
var command = CommandFactory.Create(ObjectParameterAction);
var command = CommandFactory.Create<object>(ObjectParameterAction);

// Act
command.Execute(null);
Expand All @@ -93,7 +94,7 @@ public void ActionObject_ValidExecuteParameter()
Assert.True(command.CanExecute(string.Empty));
Assert.True(command.CanExecute(0));

Assert.IsType<Forms.Command>(command);
Assert.IsType<Forms.Command<object>>(command);
Assert.IsAssignableFrom<ICommand>(command);
}

Expand All @@ -105,14 +106,14 @@ public void ActionObject_NullCanExecuteParameter()
// Act

// Assert
Assert.Throws<ArgumentNullException>(() => CommandFactory.Create(ObjectParameterAction, null));
Assert.Throws<ArgumentNullException>(() => CommandFactory.Create<object, object>(ObjectParameterAction, null));
}

[Fact]
public void ActionObject_ValidCanExecuteParameter()
{
// Arrange
var command = CommandFactory.Create(ObjectParameterAction, _ => true);
var command = CommandFactory.Create<object>(ObjectParameterAction, _ => true);

// Act
command.Execute(1);
Expand All @@ -137,25 +138,26 @@ public void ActionInt_NullExecuteParameter()
// Act

// Assert
Assert.Throws<ArgumentNullException>(() => CommandFactory.Create<int>(execute, CanExecuteTrue));
Assert.Throws<ArgumentNullException>(() => CommandFactory.Create<int>(execute, () => true));
}

[Fact]
public void ActionInt_NullCanExecuteParameter()
{
// Arrange
Func<bool> canExecute = null;

// Act

// Assert
Assert.Throws<ArgumentNullException>(() => CommandFactory.Create<int>(IntParameterAction, null));
Assert.Throws<ArgumentNullException>(() => CommandFactory.Create<int>(IntParameterAction, canExecute));
}

[Fact]
public void ActionInt_ValidCanExecuteParameter()
{
// Arrange
var command = CommandFactory.Create<int>(IntParameterAction, CanExecuteTrue);
var command = CommandFactory.Create<int, int>(IntParameterAction, CanExecuteTrue);

// Act

Expand All @@ -164,8 +166,25 @@ public void ActionInt_ValidCanExecuteParameter()
Assert.False(command.CanExecute(null));
Assert.False(command.CanExecute(string.Empty));

Assert.IsType<Forms.Command<int>>(command);
Assert.IsType<Forms.Command>(command);
Assert.IsAssignableFrom<ICommand>(command);
}

[Fact]
public void ActionInt_ValidExecuteParameter()
{
// Arrange
var executeResult = -1;
var executeParameter = 0;
var command = CommandFactory.Create<int>(parameter => executeResult = parameter);

// Act
command.Execute(executeParameter);
command.Execute(null);
command.Execute(string.Empty);

// Assert
Assert.Equal(executeParameter, executeResult);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Reflection;
using Xamarin.Forms;

namespace Xamarin.CommunityToolkit.ObjectModel
Expand All @@ -20,40 +21,114 @@ public static Command Create(Action execute) =>
/// Initializes Xamarin.Forms.Command
/// </summary>
/// <param name="execute">The Function executed when Execute is called. This does not check canExecute before executing and will execute even if canExecute is false</param>
/// <param name="canExecute">The Function that verifies whether or not Command should execute.</param>
/// <returns>Xamarin.Forms.Command</returns>
public static Command Create(Action execute, Func<bool> canExecute) =>
new Command(execute, canExecute);
public static Command Create(Action execute, Func<object, bool> canExecute) =>
new Command(ConvertExecute(execute), canExecute);

/// <summary>
/// Initializes Xamarin.Forms.Command
/// </summary>
/// <param name="execute">The Function executed when Execute is called. This does not check canExecute before executing and will execute even if canExecute is false</param>
/// <param name="canExecute">The Function that verifies whether or not Command should execute.</param>
/// <returns>Xamarin.Forms.Command</returns>
public static Command Create(Action<object> execute) =>
new Command(execute);
public static Command Create(Action execute, Func<bool> canExecute) =>
new Command(execute, canExecute);

/// <summary>
/// Initializes Xamarin.Forms.Command<typeparamref name="TExecute"/>
/// </summary>
/// <param name="execute">The Function executed when Execute is called. This does not check canExecute before executing and will execute even if canExecute is false</param>
/// <returns>Xamarin.Forms.Command<typeparamref name="TExecute"/></returns>
public static Command<TExecute> Create<TExecute>(Action<TExecute> execute) =>
new Command<TExecute>(execute);

/// <summary>
/// Initializes Xamarin.Forms.Command
/// </summary>
/// <param name="execute">The Function executed when Execute is called. This does not check canExecute before executing and will execute even if canExecute is false</param>
/// <param name="canExecute">The Function that verifies whether or not Command should execute.</param>
/// <returns>Xamarin.Forms.Command</returns>
public static Command Create(Action<object> execute, Func<object, bool> canExecute) =>
new Command(execute, canExecute);
public static Command Create<TExecute>(Action<TExecute> execute, Func<object, bool> canExecute) =>
new Command(ConvertExecute(execute), canExecute);

/// <summary>
/// Initializes Xamarin.Forms.Command<typeparamref name="T"/>
/// Initializes Xamarin.Forms.Command
/// </summary>
/// <param name="execute">The Function executed when Execute is called. This does not check canExecute before executing and will execute even if canExecute is false</param>
/// <returns>Xamarin.Forms.Command<typeparamref name="T"/></returns>
public static Command<T> Create<T>(Action<T> execute) =>
new Command<T>(execute);
/// <param name="canExecute">The Function that verifies whether or not Command should execute.</param>
/// <returns>Xamarin.Forms.Command</returns>
public static Command Create<TExecute>(Action<TExecute> execute, Func<bool> canExecute) =>
new Command(ConvertExecute(execute), ConvertCanExecute(canExecute));

/// <summary>
/// Initializes Xamarin.Forms.Command<typeparamref name="T"/>
/// Initializes Xamarin.Forms.Command
/// </summary>
/// <param name="execute">The Function executed when Execute is called. This does not check canExecute before executing and will execute even if canExecute is false</param>
/// <returns>Xamarin.Forms.Command<typeparamref name="T"/></returns>
public static Command<T> Create<T>(Action<T> execute, Func<T, bool> canExecute) =>
new Command<T>(execute, canExecute);
/// <param name="canExecute">The Function that verifies whether or not Command should execute.</param>
/// <returns>Xamarin.Forms.Command</returns>
public static Command Create<TExecute, TCanExecute>(Action<TExecute> execute, Func<TCanExecute, bool> canExecute) =>
new Command(ConvertExecute(execute), ConvertCanExecute(canExecute));

#region Helper methods to ensure Command behaviour is consistent with other commands

static Action<object> ConvertExecute(Action execute)
{
if (execute == null)
return null;

return p => execute();
}

static Action<object> ConvertExecute<T>(Action<T> execute)
{
if (execute == null)
return null;

return p => Execute(execute, p);
}

static void Execute<T>(Action<T> execute, object parameter)
{
switch (parameter)
{
case T validParameter:
execute(validParameter);
break;

case null when !typeof(T).GetTypeInfo().IsValueType:
execute((T)parameter);
break;

case null:
default:
return;
}
}

static Func<object, bool> ConvertCanExecute(Func<bool> canExecute)
{
if (canExecute == null)
return null;

return _ => canExecute();
}

static Func<object, bool> ConvertCanExecute<T>(Func<T, bool> canExecute)
{
if (canExecute == null)
return null;

return p => CanExecute(canExecute, p);
}

static bool CanExecute<T>(Func<T, bool> canExecute, object parameter) => parameter switch
{
T validParameter => canExecute(validParameter),
null when !typeof(T).GetTypeInfo().IsValueType => canExecute((T)parameter),
_ => false,
};

#endregion
}
}
Loading