This repository has been archived by the owner on May 1, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Core] Missing await in Device.InvokeOnMainThreadAsync(Func<Task>) (#…
…6718) * [Core] Use local functions * [Core] Extract DeviceUnitTests * [Core] Ensure actually called from main thread * [Core] Add InvokeOnMainThread tests WithAsyncTask is expected to fail. * [Core] Rename local wrapper functions * [Core] Avoid ambiguous call CS0121: The call is ambiguous between the following methods or properties: 'Device.InvokeOnMainThreadAsync(Action)' and 'Device.InvokeOnMainThreadAsync(Func<Task>)' dotnet/roslyn#14885 dotnet/csharplang#98
- Loading branch information
1 parent
43443f4
commit ef4990b
Showing
4 changed files
with
150 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
using System; | ||
using System.Threading.Tasks; | ||
using NUnit.Framework; | ||
using Xamarin.Forms.Internals; | ||
|
||
namespace Xamarin.Forms.Core.UnitTests | ||
{ | ||
[TestFixture] | ||
public class DeviceUnitTests : BaseTestFixture | ||
{ | ||
[Test] | ||
public void TestBeginInvokeOnMainThread() | ||
{ | ||
bool calledFromMainThread = false; | ||
Device.PlatformServices = MockPlatformServices(() => calledFromMainThread = true); | ||
|
||
bool invoked = false; | ||
Device.BeginInvokeOnMainThread(() => invoked = true); | ||
|
||
Assert.True(invoked, "Action not invoked."); | ||
Assert.True(calledFromMainThread, "Action not invoked from main thread."); | ||
} | ||
|
||
[Test] | ||
public async Task TestInvokeOnMainThreadWithSyncFunc() | ||
{ | ||
bool calledFromMainThread = false; | ||
Device.PlatformServices = MockPlatformServices(() => calledFromMainThread = true); | ||
|
||
bool invoked = false; | ||
var result = await Device.InvokeOnMainThreadAsync(() => { invoked = true; return true; }); | ||
|
||
Assert.True(invoked, "Action not invoked."); | ||
Assert.True(calledFromMainThread, "Action not invoked from main thread."); | ||
Assert.True(result, "Unexpected result."); | ||
} | ||
|
||
[Test] | ||
public async Task TestInvokeOnMainThreadWithSyncAction() | ||
{ | ||
bool calledFromMainThread = false; | ||
Device.PlatformServices = MockPlatformServices(() => calledFromMainThread = true); | ||
|
||
bool invoked = false; | ||
await Device.InvokeOnMainThreadAsync(() => { invoked = true; }); | ||
|
||
Assert.True(invoked, "Action not invoked."); | ||
Assert.True(calledFromMainThread, "Action not invoked from main thread."); | ||
} | ||
|
||
[Test] | ||
public async Task TestInvokeOnMainThreadWithAsyncFunc() | ||
{ | ||
bool calledFromMainThread = false; | ||
Device.PlatformServices = MockPlatformServices(() => calledFromMainThread = true, | ||
invokeOnMainThread: action => Task.Delay(50).ContinueWith(_ => action())); | ||
|
||
bool invoked = false; | ||
var task = Device.InvokeOnMainThreadAsync(async () => { invoked = true; return true; }); | ||
Assert.True(calledFromMainThread, "Action not invoked from main thread."); | ||
Assert.False(invoked, "Action invoked early."); | ||
|
||
var result = await task; | ||
Assert.True(invoked, "Action not invoked."); | ||
Assert.True(result, "Unexpected result."); | ||
} | ||
|
||
[Test] | ||
public async Task TestInvokeOnMainThreadWithAsyncFuncError() | ||
{ | ||
bool calledFromMainThread = false; | ||
Device.PlatformServices = MockPlatformServices(() => calledFromMainThread = true, | ||
invokeOnMainThread: action => Task.Delay(50).ContinueWith(_ => action())); | ||
|
||
bool invoked = false; | ||
async Task<bool> boom() { invoked = true; throw new ApplicationException(); } | ||
var task = Device.InvokeOnMainThreadAsync(boom); | ||
Assert.True(calledFromMainThread, "Action not invoked from main thread."); | ||
Assert.False(invoked, "Action invoked early."); | ||
|
||
var aggregateEx = Assert.Throws<AggregateException>(() => task.Wait(100)); | ||
Assert.IsInstanceOf<ApplicationException>(aggregateEx.InnerException); | ||
Assert.True(invoked, "Action not invoked."); | ||
} | ||
|
||
[Test] | ||
public async Task TestInvokeOnMainThreadWithAsyncAction() | ||
{ | ||
bool calledFromMainThread = false; | ||
Device.PlatformServices = MockPlatformServices(() => calledFromMainThread = true, | ||
invokeOnMainThread: action => Task.Delay(50).ContinueWith(_ => action())); | ||
|
||
bool invoked = false; | ||
var task = Device.InvokeOnMainThreadAsync(async () => { invoked = true; }); | ||
Assert.True(calledFromMainThread, "Action not invoked from main thread."); | ||
Assert.False(invoked, "Action invoked early."); | ||
|
||
await task; | ||
Assert.True(invoked, "Action not invoked."); | ||
} | ||
|
||
[Test] | ||
public async Task TestInvokeOnMainThreadWithAsyncActionError() | ||
{ | ||
bool calledFromMainThread = false; | ||
Device.PlatformServices = MockPlatformServices(() => calledFromMainThread = true, | ||
invokeOnMainThread: action => Task.Delay(50).ContinueWith(_ => action())); | ||
|
||
bool invoked = false; | ||
async Task boom() { invoked = true; throw new ApplicationException(); } | ||
var task = Device.InvokeOnMainThreadAsync(boom); | ||
Assert.True(calledFromMainThread, "Action not invoked from main thread."); | ||
Assert.False(invoked, "Action invoked early."); | ||
|
||
var aggregateEx = Assert.Throws<AggregateException>(() => task.Wait(100)); | ||
Assert.IsInstanceOf<ApplicationException>(aggregateEx.InnerException); | ||
Assert.True(invoked, "Action not invoked."); | ||
} | ||
|
||
[Test] | ||
public void InvokeOnMainThreadThrowsWhenNull() | ||
{ | ||
Device.PlatformServices = null; | ||
Assert.Throws<InvalidOperationException>(() => Device.BeginInvokeOnMainThread(() => { })); | ||
Assert.Throws<InvalidOperationException>(() => Device.InvokeOnMainThreadAsync(() => { }).Wait(100)); | ||
Assert.Throws<InvalidOperationException>(() => Device.InvokeOnMainThreadAsync(() => true).Wait(100)); | ||
Assert.Throws<InvalidOperationException>(() => Device.InvokeOnMainThreadAsync(async () => { }).Wait(100)); | ||
Assert.Throws<InvalidOperationException>(() => Device.InvokeOnMainThreadAsync(async () => true).Wait(100)); | ||
} | ||
|
||
private IPlatformServices MockPlatformServices(Action onInvokeOnMainThread, Action<Action> invokeOnMainThread = null) | ||
{ | ||
return new MockPlatformServices( | ||
invokeOnMainThread: action => | ||
{ | ||
onInvokeOnMainThread(); | ||
|
||
if (invokeOnMainThread == null) | ||
action(); | ||
else | ||
invokeOnMainThread(action); | ||
}); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters