using System; using System.Threading; using System.Threading.Tasks; namespace AMWD.Common.Tests.Extensions { [TestClass] public class ReaderWriterLockSlimExtensionsTest { [TestMethod] public void ShouldEnterReadLock() { // arrange var rwLock = new ReaderWriterLockSlim(); // act using var disposable = rwLock.GetReadLock(); // assert Assert.IsNotNull(disposable); Assert.IsTrue(rwLock.IsReadLockHeld); Assert.IsFalse(rwLock.IsUpgradeableReadLockHeld); Assert.IsFalse(rwLock.IsWriteLockHeld); } [TestMethod] public void ShouldEnterUpgradeableReadLock() { // arrange var rwLock = new ReaderWriterLockSlim(); // act using var disposable = rwLock.GetUpgradeableReadLock(); // assert Assert.IsNotNull(disposable); Assert.IsFalse(rwLock.IsReadLockHeld); Assert.IsTrue(rwLock.IsUpgradeableReadLockHeld); Assert.IsFalse(rwLock.IsWriteLockHeld); } [TestMethod] public void ShouldAllowWriteLockAfterUpgradableReadLock() { // arrange var rwLockUsing = new ReaderWriterLockSlim(); var rwLockClassic = new ReaderWriterLockSlim(); // act using var disposableReadUsing = rwLockUsing.GetUpgradeableReadLock(); using (rwLockUsing.GetWriteLock()) { // assert Assert.IsTrue(rwLockUsing.IsUpgradeableReadLockHeld); Assert.IsTrue(rwLockUsing.IsWriteLockHeld); } // assert Assert.IsTrue(rwLockUsing.IsUpgradeableReadLockHeld); Assert.IsFalse(rwLockUsing.IsWriteLockHeld); // act using (rwLockClassic.GetUpgradeableReadLock()) { rwLockClassic.EnterWriteLock(); // assert Assert.IsTrue(rwLockClassic.IsUpgradeableReadLockHeld); Assert.IsTrue(rwLockClassic.IsWriteLockHeld); } // assert Assert.IsFalse(rwLockClassic.IsUpgradeableReadLockHeld); Assert.IsFalse(rwLockClassic.IsWriteLockHeld); } [TestMethod] public void ShouldEnterWriteLock() { // arrange var rwLock = new ReaderWriterLockSlim(); // act using var disposable = rwLock.GetWriteLock(); // assert Assert.IsNotNull(disposable); Assert.IsFalse(rwLock.IsReadLockHeld); Assert.IsFalse(rwLock.IsUpgradeableReadLockHeld); Assert.IsTrue(rwLock.IsWriteLockHeld); } [TestMethod] public void ShouldNotAllowWriteLockAfterReadLock() { // arrange var rwLock = new ReaderWriterLockSlim(); // act using var disposableRead = rwLock.GetReadLock(); try { using var disposaleWrite = rwLock.GetWriteLock(); Assert.Fail(); } catch (LockRecursionException) { } // assert Assert.IsNotNull(disposableRead); Assert.IsTrue(rwLock.IsReadLockHeld); Assert.IsFalse(rwLock.IsUpgradeableReadLockHeld); Assert.IsFalse(rwLock.IsWriteLockHeld); } [TestMethod] public void ShouldAllowWriteLockAfterUpgradeableReadLock() { // arrange var rwLock = new ReaderWriterLockSlim(); // act using var disposableRead = rwLock.GetUpgradeableReadLock(); using var disposableWrite = rwLock.GetWriteLock(); // assert Assert.IsNotNull(disposableRead); Assert.IsNotNull(disposableWrite); Assert.IsFalse(rwLock.IsReadLockHeld); Assert.IsTrue(rwLock.IsUpgradeableReadLockHeld); Assert.IsTrue(rwLock.IsWriteLockHeld); } [TestMethod] public void ShouldGetTimeoutOnReadLock() { // arrange var rwLock = new ReaderWriterLockSlim(); bool isTimeout = false; // act using var disposableRead = rwLock.GetWriteLock(); var awaitableTask = Task.Run(() => { try { using var disposableRead = rwLock.GetReadLock(10); Assert.Fail(); } catch (TimeoutException) { isTimeout = true; } catch (Exception) { /* keep it quiet */ } }); awaitableTask.Wait(); // assert Assert.IsTrue(isTimeout); } [TestMethod] public void ShouldGetTimeoutOnUpgradeableReadLock() { // arrange var rwLock = new ReaderWriterLockSlim(); bool isTimeout = false; // act using var disposableRead = rwLock.GetWriteLock(); var awaitableTask = Task.Run(() => { try { using var disposableRead = rwLock.GetUpgradeableReadLock(10); Assert.Fail(); } catch (TimeoutException) { isTimeout = true; } catch (Exception) { /* keep it quiet */ } }); awaitableTask.Wait(); // assert Assert.IsTrue(isTimeout); } [TestMethod] public void ShouldGetTimeoutOnWriteLock() { // arrange var rwLock = new ReaderWriterLockSlim(); bool isTimeout = false; // act using var disposableRead = rwLock.GetReadLock(); var awaitableTask = Task.Run(() => { try { using var disposableRead = rwLock.GetWriteLock(10); Assert.Fail(); } catch (TimeoutException) { isTimeout = true; } catch (Exception) { /* keep it quiet */ } }); awaitableTask.Wait(); // assert Assert.IsTrue(isTimeout); } } }