public async Task TestNearCacheGetAsync() // EntryIsHit { var dictionary = await _client.GetDictionaryAsync <object, object>("nc-" + TestUtils.RandomString()); await using var _ = new AsyncDisposable(dictionary.DestroyAsync); var cache = GetNearCache(dictionary); // add a value to the dictionary await dictionary.SetAsync("key", "value"); // get the value var result = await dictionary.GetAsync("key"); Assert.AreEqual("value", result); // validate that the cache contains a value Assert.AreEqual(1, cache.Count); // and that the corresponding entry has zero hits var cacheEntries = await cache.SnapshotEntriesAsync(); Assert.That(cacheEntries.Count, Is.EqualTo(1)); Assert.That(cacheEntries.First().Hits, Is.EqualTo(0)); // get the value again result = await dictionary.GetAsync("key"); Assert.AreEqual("value", result); // validate that the entry now has one hit cacheEntries = await cache.SnapshotEntriesAsync(); Assert.That(cacheEntries.Count, Is.EqualTo(1)); Assert.That(cacheEntries.First().Hits, Is.EqualTo(1)); }
public static IAsyncObservable <TSource> Finally <TSource>(this IAsyncObservable <TSource> source, Func <Task> finallyAction) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (finallyAction == null) { throw new ArgumentNullException(nameof(finallyAction)); } return(Create <TSource>(async observer => { var subscription = await source.SubscribeSafeAsync(observer).ConfigureAwait(false); return AsyncDisposable.Create(async() => { try { await subscription.DisposeAsync().ConfigureAwait(false); } finally { await finallyAction().ConfigureAwait(false); } }); })); }
public async Task Add_AfterDisposeStarts_ExecutingInSerial_InvokesActionAfterDisposeCompletes() { bool action1Invoked = false; bool action2Invoked = false; var ready = new TaskCompletionSource <object>(); var signal = new TaskCompletionSource <object>(); var disposable = AsyncDisposable.Create(async() => { action1Invoked = true; ready.TrySetResult(null); await signal.Task; }); var disposeTask = Task.Run(async() => await disposable.DisposeAsync()); await ready.Task; var addTask = Task.Run(async() => await disposable.AddAsync(async() => { action2Invoked = true; })); Assert.NotEqual(addTask, await Task.WhenAny(addTask, Task.Delay(100))); Assert.True(action1Invoked); Assert.False(action2Invoked); signal.TrySetResult(null); await disposeTask; await addTask; Assert.True(action2Invoked); }
public async Task TestNearCacheInvalidationOnRemoveAllPredicate() { var dictionary = await _client.GetDictionaryAsync <string, string>("nc-invalidate-" + TestUtils.RandomString()); await using var _ = new AsyncDisposable(dictionary.DestroyAsync); var cache = GetNearCache(dictionary); for (var i = 0; i < 100; i++) { await dictionary.SetAsync("key" + i, "value" + i); } for (var i = 0; i < 100; i++) { await dictionary.GetAsync("key" + i); } Assert.AreEqual(100, cache.Count); Assert.AreEqual(cache.Count, cache.Statistics.EntryCount); await dictionary.RemoveAsync(new SqlPredicate("this == 'value2'")); await AssertEx.SucceedsEventually(() => { Assert.AreEqual(0, cache.Count); Assert.AreEqual(cache.Count, cache.Statistics.EntryCount); }, 8000, 500); }
public ValueTask <IAsyncDisposable> Subscribe(Func <IEnumerable <FileEvent>, ValueTask> cb) { #pragma warning disable CA2000 return(ValueTask.FromResult(AsyncDisposable.Create(() => ValueTask.CompletedTask) as IAsyncDisposable)); #pragma warning restore CA2000 }
private static IAsyncObservable <TEventArgs> FromEventCore <TDelegate, TEventArgs>(Func <Action <TEventArgs>, TDelegate> conversion, Action <TDelegate> addHandler, Action <TDelegate> removeHandler, IAsyncScheduler scheduler) { return (SynchronizeEvents( Create <TEventArgs>(observer => { var handler = new Action <TEventArgs>(async e => { await observer.OnNextAsync(e).ConfigureAwait(false); }); var converted = conversion(handler); addHandler(converted); return Task.FromResult(AsyncDisposable.Create(() => { removeHandler(converted); return Task.CompletedTask; })); }), scheduler )); }
public void GetAsyncService_DisposeAsyncOnSameThread_ThrowsAndDoesNotHangAndDisposeAsyncGetsCalled() { // Arrange var services = new ServiceCollection(); var asyncDisposableResource = new AsyncDisposable(); services.AddSingleton <DisposeServiceProviderInCtorAsyncDisposable>(sp => new DisposeServiceProviderInCtorAsyncDisposable(asyncDisposableResource, sp)); var sp = services.BuildServiceProvider(); bool doesNotHang = Task.Run(() => { SingleThreadedSynchronizationContext.Run(() => { // Act Assert.Throws <ObjectDisposedException>(() => { // ctor disposes ServiceProvider var service = sp.GetRequiredService <DisposeServiceProviderInCtorAsyncDisposable>(); }); }); }).Wait(TimeSpan.FromSeconds(10)); Assert.True(doesNotHang); Assert.True(asyncDisposableResource.DisposeAsyncCalled); }
public async Task TestNearCacheTtlEviction() { var dictionary = await _client.GetDictionaryAsync <int, int>("nc-ttl-" + TestUtils.RandomString()); await using var _ = new AsyncDisposable(dictionary.DestroyAsync); var cache = GetNearCache(dictionary); var keys = Enumerable.Range(0, 10).ToList(); foreach (var k in keys) { await dictionary.SetAsync(k, k); } await dictionary.GetAsync(keys); Assert.AreEqual(keys.Count, cache.Count); await AssertEx.SucceedsEventually(async() => { await dictionary.GetAsync(100); // force ttl check foreach (var k in keys) { var keyData = ToData(k); Assert.That(await cache.ContainsKeyAsync(keyData), Is.False, $"Key {k} should have expired."); } }, 8000, 1000); }
/// <summary> /// Initializes given editor /// </summary> /// <returns>the cleanup routine</returns> public async ValueTask <IAsyncDisposable> InitializeEditor(RichTextEdit richTextEdit) { await InitializeJsInterop(); var dotNetRef = DotNetObjectReference .Create(richTextEdit); await jsRuntime.InvokeVoidAsync("blazoriseRichTextEdit.initialize", dotNetRef, richTextEdit.ElementRef, richTextEdit.ReadOnly, richTextEdit.PlaceHolder, richTextEdit.Theme == RichTextEditTheme.Snow? "snow" : "bubble", richTextEdit.SubmitOnEnter, richTextEdit.ConfigureQuillJsMethod); return(AsyncDisposable.Create(async() => { var task = DestroyEditor(richTextEdit.EditorRef); try { await task; } catch { if (!task.IsCanceled) { throw; } } dotNetRef.Dispose(); })); }
private async Task TestInvalidateAsync(Func <IHDictionary <string, string>, string, Task> invalidatingAction) { var dictionary = await _client.GetDictionaryAsync <string, string>("nc-invalidate-" + TestUtils.RandomString()); await using var _ = new AsyncDisposable(dictionary.DestroyAsync); var cache = GetNearCache(dictionary); await dictionary.SetAsync("key", "value"); var value = await dictionary.GetAsync("key"); Assert.AreEqual("value", value); Assert.AreEqual(1, cache.Count); Assert.AreEqual(cache.Count, cache.Statistics.EntryCount); await using (var client = await CreateAndStartClientAsync()) { await invalidatingAction(await client.GetDictionaryAsync <string, string>(dictionary.Name), "key"); } var keyData = ToData("key"); await AssertEx.SucceedsEventually(async() => { Assert.IsFalse(await cache.ContainsKeyAsync(keyData), "Key should have been invalidated"); }, 8000, 1000); }
public async Task <IAsyncDisposable> SubscribeAsync(IAsyncObserver <T> observer) { if (observer == null) { throw new ArgumentNullException(nameof(observer)); } bool hasValue; T value; bool done; Exception error; lock (_gate) { done = _done; error = _error; hasValue = _hasValue; value = _value; if (!done && error == null) { _observers.Add(observer); } } if (error != null) { await observer.OnErrorAsync(error).ConfigureAwait(false); return(AsyncDisposable.Nop); } else if (done) { if (hasValue) { await observer.OnNextAsync(value).ConfigureAwait(false); } await observer.OnCompletedAsync().ConfigureAwait(false); return(AsyncDisposable.Nop); } return(AsyncDisposable.Create(() => { lock (_gate) { var i = _observers.LastIndexOf(observer); if (i >= 0) { _observers.RemoveAt(i); } } return Task.CompletedTask; })); }
public async Task Dispose_InvokesAction() { bool actionInvoked = false; var disposable = AsyncDisposable.Create(async() => { actionInvoked = true; }); await disposable.DisposeAsync(); Assert.True(actionInvoked); }
public static void Explain(this AsyncDisposable runnable, TextWriter writer) { writer.WriteLine(@" - `Stream`, `Utf8JsonWriter`, `System.Threading.Timer`, `CancellationTokenRegistration`, `BinaryWriter`, `TextWriter` and `IAsyncEnumerator<T>` implement `IAsyncDisposable` - `Stream`, `BinaryWriter`, `TextWriter` calls `.Dispose` synchronously - `Stream` `FlushAsync` calls `Flush` on another thread which is bad behavior that should be overwritten "); }
public static IAsyncObservable <TResult> UsingAwaitAsync <TResult, TResource>(Func <Task <TResource> > resourceFactory, Func <TResource, Task <IAsyncObservable <TResult> > > observableFactory) where TResource : IAsyncDisposable { if (resourceFactory == null) { throw new ArgumentNullException(nameof(resourceFactory)); } if (observableFactory == null) { throw new ArgumentNullException(nameof(observableFactory)); } return(Create <TResult>(async observer => { TResource resource; try { resource = await resourceFactory().ConfigureAwait(false); } catch (Exception ex) { await observer.OnErrorAsync(ex).ConfigureAwait(false); return AsyncDisposable.Nop; } IAsyncObservable <TResult> observable; try { observable = await observableFactory(resource).ConfigureAwait(false); } catch (Exception ex) { try { await observer.OnErrorAsync(ex).ConfigureAwait(false); return AsyncDisposable.Nop; } finally { await resource.DisposeAsync().ConfigureAwait(false); } } var subscription = await observable.SubscribeSafeAsync(observer).ConfigureAwait(false); return AsyncDisposable.Create(async() => { try { await subscription.DisposeAsync().ConfigureAwait(false); } finally { await resource.DisposeAsync().ConfigureAwait(false); } }); })); }
/// <summary> /// Temporary enables a static result for an action with the given <paramref name="actionName"/> on the logic app, /// and disables the static result when the returned instance gets disposed. /// </summary> /// <param name="actionName">The name of the action to enable the static result.</param> /// <param name="definition">The definition that describes the static result for the action.</param> /// <returns> /// An instance to control when the static result for the action on the logic app should be disabled. /// </returns> public async Task<IAsyncDisposable> TemporaryEnableStaticResultAsync(string actionName, StaticResultDefinition definition) { Guard.NotNullOrEmpty(actionName, nameof(actionName)); Guard.NotNull(definition, nameof(definition)); return await AsyncDisposable.CreateAsync( async () => await EnableStaticResultForActionsAsync(new Dictionary<string, StaticResultDefinition> { [actionName] = definition }), async () => await DisableStaticResultForActionAsync(actionName)); }
public async Task AsyncDisposableDisposesAsync() { var disposable = new AsyncDisposable(); Assert.IsFalse(disposable.IsDisposed); await disposable.UsingAsync(() => { }); Assert.IsTrue(disposable.IsDisposed); }
/// <summary> /// Enables static results for a given set of actions on the logic app. /// </summary> /// <param name="actions">The set of action names and the corresponding static result.</param> /// <returns> /// An instance to control when the static result for the actions on the logic app should be disabled. /// </returns> public async Task <IAsyncDisposable> TemporaryEnableStaticResultsAsync(IDictionary <string, StaticResultDefinition> actions) { Guard.NotNull(actions, nameof(actions)); Guard.NotAny(actions, nameof(actions)); return(await AsyncDisposable.CreateAsync( async() => await EnableStaticResultForActionsAsync(actions), async() => await DisableStaticResultsForActionsAsync(actions.Keys))); }
public async Task MultipleDispose_OnlyInvokesActionOnce() { var counter = 0; var disposable = AsyncDisposable.Create(async() => { ++counter; }); await disposable.DisposeAsync(); await disposable.DisposeAsync(); Assert.Equal(1, counter); }
public async Task Dispose_AfterAddingNull_DoesNotThrow() { bool action1Invoked = false; var disposable = AsyncDisposable.Create(async() => { action1Invoked = true; }); await disposable.AddAsync(null); await disposable.DisposeAsync(); Assert.True(action1Invoked); }
public async Task TestNearCacheLfuEviction() { var dictionary = await _client.GetDictionaryAsync <object, object>("nc-lfu-" + TestUtils.RandomString()); await using var _ = new AsyncDisposable(dictionary.DestroyAsync); var cache = GetNearCache(dictionary); var keys = new List <object>(); for (var i = 0; i < MaxSize; i++) { await dictionary.SetAsync(i, i); keys.Add(i); } // make sure all keys are cached await dictionary.GetAsync(keys); // make keys in sublist accessed again var subList = keys.Take(MaxSize / 2).ToList(); await dictionary.GetAsync(subList); // Add another item, triggering eviction await dictionary.SetAsync(MaxSize, MaxSize); await dictionary.GetAsync(MaxSize); // var sl = new SortedList<int, int>(); // // foreach (var cacheRecord in cache.Records.Keys) // { // sl.Add(ClientInternal.SerializationService.ToObject<int>(cacheRecord), 0); // } // foreach (var lazy in cache.Records.Values) // { // if (lazy.Value.Hit.Get() > 0) // { // Console.WriteLine($"non zero hit {ClientInternal.SerializationService.ToObject<int>(lazy.Value.Key)}"); // } // } await AssertEx.SucceedsEventually(async() => { Assert.IsTrue(cache.Count <= MaxSize, cache.Count + " should be less than " + MaxSize); Assert.AreEqual(cache.Count, cache.Statistics.EntryCount); foreach (var key in subList) { var keyData = ToData(key); Assert.IsTrue(await cache.ContainsKeyAsync(keyData), "key " + key + " not found in cache"); } }, 8000, 1000); }
private static async Task Main() { var asyncDisposable = new AsyncDisposable(); await asyncDisposable.DisposeAsync(); _ = new ExampleClass("test").WriteSpans().DoSerialize(); await ExampleClass.DoAsyncNumbersAsync(); Console.WriteLine($"The character 7 {('7'.IsLetter() ? "is" : "is not")} a letter"); }
public async Task Dispose_AfterAdd_InvokesBothActions() { bool action1Invoked = false; bool action2Invoked = false; var disposable = AsyncDisposable.Create(async() => { action1Invoked = true; }); await disposable.AddAsync(async() => { action2Invoked = true; }); await disposable.DisposeAsync(); Assert.True(action1Invoked); Assert.True(action2Invoked); }
public async Task TestNearCacheIdleEviction() { var dictionary = await _client.GetDictionaryAsync <int, int>("nc-idle-" + TestUtils.RandomString()); await using var _ = new AsyncDisposable(dictionary.DestroyAsync); var cache = GetNearCache(dictionary); var keys = Enumerable.Range(0, 10).ToList(); foreach (var k in keys) { await dictionary.SetAsync(k, k); } Assert.AreEqual(0, cache.Count); // cache is still empty Assert.AreEqual(cache.Count, cache.Statistics.EntryCount); const int nonIdleKey = 100; await dictionary.SetAsync(nonIdleKey, nonIdleKey); Assert.AreEqual(0, cache.Count); // cache is still empty Assert.AreEqual(cache.Count, cache.Statistics.EntryCount); await dictionary.GetAsync(keys); // populates the cache Assert.AreEqual(keys.Count, cache.Count); // which only contains the 10 keys Assert.AreEqual(cache.Count, cache.Statistics.EntryCount); await dictionary.GetAsync(nonIdleKey); // also the non-idle key Assert.AreEqual(keys.Count + 1, cache.Count); // now also contains the idle key Assert.AreEqual(cache.Count, cache.Statistics.EntryCount); var nonIdleKeyData = ToData(nonIdleKey); await AssertEx.SucceedsEventually(async() => { var val = await dictionary.GetAsync(nonIdleKey); // force ttl check Assert.That(val, Is.EqualTo(100)); // note: ContainsKeyAsync(, false) to make sure we don't hit the entries, // else they would never ever become idle of course... // idle keys are going away foreach (var k in keys) { var keyData = ToData(k); Assert.IsFalse(await cache.ContainsKeyAsync(keyData, false), "Key " + k + " should have expired."); } // non-idle key is never going away Assert.IsTrue(await cache.ContainsKeyAsync(nonIdleKeyData, false), "Key 100 should not have expired."); }, 8000, 200); }
public async Task <IAsyncDisposable> ServeAsync() { var host = Host; await host.StartAsync().ConfigureAwait(false); // ReSharper disable once HeapView.BoxingAllocation return(AsyncDisposable.New(async self => { var host1 = self.Host; await host1.StopAsync().SuppressExceptions().ConfigureAwait(false); Task.Run(() => host1.Dispose()).Ignore(); self.HostLazy = new Lazy <IHost>(CreateHost); }, this)); }
/// <summary> /// Temporary disables the current logic app resource on Azure, and enables the logic app after the returned instance gets disposed. /// </summary> /// <returns> /// An instance to control the removal of the updates. /// </returns> public async Task <IAsyncDisposable> TemporaryDisableAsync() { return(await AsyncDisposable.CreateAsync( async() => { _logger.LogTrace("Disables (-) the workflow on logic app '{LogicAppName}' in resource group '{ResourceGroup}'", _logicAppName, _resourceGroup); await _logicManagementClient.Workflows.DisableAsync(_resourceGroup, _logicAppName); }, async() => { _logger.LogTrace("Enables (+) the workflow on logic app '{LogicAppName}' in resource group '{ResourceGroup}'", _logicAppName, _resourceGroup); await _logicManagementClient.Workflows.EnableAsync(_resourceGroup, _logicAppName); })); }
/// <summary> /// Updates the current JSON logic app definition with the given <paramref name="logicAppDefinition"/>, /// and removes this update after the returned instance gets disposed. /// </summary> /// <param name="logicAppDefinition">Then JSON representation of the new definition.</param> /// <returns> /// An instance to control the removal of the updates. /// </returns> public async Task<IAsyncDisposable> TemporaryUpdateAsync(string logicAppDefinition) { Guard.NotNull(logicAppDefinition, nameof(logicAppDefinition)); Workflow workflow = await _logicManagementClient.Workflows.GetAsync(_resourceGroup, _logicAppName); object originalAppDefinition = workflow.Definition; _logger.LogTrace("Updates (+) the logic app '{LogicAppName}' workflow definition in resource group '{ResourceGroup}'", _logicAppName, _resourceGroup); await UpdateAsync(workflow, JObject.Parse(logicAppDefinition)); return AsyncDisposable.Create(async () => { _logger.LogTrace("Reverts (-) the update of the logic app '{LogicAppName}' workflow definition in resource group '{ResourceGroup}'", _logicAppName, _resourceGroup); await UpdateAsync(workflow, originalAppDefinition); }); }
public async Task AsyncDisposableThrowsOnceDisposedAsync() { var disposable = new AsyncDisposable(); await disposable.UsingAsync(() => { }); var threwObjectDisposed = false; try { disposable.RequiresNotDisposed(); } catch (ObjectDisposedException) { threwObjectDisposed = true; } Assert.IsTrue(threwObjectDisposed); }
public static IAsyncObservable <TSource> SubscribeOn <TSource>(this IAsyncObservable <TSource> source, IAsyncScheduler subscribeScheduler, IAsyncScheduler disposeScheduler) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (subscribeScheduler == null) { throw new ArgumentNullException(nameof(subscribeScheduler)); } if (disposeScheduler == null) { throw new ArgumentNullException(nameof(disposeScheduler)); } return(CreateAsyncObservable <TSource> .From( source, (subscribeScheduler, disposeScheduler), static async (source, state, observer) => { var m = new SingleAssignmentAsyncDisposable(); var d = new SerialAsyncDisposable(); await d.AssignAsync(m).ConfigureAwait(false); var scheduled = await state.subscribeScheduler.ScheduleAsync(async ct => { var subscription = await source.SubscribeSafeAsync(observer).RendezVous(state.subscribeScheduler, ct); var scheduledDispose = AsyncDisposable.Create(async() => { await state.disposeScheduler.ScheduleAsync(async _ => { await subscription.DisposeAsync().RendezVous(state.disposeScheduler, ct); }).ConfigureAwait(false); }); await d.AssignAsync(scheduledDispose).RendezVous(state.subscribeScheduler, ct); }).ConfigureAwait(false); await m.AssignAsync(scheduled).ConfigureAwait(false); return d; })); }
public async Task Actions_ExecutingInSerial_ExecuteInSerial() { bool running = false; var disposable = new AsyncDisposable(null); for (int i = 0; i != 10; ++i) { await disposable.AddAsync(async() => { Assert.False(running); running = true; await Task.Delay(10); running = false; }); } await disposable.DisposeAsync(); }
public async Task TestNearCacheGet() // CacheIsPopulatedByRead { var dictionary = await _client.GetDictionaryAsync <object, object>("nc-" + TestUtils.RandomString()); await using var _ = new AsyncDisposable(dictionary.DestroyAsync); var cache = GetNearCache(dictionary); // add a vale to the dictionary await dictionary.SetAsync("key", "value"); // get the value = populates the cache await dictionary.GetAsync("key"); // validate that the value is in the cache var getAttempt = await cache.TryGetAsync(ToData("key")); Assert.That(getAttempt.Success, Is.True); Assert.That(getAttempt.Value, Is.EqualTo("value")); }
public void TestUsing1_CanceledResource_CanceledBody_AsyncDisposable() { bool executed = false; AsyncDisposable resourceObject = null; // declaring these makes it clear we are testing the correct overload Func<Task<IDisposable>> resource = () => { resourceObject = new AsyncDisposable(); return CompletedTask.Canceled<IDisposable>(); }; CancellationTokenSource cts = new CancellationTokenSource(); Func<Task<IDisposable>, Task> body = task => Task.Factory.StartNew( () => { executed = true; cts.Cancel(); cts.Token.ThrowIfCancellationRequested(); }, cts.Token); Task combinedTask = null; try { combinedTask = TaskBlocks.Using(resource, body); combinedTask.Wait(); Assert.Fail("Expected a TaskCanceledException wrapped in an AggregateException"); } catch (AggregateException ex) { Assert.IsNotNull(combinedTask, "Failed to create the combined task."); Assert.AreEqual(TaskStatus.Canceled, combinedTask.Status); Assert.AreEqual(1, ex.InnerExceptions.Count); Assert.IsInstanceOfType(ex.InnerExceptions[0], typeof(TaskCanceledException)); Assert.IsNotNull(resourceObject); Assert.IsFalse(resourceObject.Disposed); Assert.IsFalse(resourceObject.AsyncDisposed); Assert.IsFalse(executed); } }
public void TestUsing1_CompletedResource_NullBody_AsyncDisposable() { bool executed = false; AsyncDisposable resourceObject = null; // declaring these makes it clear we are testing the correct overload Func<Task<IDisposable>> resource = () => { resourceObject = new AsyncDisposable(); return CompletedTask.FromResult<IDisposable>(resourceObject); }; Func<Task<IDisposable>, Task> body = task => { executed = true; return null; }; Task combinedTask = null; try { combinedTask = TaskBlocks.Using(resource, body); combinedTask.Wait(); Assert.Fail("Expected an TaskCanceledException wrapped in an AggregateException"); } catch (AggregateException ex) { Assert.IsNotNull(combinedTask, "Failed to create the combined task."); Assert.AreEqual(TaskStatus.Canceled, combinedTask.Status); Assert.AreEqual(1, ex.InnerExceptions.Count); Assert.IsInstanceOfType(ex.InnerExceptions[0], typeof(TaskCanceledException)); Assert.IsNotNull(resourceObject); Assert.IsTrue(resourceObject.Disposed); Assert.IsTrue(resourceObject.AsyncDisposed); Assert.IsTrue(executed); } }
public void TestUsing1_CompletedResource_FaultedBody_AsyncDisposable() { bool executed = false; AsyncDisposable resourceObject = null; // declaring these makes it clear we are testing the correct overload Func<Task<IDisposable>> resource = () => { resourceObject = new AsyncDisposable(); return CompletedTask.FromResult<IDisposable>(resourceObject); }; Exception bodyException = new InvalidOperationException(); Func<Task<IDisposable>, Task> body = task => Task.Factory.StartNew(() => { executed = true; throw bodyException; }); Task combinedTask = null; try { combinedTask = TaskBlocks.Using(resource, body); combinedTask.Wait(); Assert.Fail("Expected an InvalidOperationException wrapped in an AggregateException"); } catch (AggregateException ex) { Assert.IsNotNull(combinedTask, "Failed to create the combined task."); Assert.AreEqual(TaskStatus.Faulted, combinedTask.Status); Assert.AreEqual(1, ex.InnerExceptions.Count); Assert.AreSame(bodyException, ex.InnerExceptions[0]); Assert.IsNotNull(resourceObject); Assert.IsTrue(resourceObject.Disposed); Assert.IsTrue(resourceObject.AsyncDisposed); Assert.IsTrue(executed); } }
public void TestUsing1_CompletedResource_CompletedBody_AsyncDisposable() { bool executed = false; AsyncDisposable resourceObject = null; // declaring these makes it clear we are testing the correct overload Func<Task<IDisposable>> resource = () => { resourceObject = new AsyncDisposable(); return CompletedTask.FromResult<IDisposable>(resourceObject); }; Func<Task<IDisposable>, Task> body = task => Task.Factory.StartNew(() => executed = true); Task combinedTask = TaskBlocks.Using(resource, body); combinedTask.Wait(); Assert.AreEqual(TaskStatus.RanToCompletion, combinedTask.Status); Assert.IsNotNull(resourceObject); Assert.IsTrue(resourceObject.Disposed); Assert.IsTrue(resourceObject.AsyncDisposed); Assert.IsTrue(executed); }