From 9b11454772156a6792b92ae9d5e7ddfeea9319b3 Mon Sep 17 00:00:00 2001 From: Carl de Billy Date: Fri, 5 Oct 2018 10:33:59 -0400 Subject: [PATCH 1/3] Added a test for AsyncLock --- .../Threading/LockAsyncFixture.cs | 99 +++++++++++++++++++ src/Uno.Core/Threading/AsyncLock.cs | 34 +++---- src/Uno.Core/Threading/FastAsyncLock.cs | 8 +- 3 files changed, 120 insertions(+), 21 deletions(-) create mode 100644 src/Uno.Core.Tests/Threading/LockAsyncFixture.cs diff --git a/src/Uno.Core.Tests/Threading/LockAsyncFixture.cs b/src/Uno.Core.Tests/Threading/LockAsyncFixture.cs new file mode 100644 index 0000000..c2becfd --- /dev/null +++ b/src/Uno.Core.Tests/Threading/LockAsyncFixture.cs @@ -0,0 +1,99 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Uno.Threading; + +namespace Uno.Core.Tests.Threading +{ + [TestClass] + public class LockAsyncFixture + { + [TestMethod] + public async Task BasicLock() + { + var gate = new AsyncLock(); + var sync = new object(); + var gate2 = new object(); + var current = 0; + var maxCurrent = 0; + var waiting = 0; + + var func1 = Funcs.Create(async ct => { + + await Task.Yield(); + + lock (sync) + { + waiting++; + Monitor.Wait(sync); + } + + using(await gate.LockAsync(ct)) + { + lock (gate2) + { + current++; + maxCurrent = Math.Max(current, maxCurrent); + } + + await Task.Delay(100); + + lock (gate2) + { + current--; + } + } + + return 42; + }); + + var c1 = func1(CancellationToken.None); + var c2 = func1(CancellationToken.None); + + while (waiting != 2) + { + await Task.Delay(100); + } + + lock(sync) + { + Monitor.PulseAll(sync); + } + + await c1; + await c2; + + Assert.AreEqual(1, maxCurrent); + } + + [TestMethod] + public async Task CancelledLock() + { + var gate = new AsyncLock(); + + var func = Funcs.Create(async (int wait, CancellationToken ct) => { + + using(await gate.LockAsync(ct)) + { + await Task.Delay(wait, ct); + } + + return 42; + }); + + using (await gate.LockAsync(CancellationToken.None)) + { + var cts = new CancellationTokenSource(); + var r1 = func(100000, cts.Token); + + cts.Cancel(); + + Assert.AreEqual(TaskStatus.Canceled, r1.Status); + } + + var r2 = await func(1000, CancellationToken.None); + Assert.AreEqual(42, r2); + } + } +} diff --git a/src/Uno.Core/Threading/AsyncLock.cs b/src/Uno.Core/Threading/AsyncLock.cs index bf74c20..6357618 100644 --- a/src/Uno.Core/Threading/AsyncLock.cs +++ b/src/Uno.Core/Threading/AsyncLock.cs @@ -22,23 +22,23 @@ namespace Uno.Threading { - /// - /// An asynchronous lock, that can be used in conjuction with C# async/await - /// - public sealed class AsyncLock - { - private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); + /// + /// An asynchronous lock, that can be used in conjunction with C# async/await + /// + public sealed class AsyncLock + { + private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); - /// - /// Acquires the lock, then provides a disposable to release it. - /// - /// A cancellation token to cancel the lock - /// An IDisposable instance that allows the release of the lock. - public async Task LockAsync(CancellationToken ct) - { - await _semaphore.WaitAsync(ct); + /// + /// Acquires the lock, then provides a disposable to release it. + /// + /// A cancellation token to cancel the lock + /// An IDisposable instance that allows the release of the lock. + public async Task LockAsync(CancellationToken ct) + { + await _semaphore.WaitAsync(ct); - return Disposable.Create(() => _semaphore.Release()); - } - } + return Disposable.Create(() => _semaphore.Release()); + } + } } diff --git a/src/Uno.Core/Threading/FastAsyncLock.cs b/src/Uno.Core/Threading/FastAsyncLock.cs index 2ffaa6d..e796572 100644 --- a/src/Uno.Core/Threading/FastAsyncLock.cs +++ b/src/Uno.Core/Threading/FastAsyncLock.cs @@ -23,7 +23,7 @@ namespace Uno.Threading { /// - /// An re-entrant asynchronous lock, that can be used in conjuction with C# async/await + /// An re-entrant asynchronous lock, that can be used in conjunction with C# async/await /// public sealed class FastAsyncLock { @@ -159,7 +159,7 @@ void Abort() private void Dequeued() { - // Dequeing may occures more than once. So move to next step only if item is really waiting! + // Dequeing may occured more than once. So move to next step only if item is really waiting! switch (Interlocked.CompareExchange(ref _state, State.Entered, State.Waiting)) { case State.Waiting: @@ -201,7 +201,7 @@ public void Exit() // As we are running asynchronous, it may occures that the inner task completes from another execution context (e.g. an event). // So unlike the synchronous lock which must be exited from the same execution context / thread (otherwise we receive an SynchronizationLockException), // here we cannot enforce the 'Exit' to be invoked only from the entering execution context (ie. check that '_owner._localMonitor.Value == this') - // Consequently, we have to handle concurrency with ReEntrency (Enter{Sync|Async} are not impacted since for those the caller did not received an 'Handle' yet) + // Consequently, we have to handle concurrency with Reentrency (Enter{Sync|Async} are not impacted since for those the caller did not received an 'Handle' yet) if (Interlocked.Decrement(ref _count) == 0) { @@ -217,7 +217,7 @@ public void Exit() } /// - /// An handle on an async lock which makes sure that disposing it mutiple times won't exit the monitor multiple times + /// An handle on an async lock which makes sure that disposing it multiple times won't exit the monitor multiple times /// private class Handle : IDisposable { From c0434b2d0208dd617996b7ea34966c9e781633dd Mon Sep 17 00:00:00 2001 From: Carl de Billy Date: Fri, 5 Oct 2018 10:34:25 -0400 Subject: [PATCH 2/3] Fixed a test was culture-dependent --- .../Extensions/StringExtensionsFixture.cs | 30 +++++++++++++------ .../Threading/LockAsyncFixture.cs | 18 ++++++++++- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/src/Uno.Core.Tests/Extensions/StringExtensionsFixture.cs b/src/Uno.Core.Tests/Extensions/StringExtensionsFixture.cs index 9b42bac..48cac58 100644 --- a/src/Uno.Core.Tests/Extensions/StringExtensionsFixture.cs +++ b/src/Uno.Core.Tests/Extensions/StringExtensionsFixture.cs @@ -315,15 +315,27 @@ public void StringFormatsErrorHandlingAreIdentical() [TestMethod] public void CustomStringFormatsWithMultipleValues() { - Assert.AreEqual( - StringExtensions.Format("For {0} and {1}?", 42, 3.1416), - "For 42 and 3.1416?"); - Assert.AreEqual( - StringExtensions.Format("For {0:#.##;(#.##);ZERO} and {1:#.##;(#.##);ZERO}?", 42, 3.1416), - "For 42 and 3.14?"); - Assert.AreEqual( - StringExtensions.Format("For {0:#.##;(#.##);ZERO;ONE}, {1:#.##;(#.##);ZERO;ONE} and {2:#.##;(#.##);ZERO;ONE}?", 42, 3.1416, 1.004), - "For 42, 3.14 and ONE?"); + var previous = CultureInfo.CurrentUICulture; + try + { + CultureInfo.CurrentUICulture = new CultureInfo("en-US", false); + + Assert.AreEqual( + StringExtensions.Format("For {0} and {1}?", 42, 3.1416), + "For 42 and 3.1416?"); + Assert.AreEqual( + StringExtensions.Format("For {0:#.##;(#.##);ZERO} and {1:#.##;(#.##);ZERO}?", 42, 3.1416), + "For 42 and 3.14?"); + Assert.AreEqual( + StringExtensions.Format( + "For {0:#.##;(#.##);ZERO;ONE}, {1:#.##;(#.##);ZERO;ONE} and {2:#.##;(#.##);ZERO;ONE}?", 42, + 3.1416, 1.004), + "For 42, 3.14 and ONE?"); + } + finally + { + CultureInfo.CurrentUICulture = previous; + } } } } diff --git a/src/Uno.Core.Tests/Threading/LockAsyncFixture.cs b/src/Uno.Core.Tests/Threading/LockAsyncFixture.cs index c2becfd..1c2c36d 100644 --- a/src/Uno.Core.Tests/Threading/LockAsyncFixture.cs +++ b/src/Uno.Core.Tests/Threading/LockAsyncFixture.cs @@ -1,4 +1,20 @@ -using System; +// ****************************************************************** +// Copyright � 2015-2018 nventive inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ****************************************************************** +using System; using System.Threading; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; From df1c85a32a521f01c7b89bfe3d76feddfdf37b3a Mon Sep 17 00:00:00 2001 From: Carl de Billy Date: Fri, 5 Oct 2018 13:08:42 -0400 Subject: [PATCH 3/3] Improved README.md --- README.md | 18 ++++++++++++++++++ Readme.md | 13 ------------- 2 files changed, 18 insertions(+), 13 deletions(-) create mode 100644 README.md delete mode 100644 Readme.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..82b7cb8 --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +# Uno.Core + +Uno.Core is nventive's attempt at filling some gaps in the existing .net framework and related technologies; hence reducing friction +and increasing the predictability of the api. It consists of a set of helpers, extension methods and additional abstractions. + +## Build status + +| Target | Branch | Status | Usage | +| ------ | ------ | ------ | ----- | +| development | master |[![Build status](https://ci.appveyor.com/api/projects/status/2h6icw8bwdvf2x68/branch/master?svg=true)](https://ci.appveyor.com/project/nventivedevops/uno-core/branch/master) | For developing and testing | +| beta | beta |[![Build status](https://ci.appveyor.com/api/projects/status/2h6icw8bwdvf2x68/branch/beta?svg=true)](https://ci.appveyor.com/project/nventivedevops/uno-core/branch/beta) | Testing before release as stable | +| release | stable |[![Build status](https://ci.appveyor.com/api/projects/status/2h6icw8bwdvf2x68/branch/stable?svg=true)](https://ci.appveyor.com/project/nventivedevops/uno-core/branch/stable) | Last stable version | + +## Package +[![NuGet](https://img.shields.io/nuget/v/Uno.Core.svg)](https://www.nuget.org/packages/Uno.Core/) + +## Documentation +_Coming soon._ \ No newline at end of file diff --git a/Readme.md b/Readme.md deleted file mode 100644 index 17d01d5..0000000 --- a/Readme.md +++ /dev/null @@ -1,13 +0,0 @@ -# Uno.Core - -Uno.Core is nventive's attempt at filling some gaps in the existing .net framework and related technologies; hence reducing friction -and increasing the predictability of the api. It consists of a set of helpers, extension methods and additional abstractions. - -## Build status - -| Target | Branch | Status | Recommended Nuget packages version | -| ------ | ------ | ------ | ------ | -| development | master |[![Build status](https://ci.appveyor.com/api/projects/status/2h6icw8bwdvf2x68/branch/master?svg=true)](https://ci.appveyor.com/project/nventivedevops/uno-core/branch/master) | [![NuGet](https://img.shields.io/nuget/v/Uno.Core.svg)](https://www.nuget.org/packages/Uno.Core/) | - -## Documentation -_Coming soon._ \ No newline at end of file