1
0
mirror of https://github.com/chylex/.NET-Community-Toolkit.git synced 2025-04-10 11:15:45 +02:00

Add unit tests for cancel commands

This commit is contained in:
Sergio Pedri 2022-03-02 11:53:41 +01:00
parent 5afbbdf6f8
commit 1371da130a
4 changed files with 282 additions and 0 deletions
tests
CommunityToolkit.Mvvm.SourceGenerators.UnitTests
CommunityToolkit.Mvvm.UnitTests

View File

@ -554,6 +554,68 @@ private void GreetUser(User user)
VerifyGeneratedDiagnostics<ICommandGenerator>(source, "MVVMTK0012");
}
[TestMethod]
public void InvalidICommandIncludeCancelCommandSettings_SynchronousMethod()
{
string source = @"
using CommunityToolkit.Mvvm.Input;
namespace MyApp
{
public partial class SampleViewModel
{
[ICommand(IncludeCancelCommand = true)]
private void GreetUser(User user)
{
}
}
}";
VerifyGeneratedDiagnostics<ICommandGenerator>(source, "MVVMTK0013");
}
[TestMethod]
public void InvalidICommandIncludeCancelCommandSettings_AsynchronousMethodWithNoCancellationToken()
{
string source = @"
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.Input;
namespace MyApp
{
public partial class SampleViewModel
{
[ICommand(IncludeCancelCommand = true)]
private async Task DoWorkAsync()
{
}
}
}";
VerifyGeneratedDiagnostics<ICommandGenerator>(source, "MVVMTK0013");
}
[TestMethod]
public void InvalidICommandIncludeCancelCommandSettings_AsynchronousMethodWithParameterAndNoCancellationToken()
{
string source = @"
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.Input;
namespace MyApp
{
public partial class SampleViewModel
{
[ICommand(IncludeCancelCommand = true)]
private async Task GreetUserAsync(User user)
{
}
}
}";
VerifyGeneratedDiagnostics<ICommandGenerator>(source, "MVVMTK0013");
}
/// <summary>
/// Verifies the output of a source generator.
/// </summary>

View File

@ -6,6 +6,7 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows.Input;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.UnitTests.Helpers;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@ -418,4 +419,68 @@ public void Test_AsyncRelayCommand_ExecuteWithoutConcurrencyRaisesCanExecuteChan
tcs.SetResult(null);
}
[TestMethod]
public void Test_AsyncRelayCommand_GetCancelCommand_DisabledCommand()
{
TaskCompletionSource<object?> tcs = new();
AsyncRelayCommand command = new(() => tcs.Task);
ICommand cancelCommand = command.CreateCancelCommand();
Assert.IsNotNull(cancelCommand);
Assert.IsFalse(cancelCommand.CanExecute(null));
// No-op
cancelCommand.Execute(null);
Assert.AreEqual("CommunityToolkit.Mvvm.Input.Internals.DisabledCommand", cancelCommand.GetType().ToString());
ICommand cancelCommand2 = command.CreateCancelCommand();
Assert.IsNotNull(cancelCommand2);
Assert.IsFalse(cancelCommand2.CanExecute(null));
Assert.AreSame(cancelCommand, cancelCommand2);
}
[TestMethod]
public void Test_AsyncRelayCommand_GetCancelCommand_WithToken()
{
TaskCompletionSource<object?> tcs = new();
AsyncRelayCommand command = new(token => tcs.Task);
ICommand cancelCommand = command.CreateCancelCommand();
Assert.IsNotNull(cancelCommand);
Assert.IsFalse(cancelCommand.CanExecute(null));
// No-op
cancelCommand.Execute(null);
Assert.AreEqual("CommunityToolkit.Mvvm.Input.Internals.CancelCommand", cancelCommand.GetType().ToString());
List<(object? Sender, EventArgs Args)> cancelCommandCanExecuteChangedArgs = new();
cancelCommand.CanExecuteChanged += (s, e) => cancelCommandCanExecuteChangedArgs.Add((s, e));
command.Execute(null);
Assert.AreEqual(1, cancelCommandCanExecuteChangedArgs.Count);
Assert.AreSame(cancelCommand, cancelCommandCanExecuteChangedArgs[0].Sender);
Assert.AreSame(EventArgs.Empty, cancelCommandCanExecuteChangedArgs[0].Args);
Assert.IsTrue(cancelCommand.CanExecute(null));
cancelCommand.Execute(null);
Assert.IsFalse(cancelCommand.CanExecute(null));
Assert.AreEqual(2, cancelCommandCanExecuteChangedArgs.Count);
Assert.AreSame(cancelCommand, cancelCommandCanExecuteChangedArgs[1].Sender);
Assert.AreSame(EventArgs.Empty, cancelCommandCanExecuteChangedArgs[1].Args);
Assert.IsFalse(command.CanBeCanceled);
Assert.IsTrue(command.IsCancellationRequested);
}
}

View File

@ -6,6 +6,7 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows.Input;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.UnitTests.Helpers;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@ -360,4 +361,68 @@ public void Test_AsyncRelayCommand_ExecuteWithoutConcurrencyRaisesCanExecuteChan
tcs.SetResult(null);
}
[TestMethod]
public void Test_AsyncRelayCommandOfT_GetCancelCommand_DisabledCommand()
{
TaskCompletionSource<object?> tcs = new();
AsyncRelayCommand<string> command = new(s => tcs.Task);
ICommand cancelCommand = command.CreateCancelCommand();
Assert.IsNotNull(cancelCommand);
Assert.IsFalse(cancelCommand.CanExecute(null));
// No-op
cancelCommand.Execute(null);
Assert.AreEqual("CommunityToolkit.Mvvm.Input.Internals.DisabledCommand", cancelCommand.GetType().ToString());
ICommand cancelCommand2 = command.CreateCancelCommand();
Assert.IsNotNull(cancelCommand2);
Assert.IsFalse(cancelCommand2.CanExecute(null));
Assert.AreSame(cancelCommand, cancelCommand2);
}
[TestMethod]
public void Test_AsyncRelayCommandOfT_GetCancelCommand_WithToken()
{
TaskCompletionSource<object?> tcs = new();
AsyncRelayCommand<string> command = new((s, token) => tcs.Task);
ICommand cancelCommand = command.CreateCancelCommand();
Assert.IsNotNull(cancelCommand);
Assert.IsFalse(cancelCommand.CanExecute(null));
// No-op
cancelCommand.Execute(null);
Assert.AreEqual("CommunityToolkit.Mvvm.Input.Internals.CancelCommand", cancelCommand.GetType().ToString());
List<(object? Sender, EventArgs Args)> cancelCommandCanExecuteChangedArgs = new();
cancelCommand.CanExecuteChanged += (s, e) => cancelCommandCanExecuteChangedArgs.Add((s, e));
command.Execute(null);
Assert.AreEqual(1, cancelCommandCanExecuteChangedArgs.Count);
Assert.AreSame(cancelCommand, cancelCommandCanExecuteChangedArgs[0].Sender);
Assert.AreSame(EventArgs.Empty, cancelCommandCanExecuteChangedArgs[0].Args);
Assert.IsTrue(cancelCommand.CanExecute(null));
cancelCommand.Execute(null);
Assert.IsFalse(cancelCommand.CanExecute(null));
Assert.AreEqual(2, cancelCommandCanExecuteChangedArgs.Count);
Assert.AreSame(cancelCommand, cancelCommandCanExecuteChangedArgs[1].Sender);
Assert.AreSame(EventArgs.Empty, cancelCommandCanExecuteChangedArgs[1].Args);
Assert.IsFalse(command.CanBeCanceled);
Assert.IsTrue(command.IsCancellationRequested);
}
}

View File

@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
@ -74,6 +75,18 @@ public async Task Test_ICommandAttribute_RelayCommand()
{
Assert.AreSame(Task.CompletedTask, tasks[i]);
}
tasks.Clear();
for (int i = 11; i < 21; i++)
{
tasks.Add(model.AddValueToListAndDelayWithDefaultConcurrencyAsync_WithCancelCommandCommand.ExecuteAsync(i));
}
Assert.AreEqual(10, tasks.Count);
// Only the first item should have been added, like the previous case
CollectionAssert.AreEqual(model.Values, Enumerable.Range(0, 12).ToArray());
}
[TestMethod]
@ -334,6 +347,34 @@ public void Test_ICommandAttribute_ViewModelRightAfterRegion()
Assert.IsInstanceOfType(model.GreetCommand, typeof(RelayCommand));
}
[TestMethod]
public async void Test_ICommandAttribute_CancelCommands()
{
CancelCommandViewModel model = new();
model.DoWorkCommand.Execute(null);
Assert.IsTrue(model.DoWorkCancelCommand.CanExecute(null));
model.DoWorkCancelCommand.Execute(null);
await Task.Yield();
Assert.IsTrue(model.Tcs1.Task.IsCompleted);
Assert.IsTrue(model.Tcs1.Task.Result is OperationCanceledException);
model.DoWorkWithParameterCommand.Execute(null);
Assert.IsTrue(model.DoWorkWithParameterCancelCommand.CanExecute(null));
model.DoWorkWithParameterCancelCommand.Execute(42);
await Task.Yield();
Assert.IsTrue(model.Tcs2.Task.IsCompleted);
Assert.IsTrue(model.Tcs2.Task.Result is 42);
}
#region Region
public class Region
{
@ -399,6 +440,14 @@ private async Task AddValueToListAndDelayWithDefaultConcurrencyAsync(int value)
await Task.Delay(1000);
}
[ICommand(IncludeCancelCommand = true)]
private async Task AddValueToListAndDelayWithDefaultConcurrencyAsync_WithCancelCommand(int value, CancellationToken token)
{
Values.Add(value);
await Task.Delay(1000);
}
#region Test region
/// <summary>
@ -567,4 +616,45 @@ public sealed class User
{
public string? Name { get; set; }
}
public partial class CancelCommandViewModel
{
public TaskCompletionSource<object?> Tcs1 { get; } = new();
public TaskCompletionSource<object?> Tcs2 { get; } = new();
[ICommand(IncludeCancelCommand = true)]
private async Task DoWorkAsync(CancellationToken token)
{
using CancellationTokenRegistration registration = token.Register(static state => ((TaskCompletionSource<object?>)state!).TrySetCanceled(), Tcs1);
try
{
_ = await Tcs1.Task;
_ = Tcs1.TrySetResult(null);
}
catch (OperationCanceledException e)
{
_ = Tcs1.TrySetResult(e);
}
}
[ICommand(IncludeCancelCommand = true)]
private async Task DoWorkWithParameterAsync(int number, CancellationToken token)
{
using CancellationTokenRegistration registration = token.Register(static state => ((TaskCompletionSource<object?>)state!).TrySetCanceled(), Tcs2);
try
{
_ = await Tcs2.Task;
_ = Tcs2.TrySetResult(null);
}
catch (OperationCanceledException)
{
_ = Tcs2.TrySetResult(number);
}
}
}
}