提交 26270c7d 编写于 作者: S Sam Harwell

Rewrite WpfTestCase using Semaphore instead of SemaphoreSlim

上级 e7d21a11
......@@ -36,6 +36,7 @@
<Compile Include="InternalUtilities\NoThrowStreamDisposer.cs" />
<Compile Include="InternalUtilities\OrderedMultiDictionary.cs" />
<Compile Include="InternalUtilities\PlatformInformation.cs" />
<Compile Include="InternalUtilities\SemaphoreExtensions.cs" />
<Compile Include="Operations\ArgumentKind.cs" />
<Compile Include="Operations\BinaryOperandsKind.cs" />
<Compile Include="Operations\BinaryOperationKind.cs" />
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Roslyn.Utilities
{
internal static class SemaphoreExtensions
{
public static SemaphoreDisposer DisposableWait(this Semaphore semaphore, CancellationToken cancellationToken = default(CancellationToken))
{
if (cancellationToken.CanBeCanceled)
{
int signalledIndex = WaitHandle.WaitAny(new[] { semaphore, cancellationToken.WaitHandle });
if (signalledIndex != 0)
{
cancellationToken.ThrowIfCancellationRequested();
throw ExceptionUtilities.Unreachable;
}
}
else
{
semaphore.WaitOne();
}
return new SemaphoreDisposer(semaphore);
}
public static Task<SemaphoreDisposer> DisposableWaitAsync(this Semaphore semaphore, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.Run(() => DisposableWait(semaphore, cancellationToken));
}
internal struct SemaphoreDisposer : IDisposable
{
private readonly Semaphore _semaphore;
public SemaphoreDisposer(Semaphore semaphore)
{
_semaphore = semaphore;
}
public void Dispose()
{
_semaphore.Release();
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading;
using System;
using Xunit.Abstractions;
using Xunit.Sdk;
......@@ -11,11 +11,12 @@ public class WpfFactDiscoverer : FactDiscoverer
private readonly IMessageSink _diagnosticMessageSink;
/// <summary>
/// A <see cref="SemaphoreSlim"/> used to ensure that only a single <see cref="WpfFactAttribute"/>-attributed test runs at once.
/// This requirement must be made because, currently, <see cref="WpfTestCase"/>'s logic sets various static state before a method
/// runs. If two tests run interleaved on the same scheduler (i.e. if one yields with an await) then all bets are off.
/// The name of a <see cref="Semaphore"/> used to ensure that only a single
/// <see cref="WpfFactAttribute"/>-attributed test runs at once. This requirement must be made because,
/// currently, <see cref="WpfTestCase"/>'s logic sets various static state before a method runs. If two tests
/// run interleaved on the same scheduler (i.e. if one yields with an await) then all bets are off.
/// </summary>
private readonly SemaphoreSlim _wpfTestSerializationGate = new SemaphoreSlim(initialCount: 1);
private readonly Guid _wpfTestSerializationGate = Guid.NewGuid();
public WpfFactDiscoverer(IMessageSink diagnosticMessageSink) : base(diagnosticMessageSink)
{
......
......@@ -18,19 +18,20 @@ namespace Roslyn.Test.Utilities
{
public class WpfTestCase : XunitTestCase
{
private readonly SemaphoreSlim _wpfTestSerializationGate;
private Guid _semaphoreName;
private Semaphore _wpfTestSerializationGate;
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")]
public WpfTestCase()
{
_wpfTestSerializationGate = new SemaphoreSlim(1);
}
public WpfTestCase(IMessageSink diagnosticMessageSink, TestMethodDisplay defaultMethodDisplay, ITestMethod testMethod, SemaphoreSlim wpfTestSerializationGate, object[] testMethodArguments = null)
public WpfTestCase(IMessageSink diagnosticMessageSink, TestMethodDisplay defaultMethodDisplay, ITestMethod testMethod, Guid wpfTestSerializationGate, object[] testMethodArguments = null)
: base(diagnosticMessageSink, defaultMethodDisplay, testMethod, testMethodArguments)
{
_wpfTestSerializationGate = wpfTestSerializationGate;
_semaphoreName = wpfTestSerializationGate;
_wpfTestSerializationGate = new Semaphore(1, 1, _semaphoreName.ToString("N"));
}
public override Task<RunSummary> RunAsync(IMessageSink diagnosticMessageSink, IMessageBus messageBus, object[] constructorArguments, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource)
......@@ -96,6 +97,19 @@ public override Task<RunSummary> RunAsync(IMessageSink diagnosticMessageSink, IM
return task.Unwrap();
}
public override void Serialize(IXunitSerializationInfo data)
{
base.Serialize(data);
data.AddValue(nameof(_semaphoreName), _semaphoreName.ToString("N"));
}
public override void Deserialize(IXunitSerializationInfo data)
{
base.Deserialize(data);
_semaphoreName = Guid.ParseExact(data.GetValue<string>(nameof(_semaphoreName)), "N");
_wpfTestSerializationGate = new Semaphore(1, 1, _semaphoreName.ToString("N"));
}
private static string s_wpfFactRequirementReason;
/// <summary>
......
......@@ -129,6 +129,9 @@
<Compile Include="..\..\..\Compilers\Core\Portable\InternalUtilities\ReferenceEqualityComparer.cs">
<Link>InternalUtilities\ReferenceEqualityComparer.cs</Link>
</Compile>
<Compile Include="..\..\..\Compilers\Core\Portable\InternalUtilities\SemaphoreExtensions.cs">
<Link>InternalUtilities\SemaphoreExtensions.cs</Link>
</Compile>
<Compile Include="..\..\..\Compilers\Core\Portable\InternalUtilities\SemaphoreSlimExtensions.cs">
<Link>InternalUtilities\SemaphoreSlimExtensions.cs</Link>
</Compile>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册