// // Copyright (c) Umbraco. // // See LICENSE for more details. // // using System.Linq; // using System.Threading.Tasks; // using Moq; // using NUnit.Framework; // using Umbraco.Cms.Core.Scoping; // using Umbraco.Cms.Infrastructure.PublishedCache; // // namespace Umbraco.Cms.Tests.UnitTests.Umbraco.PublishedCache.NuCache; // // FIXME: Reintroduce if relevant // [TestFixture] // public class SnapDictionaryTests // { // [Test] // public void LiveGenUpdate() // { // var d = new SnapDictionary(); // d.Test.CollectAuto = false; // // Assert.AreEqual(0, d.Test.GetValues(1).Length); // // // gen 1 // d.Set(1, "one"); // Assert.AreEqual(1, d.Test.GetValues(1).Length); // d.Clear(1); // Assert.AreEqual(0, d.Test.GetValues(1).Length); // gone // // Assert.AreEqual(1, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // Assert.AreEqual(0, d.Test.FloorGen); // } // // [Test] // public void OtherGenUpdate() // { // var d = new SnapDictionary(); // d.Test.CollectAuto = false; // // Assert.AreEqual(0, d.Test.GetValues(1).Length); // Assert.AreEqual(0, d.Test.LiveGen); // Assert.IsFalse(d.Test.NextGen); // // // gen 1 // d.Set(1, "one"); // Assert.AreEqual(1, d.Test.GetValues(1).Length); // Assert.AreEqual(1, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // var s = d.CreateSnapshot(); // Assert.AreEqual(1, s.Gen); // Assert.AreEqual(1, d.Test.LiveGen); // Assert.IsFalse(d.Test.NextGen); // // // gen 2 // d.Clear(1); // Assert.AreEqual(2, d.Test.GetValues(1).Length); // there // Assert.AreEqual(2, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // Assert.AreEqual(0, d.Test.FloorGen); // // GC.KeepAlive(s); // } // // [Test] // public void MissingReturnsNull() // { // var d = new SnapDictionary(); // var s = d.CreateSnapshot(); // // Assert.IsNull(s.Get(1)); // } // // [Test] // public void DeletedReturnsNull() // { // var d = new SnapDictionary(); // // // gen 1 // d.Set(1, "one"); // // var s1 = d.CreateSnapshot(); // Assert.AreEqual("one", s1.Get(1)); // // // gen 2 // d.Clear(1); // // var s2 = d.CreateSnapshot(); // Assert.IsNull(s2.Get(1)); // // Assert.AreEqual("one", s1.Get(1)); // } // // [Retry(5)] // TODO make this test non-flaky. // [Test] // public async Task CollectValues() // { // var d = new SnapDictionary(); // d.Test.CollectAuto = false; // // // gen 1 // d.Set(1, "one"); // Assert.AreEqual(1, d.Test.GetValues(1).Length); // d.Set(1, "one"); // Assert.AreEqual(1, d.Test.GetValues(1).Length); // d.Set(1, "uno"); // Assert.AreEqual(1, d.Test.GetValues(1).Length); // // Assert.AreEqual(1, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // var s1 = d.CreateSnapshot(); // // Assert.AreEqual(1, d.Test.LiveGen); // Assert.IsFalse(d.Test.NextGen); // // // gen 2 // Assert.AreEqual(1, d.Test.GetValues(1).Length); // d.Set(1, "one"); // Assert.AreEqual(2, d.Test.GetValues(1).Length); // d.Set(1, "uno"); // Assert.AreEqual(2, d.Test.GetValues(1).Length); // // Assert.AreEqual(2, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // var s2 = d.CreateSnapshot(); // // Assert.AreEqual(2, d.Test.LiveGen); // Assert.IsFalse(d.Test.NextGen); // // // gen 3 // Assert.AreEqual(2, d.Test.GetValues(1).Length); // d.Set(1, "one"); // Assert.AreEqual(3, d.Test.GetValues(1).Length); // d.Set(1, "uno"); // Assert.AreEqual(3, d.Test.GetValues(1).Length); // // Assert.AreEqual(3, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // var tv = d.Test.GetValues(1); // Assert.AreEqual(3, tv[0].Gen); // Assert.AreEqual(2, tv[1].Gen); // Assert.AreEqual(1, tv[2].Gen); // // Assert.AreEqual(0, d.Test.FloorGen); // // // nothing to collect // await d.CollectAsync(); // GC.KeepAlive(s1); // GC.KeepAlive(s2); // Assert.AreEqual(0, d.Test.FloorGen); // Assert.AreEqual(3, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // Assert.AreEqual(2, d.SnapCount); // Assert.AreEqual(3, d.Test.GetValues(1).Length); // // // one snapshot to collect // s1 = null; // GC.Collect(); // GC.KeepAlive(s2); // await d.CollectAsync(); // Assert.AreEqual(1, d.Test.FloorGen); // Assert.AreEqual(3, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // Assert.AreEqual(1, d.SnapCount); // Assert.AreEqual(2, d.Test.GetValues(1).Length); // // // another snapshot to collect // s2 = null; // GC.Collect(); // await d.CollectAsync(); // Assert.AreEqual(2, d.Test.FloorGen); // Assert.AreEqual(3, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // Assert.AreEqual(0, d.SnapCount); // Assert.AreEqual(1, d.Test.GetValues(1).Length); // } // // [Test] // public async Task ProperlyCollects() // { // var d = new SnapDictionary(); // d.Test.CollectAuto = false; // // for (var i = 0; i < 32; i++) // { // d.Set(i, i.ToString()); // d.CreateSnapshot().Dispose(); // } // // Assert.AreEqual(32, d.GenCount); // Assert.AreEqual(0, d.SnapCount); // because we've disposed them // // await d.CollectAsync(); // Assert.AreEqual(32, d.Test.LiveGen); // Assert.IsFalse(d.Test.NextGen); // Assert.AreEqual(0, d.GenCount); // Assert.AreEqual(0, d.SnapCount); // Assert.AreEqual(32, d.Count); // // for (var i = 0; i < 32; i++) // { // d.Set(i, null); // } // // d.CreateSnapshot().Dispose(); // // // because we haven't collected yet, but disposed nevertheless // Assert.AreEqual(1, d.GenCount); // Assert.AreEqual(0, d.SnapCount); // Assert.AreEqual(32, d.Count); // // // once we collect, they are all gone // // since noone is interested anymore // await d.CollectAsync(); // Assert.AreEqual(0, d.GenCount); // Assert.AreEqual(0, d.SnapCount); // Assert.AreEqual(0, d.Count); // } // // [Retry(5)] // TODO make this test non-flaky. // [Test] // public async Task CollectNulls() // { // var d = new SnapDictionary(); // d.Test.CollectAuto = false; // // // gen 1 // d.Set(1, "one"); // Assert.AreEqual(1, d.Test.GetValues(1).Length); // d.Set(1, "one"); // Assert.AreEqual(1, d.Test.GetValues(1).Length); // d.Set(1, "uno"); // Assert.AreEqual(1, d.Test.GetValues(1).Length); // // Assert.AreEqual(1, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // var s1 = d.CreateSnapshot(); // // Assert.AreEqual(1, d.Test.LiveGen); // Assert.IsFalse(d.Test.NextGen); // // // gen 2 // Assert.AreEqual(1, d.Test.GetValues(1).Length); // d.Set(1, "one"); // Assert.AreEqual(2, d.Test.GetValues(1).Length); // d.Set(1, "uno"); // Assert.AreEqual(2, d.Test.GetValues(1).Length); // // Assert.AreEqual(2, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // var s2 = d.CreateSnapshot(); // // Assert.AreEqual(2, d.Test.LiveGen); // Assert.IsFalse(d.Test.NextGen); // // // gen 3 // Assert.AreEqual(2, d.Test.GetValues(1).Length); // d.Set(1, "one"); // Assert.AreEqual(3, d.Test.GetValues(1).Length); // d.Set(1, "uno"); // Assert.AreEqual(3, d.Test.GetValues(1).Length); // d.Clear(1); // Assert.AreEqual(3, d.Test.GetValues(1).Length); // // Assert.AreEqual(3, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // var tv = d.Test.GetValues(1); // Assert.AreEqual(3, tv[0].Gen); // Assert.AreEqual(2, tv[1].Gen); // Assert.AreEqual(1, tv[2].Gen); // // Assert.AreEqual(0, d.Test.FloorGen); // // // nothing to collect // await d.CollectAsync(); // GC.KeepAlive(s1); // GC.KeepAlive(s2); // Assert.AreEqual(0, d.Test.FloorGen); // Assert.AreEqual(3, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // Assert.AreEqual(2, d.SnapCount); // Assert.AreEqual(3, d.Test.GetValues(1).Length); // // // one snapshot to collect // s1 = null; // GC.Collect(); // GC.KeepAlive(s2); // await d.CollectAsync(); // Assert.AreEqual(1, d.Test.FloorGen); // Assert.AreEqual(3, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // Assert.AreEqual(1, d.SnapCount); // Assert.AreEqual(2, d.Test.GetValues(1).Length); // // // another snapshot to collect // s2 = null; // GC.Collect(); // await d.CollectAsync(); // Assert.AreEqual(2, d.Test.FloorGen); // Assert.AreEqual(3, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // Assert.AreEqual(0, d.SnapCount); // // // and everything is gone? // // no, cannot collect the live gen because we'd need to lock // Assert.AreEqual(1, d.Test.GetValues(1).Length); // // d.CreateSnapshot(); // GC.Collect(); // await d.CollectAsync(); // // // poof, gone // Assert.AreEqual(0, d.Test.GetValues(1).Length); // } // // [Test] // [Retry(5)] // TODO make this test non-flaky. // public async Task EventuallyCollectNulls() // { // var d = new SnapDictionary(); // d.Test.CollectAuto = false; // // Assert.AreEqual(0, d.Test.GetValues(1).Length); // // // gen 1 // d.Set(1, "one"); // Assert.AreEqual(1, d.Test.GetValues(1).Length); // // Assert.AreEqual(1, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // await d.CollectAsync(); // var tv = d.Test.GetValues(1); // Assert.AreEqual(1, tv.Length); // Assert.AreEqual(1, tv[0].Gen); // // var s = d.CreateSnapshot(); // Assert.AreEqual("one", s.Get(1)); // // Assert.AreEqual(1, d.Test.LiveGen); // Assert.IsFalse(d.Test.NextGen); // // Assert.AreEqual(1, d.Count); // Assert.AreEqual(1, d.SnapCount); // Assert.AreEqual(1, d.GenCount); // // // gen 2 // d.Clear(1); // tv = d.Test.GetValues(1); // Assert.AreEqual(2, tv.Length); // Assert.AreEqual(2, tv[0].Gen); // // Assert.AreEqual(2, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // Assert.AreEqual(1, d.Count); // Assert.AreEqual(1, d.SnapCount); // Assert.AreEqual(1, d.GenCount); // // // nothing to collect // await d.CollectAsync(); // GC.KeepAlive(s); // Assert.AreEqual(2, d.Test.GetValues(1).Length); // // Assert.AreEqual(1, d.Count); // Assert.AreEqual(1, d.SnapCount); // Assert.AreEqual(1, d.GenCount); // // Assert.AreEqual(2, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // // collect snapshot // // don't collect liveGen+ // s = null; // without being disposed // GC.Collect(); // should release the generation reference // await d.CollectAsync(); // // Assert.AreEqual(1, d.Test.GetValues(1).Length); // "one" value is gone // Assert.AreEqual(1, d.Count); // still have 1 item // Assert.AreEqual(0, d.SnapCount); // snapshot is gone // Assert.AreEqual(0, d.GenCount); // and generation has been dequeued // // // liveGen/nextGen // s = d.CreateSnapshot(); // s = null; // // // collect liveGen // GC.Collect(); // // Assert.IsTrue(d.Test.GenObjs.TryPeek(out var genObj)); // genObj = null; // // // in Release mode, it works, but in Debug mode, the weak reference is still alive // // and for some reason we need to do this to ensure it is collected // #if DEBUG // await d.CollectAsync(); // GC.Collect(); // #endif // // Assert.IsTrue(d.Test.GenObjs.TryPeek(out genObj)); // Assert.IsFalse(genObj.WeakGenRef.IsAlive); // snapshot is gone, along with its reference // // await d.CollectAsync(); // // Assert.AreEqual(0, d.Test.GetValues(1).Length); // null value is gone // Assert.AreEqual(0, d.Count); // item is gone // Assert.AreEqual(0, d.Test.GenObjs.Count); // Assert.AreEqual(0, d.SnapCount); // snapshot is gone // Assert.AreEqual(0, d.GenCount); // and generation has been dequeued // } // // [Test] // public async Task CollectDisposedSnapshots() // { // var d = new SnapDictionary(); // d.Test.CollectAuto = false; // // // gen 1 // d.Set(1, "one"); // Assert.AreEqual(1, d.Test.GetValues(1).Length); // // Assert.AreEqual(1, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // var s1 = d.CreateSnapshot(); // // Assert.AreEqual(1, d.Test.LiveGen); // Assert.IsFalse(d.Test.NextGen); // // // gen 2 // d.Set(1, "two"); // Assert.AreEqual(2, d.Test.GetValues(1).Length); // // Assert.AreEqual(2, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // var s2 = d.CreateSnapshot(); // // Assert.AreEqual(2, d.Test.LiveGen); // Assert.IsFalse(d.Test.NextGen); // // // gen 3 // d.Set(1, "three"); // Assert.AreEqual(3, d.Test.GetValues(1).Length); // // Assert.AreEqual(3, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // var s3 = d.CreateSnapshot(); // // Assert.AreEqual(3, d.Test.LiveGen); // Assert.IsFalse(d.Test.NextGen); // // Assert.AreEqual(3, d.SnapCount); // // s1.Dispose(); // await d.CollectAsync(); // Assert.AreEqual(2, d.SnapCount); // Assert.AreEqual(2, d.Test.GetValues(1).Length); // // s2.Dispose(); // await d.CollectAsync(); // Assert.AreEqual(1, d.SnapCount); // Assert.AreEqual(1, d.Test.GetValues(1).Length); // // s3.Dispose(); // await d.CollectAsync(); // Assert.AreEqual(0, d.SnapCount); // Assert.AreEqual(1, d.Test.GetValues(1).Length); // } // // [Retry(5)] // TODO make this test non-flaky. // [Test] // public async Task CollectGcSnapshots() // { // var d = new SnapDictionary(); // d.Test.CollectAuto = false; // // // gen 1 // d.Set(1, "one"); // Assert.AreEqual(1, d.Test.GetValues(1).Length); // // Assert.AreEqual(1, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // var s1 = d.CreateSnapshot(); // // Assert.AreEqual(1, d.Test.LiveGen); // Assert.IsFalse(d.Test.NextGen); // // // gen 2 // d.Set(1, "two"); // Assert.AreEqual(2, d.Test.GetValues(1).Length); // // Assert.AreEqual(2, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // var s2 = d.CreateSnapshot(); // // Assert.AreEqual(2, d.Test.LiveGen); // Assert.IsFalse(d.Test.NextGen); // // // gen 3 // d.Set(1, "three"); // Assert.AreEqual(3, d.Test.GetValues(1).Length); // // Assert.AreEqual(3, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // var s3 = d.CreateSnapshot(); // // Assert.AreEqual(3, d.Test.LiveGen); // Assert.IsFalse(d.Test.NextGen); // // Assert.AreEqual(3, d.SnapCount); // // s1 = s2 = s3 = null; // // await d.CollectAsync(); // Assert.AreEqual(3, d.SnapCount); // Assert.AreEqual(3, d.Test.GetValues(1).Length); // // GC.Collect(); // await d.CollectAsync(); // Assert.AreEqual(0, d.SnapCount); // Assert.AreEqual(1, d.Test.GetValues(1).Length); // } // // [Retry(5)] // TODO make this test non-flaky. // [Test] // public async Task RandomTest1() // { // var d = new SnapDictionary(); // d.Test.CollectAuto = false; // // d.Set(1, "one"); // d.Set(2, "two"); // // var s1 = d.CreateSnapshot(); // var v1 = s1.Get(1); // Assert.AreEqual("one", v1); // // d.Set(1, "uno"); // // var s2 = d.CreateSnapshot(); // var v2 = s2.Get(1); // Assert.AreEqual("uno", v2); // // v1 = s1.Get(1); // Assert.AreEqual("one", v1); // // Assert.AreEqual(2, d.SnapCount); // // s1 = null; // GC.Collect(); // await d.CollectAsync(); // // GC.Collect(); // await d.CollectAsync(); // // Assert.AreEqual(1, d.SnapCount); // v2 = s2.Get(1); // Assert.AreEqual("uno", v2); // // s2 = null; // GC.Collect(); // await d.CollectAsync(); // // Assert.AreEqual(0, d.SnapCount); // } // // [Retry(5)] // TODO make this test non-flaky. // [Test] // public async Task RandomTest2() // { // var d = new SnapDictionary(); // d.Test.CollectAuto = false; // // d.Set(1, "one"); // d.Set(2, "two"); // // var s1 = d.CreateSnapshot(); // var v1 = s1.Get(1); // Assert.AreEqual("one", v1); // // d.Clear(1); // // var s2 = d.CreateSnapshot(); // var v2 = s2.Get(1); // Assert.AreEqual(null, v2); // // v1 = s1.Get(1); // Assert.AreEqual("one", v1); // // Assert.AreEqual(2, d.SnapCount); // // s1 = null; // GC.Collect(); // await d.CollectAsync(); // // GC.Collect(); // await d.CollectAsync(); // // Assert.AreEqual(1, d.SnapCount); // v2 = s2.Get(1); // Assert.AreEqual(null, v2); // // s2 = null; // GC.Collect(); // await d.CollectAsync(); // // Assert.AreEqual(0, d.SnapCount); // } // // [Test] // public void WriteLockingFirstSnapshot() // { // var d = new SnapDictionary(); // d.Test.CollectAuto = false; // // // gen 1 // d.Set(1, "one"); // Assert.AreEqual(1, d.Test.GetValues(1).Length); // // Assert.AreEqual(1, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // using (d.GetScopedWriteLock(GetScopeProvider())) // { // var s1 = d.CreateSnapshot(); // // Assert.AreEqual(0, s1.Gen); // Assert.AreEqual(1, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // Assert.IsNull(s1.Get(1)); // } // // var s2 = d.CreateSnapshot(); // // Assert.AreEqual(1, s2.Gen); // Assert.AreEqual(1, d.Test.LiveGen); // Assert.IsFalse(d.Test.NextGen); // Assert.AreEqual("one", s2.Get(1)); // } // // [Test] // public void WriteLocking() // { // var d = new SnapDictionary(); // d.Test.CollectAuto = false; // // // gen 1 // d.Set(1, "one"); // Assert.AreEqual(1, d.Test.GetValues(1).Length); // // Assert.AreEqual(1, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // var s1 = d.CreateSnapshot(); // // Assert.AreEqual(1, s1.Gen); // Assert.AreEqual(1, d.Test.LiveGen); // Assert.IsFalse(d.Test.NextGen); // Assert.AreEqual("one", s1.Get(1)); // // // gen 2 // Assert.AreEqual(1, d.Test.GetValues(1).Length); // d.Set(1, "uno"); // Assert.AreEqual(2, d.Test.GetValues(1).Length); // // Assert.AreEqual(2, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // var s2 = d.CreateSnapshot(); // // Assert.AreEqual(2, s2.Gen); // Assert.AreEqual(2, d.Test.LiveGen); // Assert.IsFalse(d.Test.NextGen); // Assert.AreEqual("uno", s2.Get(1)); // // using (d.GetScopedWriteLock(GetScopeProvider())) // { // // gen 3 // Assert.AreEqual(2, d.Test.GetValues(1).Length); // d.SetLocked(1, "ein"); // Assert.AreEqual(3, d.Test.GetValues(1).Length); // // Assert.AreEqual(3, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // var s3 = d.CreateSnapshot(); // // Assert.AreEqual(2, s3.Gen); // Assert.AreEqual(3, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // has NOT changed when (non) creating snapshot // Assert.AreEqual("uno", s3.Get(1)); // } // // var s4 = d.CreateSnapshot(); // // Assert.AreEqual(3, s4.Gen); // Assert.AreEqual(3, d.Test.LiveGen); // Assert.IsFalse(d.Test.NextGen); // Assert.AreEqual("ein", s4.Get(1)); // } // // [Test] // public void NestedWriteLocking1() // { // var d = new SnapDictionary(); // var t = d.Test; // t.CollectAuto = false; // // Assert.AreEqual(0, d.CreateSnapshot().Gen); // // // no scope context: writers nest, last one to be disposed commits // var scopeProvider = GetScopeProvider(); // // using (var w1 = d.GetScopedWriteLock(scopeProvider)) // { // Assert.AreEqual(1, t.LiveGen); // Assert.IsTrue(t.IsLocked); // Assert.IsTrue(t.NextGen); // // Assert.Throws(() => // { // using (var w2 = d.GetScopedWriteLock(scopeProvider)) // { // } // }); // // Assert.AreEqual(1, t.LiveGen); // Assert.IsTrue(t.IsLocked); // Assert.IsTrue(t.NextGen); // // Assert.AreEqual(0, d.CreateSnapshot().Gen); // } // // Assert.AreEqual(1, t.LiveGen); // Assert.IsFalse(t.IsLocked); // Assert.IsTrue(t.NextGen); // // Assert.AreEqual(1, d.CreateSnapshot().Gen); // } // // [Test] // public void NestedWriteLocking2() // { // var d = new SnapDictionary(); // d.Test.CollectAuto = false; // // Assert.AreEqual(0, d.CreateSnapshot().Gen); // // // scope context: writers enlist // var scopeContext = new ScopeContext(); // var scopeProvider = GetScopeProvider(scopeContext); // // using (var w1 = d.GetScopedWriteLock(scopeProvider)) // { // // This one is interesting, although we don't allow recursive locks, since this is // // using the same ScopeContext/key, the lock acquisition is only done once. // using (var w2 = d.GetScopedWriteLock(scopeProvider)) // { // Assert.AreSame(w1, w2); // // d.SetLocked(1, "one"); // } // } // } // // [Test] // public void NestedWriteLocking3() // { // var d = new SnapDictionary(); // var t = d.Test; // t.CollectAuto = false; // // Assert.AreEqual(0, d.CreateSnapshot().Gen); // // var scopeContext = new ScopeContext(); // var scopeProvider1 = GetScopeProvider(); // var scopeProvider2 = GetScopeProvider(scopeContext); // // using (var w1 = d.GetScopedWriteLock(scopeProvider1)) // { // Assert.AreEqual(1, t.LiveGen); // Assert.IsTrue(t.IsLocked); // Assert.IsTrue(t.NextGen); // // Assert.Throws(() => // { // using (var w2 = d.GetScopedWriteLock(scopeProvider2)) // { // } // }); // } // } // // [Test] // public void WriteLocking2() // { // var d = new SnapDictionary(); // d.Test.CollectAuto = false; // // // gen 1 // d.Set(1, "one"); // Assert.AreEqual(1, d.Test.GetValues(1).Length); // // Assert.AreEqual(1, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // var s1 = d.CreateSnapshot(); // // Assert.AreEqual(1, s1.Gen); // Assert.AreEqual(1, d.Test.LiveGen); // Assert.IsFalse(d.Test.NextGen); // Assert.AreEqual("one", s1.Get(1)); // // // gen 2 // Assert.AreEqual(1, d.Test.GetValues(1).Length); // d.Set(1, "uno"); // Assert.AreEqual(2, d.Test.GetValues(1).Length); // // Assert.AreEqual(2, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // var s2 = d.CreateSnapshot(); // // Assert.AreEqual(2, s2.Gen); // Assert.AreEqual(2, d.Test.LiveGen); // Assert.IsFalse(d.Test.NextGen); // Assert.AreEqual("uno", s2.Get(1)); // // var scopeProvider = GetScopeProvider(); // using (d.GetScopedWriteLock(scopeProvider)) // { // // gen 3 // Assert.AreEqual(2, d.Test.GetValues(1).Length); // d.SetLocked(1, "ein"); // Assert.AreEqual(3, d.Test.GetValues(1).Length); // // Assert.AreEqual(3, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // var s3 = d.CreateSnapshot(); // // Assert.AreEqual(2, s3.Gen); // Assert.AreEqual(3, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // has NOT changed when (non) creating snapshot // Assert.AreEqual("uno", s3.Get(1)); // } // // var s4 = d.CreateSnapshot(); // // Assert.AreEqual(3, s4.Gen); // Assert.AreEqual(3, d.Test.LiveGen); // Assert.IsFalse(d.Test.NextGen); // Assert.AreEqual("ein", s4.Get(1)); // } // // [Test] // public void WriteLocking3() // { // var d = new SnapDictionary(); // d.Test.CollectAuto = false; // // // gen 1 // d.Set(1, "one"); // var s1 = d.CreateSnapshot(); // Assert.AreEqual(1, s1.Gen); // Assert.AreEqual("one", s1.Get(1)); // // d.Set(1, "uno"); // var s2 = d.CreateSnapshot(); // Assert.AreEqual(2, s2.Gen); // Assert.AreEqual("uno", s2.Get(1)); // // var scopeProvider = GetScopeProvider(); // using (d.GetScopedWriteLock(scopeProvider)) // { // // creating a snapshot in a write-lock does NOT return the "current" content // // it uses the previous snapshot, so new snapshot created only on release // d.SetLocked(1, "ein"); // var s3 = d.CreateSnapshot(); // Assert.AreEqual(2, s3.Gen); // Assert.AreEqual("uno", s3.Get(1)); // // // but live snapshot contains changes // var ls = d.Test.LiveSnapshot; // Assert.AreEqual("ein", ls.Get(1)); // Assert.AreEqual(3, ls.Gen); // } // // var s4 = d.CreateSnapshot(); // Assert.AreEqual(3, s4.Gen); // Assert.AreEqual("ein", s4.Get(1)); // } // // [Test] // public void ScopeLocking1() // { // var d = new SnapDictionary(); // d.Test.CollectAuto = false; // // // gen 1 // d.Set(1, "one"); // var s1 = d.CreateSnapshot(); // Assert.AreEqual(1, s1.Gen); // Assert.AreEqual("one", s1.Get(1)); // // d.Set(1, "uno"); // var s2 = d.CreateSnapshot(); // Assert.AreEqual(2, s2.Gen); // Assert.AreEqual("uno", s2.Get(1)); // // var scopeContext = new ScopeContext(); // var scopeProvider = GetScopeProvider(scopeContext); // using (d.GetScopedWriteLock(scopeProvider)) // { // // creating a snapshot in a write-lock does NOT return the "current" content // // it uses the previous snapshot, so new snapshot created only on release // d.SetLocked(1, "ein"); // var s3 = d.CreateSnapshot(); // Assert.AreEqual(2, s3.Gen); // Assert.AreEqual("uno", s3.Get(1)); // // // but live snapshot contains changes // var ls = d.Test.LiveSnapshot; // Assert.AreEqual("ein", ls.Get(1)); // Assert.AreEqual(3, ls.Gen); // } // // var s4 = d.CreateSnapshot(); // Assert.AreEqual(2, s4.Gen); // Assert.AreEqual("uno", s4.Get(1)); // // scopeContext.ScopeExit(true); // // var s5 = d.CreateSnapshot(); // Assert.AreEqual(3, s5.Gen); // Assert.AreEqual("ein", s5.Get(1)); // } // // [Test] // public void ScopeLocking2() // { // var d = new SnapDictionary(); // var t = d.Test; // t.CollectAuto = false; // // // gen 1 // d.Set(1, "one"); // var s1 = d.CreateSnapshot(); // Assert.AreEqual(1, s1.Gen); // Assert.AreEqual("one", s1.Get(1)); // // d.Set(1, "uno"); // var s2 = d.CreateSnapshot(); // Assert.AreEqual(2, s2.Gen); // Assert.AreEqual("uno", s2.Get(1)); // // Assert.AreEqual(2, t.LiveGen); // Assert.IsFalse(t.NextGen); // // var scopeContext = new ScopeContext(); // var scopeProvider = GetScopeProvider(scopeContext); // using (d.GetScopedWriteLock(scopeProvider)) // { // // creating a snapshot in a write-lock does NOT return the "current" content // // it uses the previous snapshot, so new snapshot created only on release // d.SetLocked(1, "ein"); // var s3 = d.CreateSnapshot(); // Assert.AreEqual(2, s3.Gen); // Assert.AreEqual("uno", s3.Get(1)); // // // we made some changes, so a next gen is required // Assert.AreEqual(3, t.LiveGen); // Assert.IsTrue(t.NextGen); // Assert.IsTrue(t.IsLocked); // // // but live snapshot contains changes // var ls = t.LiveSnapshot; // Assert.AreEqual("ein", ls.Get(1)); // Assert.AreEqual(3, ls.Gen); // } // // // nothing is committed until scope exits // Assert.AreEqual(3, t.LiveGen); // Assert.IsTrue(t.NextGen); // Assert.IsTrue(t.IsLocked); // // // no changes until exit // var s4 = d.CreateSnapshot(); // Assert.AreEqual(2, s4.Gen); // Assert.AreEqual("uno", s4.Get(1)); // // scopeContext.ScopeExit(false); // // // now things have changed // Assert.AreEqual(2, t.LiveGen); // Assert.IsFalse(t.NextGen); // Assert.IsFalse(t.IsLocked); // // // no changes since not completed // var s5 = d.CreateSnapshot(); // Assert.AreEqual(2, s5.Gen); // Assert.AreEqual("uno", s5.Get(1)); // } // // [Test] // public void GetAll() // { // var d = new SnapDictionary(); // d.Test.CollectAuto = false; // // Assert.AreEqual(0, d.Test.GetValues(1).Length); // // d.Set(1, "one"); // d.Set(2, "two"); // d.Set(3, "three"); // d.Set(4, "four"); // // var s1 = d.CreateSnapshot(); // var all = s1.GetAll().ToArray(); // Assert.AreEqual(4, all.Length); // Assert.AreEqual("one", all[0]); // Assert.AreEqual("four", all[3]); // // d.Set(1, "uno"); // var s2 = d.CreateSnapshot(); // // all = s1.GetAll().ToArray(); // Assert.AreEqual(4, all.Length); // Assert.AreEqual("one", all[0]); // Assert.AreEqual("four", all[3]); // // all = s2.GetAll().ToArray(); // Assert.AreEqual(4, all.Length); // Assert.AreEqual("uno", all[0]); // Assert.AreEqual("four", all[3]); // } // // [Test] // public void DontPanic() // { // var d = new SnapDictionary(); // d.Test.CollectAuto = false; // // Assert.IsNull(d.Test.GenObj); // // // gen 1 // d.Set(1, "one"); // Assert.IsTrue(d.Test.NextGen); // Assert.AreEqual(1, d.Test.LiveGen); // Assert.IsNull(d.Test.GenObj); // // var s1 = d.CreateSnapshot(); // Assert.IsFalse(d.Test.NextGen); // Assert.AreEqual(1, d.Test.LiveGen); // Assert.IsNotNull(d.Test.GenObj); // Assert.AreEqual(1, d.Test.GenObj.Gen); // // Assert.AreEqual(1, s1.Gen); // Assert.AreEqual("one", s1.Get(1)); // // d.Set(1, "uno"); // Assert.IsTrue(d.Test.NextGen); // Assert.AreEqual(2, d.Test.LiveGen); // Assert.IsNotNull(d.Test.GenObj); // Assert.AreEqual(1, d.Test.GenObj.Gen); // // var scopeContext = new ScopeContext(); // var scopeProvider = GetScopeProvider(scopeContext); // // // scopeProvider.Context == scopeContext -> writer is scoped // // writer is scope contextual and scoped // // when disposed, nothing happens // // when the context exists, the writer is released // using (d.GetScopedWriteLock(scopeProvider)) // { // d.SetLocked(1, "ein"); // Assert.IsTrue(d.Test.NextGen); // Assert.AreEqual(3, d.Test.LiveGen); // Assert.IsNotNull(d.Test.GenObj); // Assert.AreEqual(2, d.Test.GenObj.Gen); // } // // // writer has not released // Assert.IsTrue(d.Test.IsLocked); // Assert.IsNotNull(d.Test.GenObj); // Assert.AreEqual(2, d.Test.GenObj.Gen); // // // nothing changed // Assert.IsTrue(d.Test.NextGen); // Assert.AreEqual(3, d.Test.LiveGen); // // // panic! // var s2 = d.CreateSnapshot(); // // Assert.IsTrue(d.Test.IsLocked); // Assert.IsNotNull(d.Test.GenObj); // Assert.AreEqual(2, d.Test.GenObj.Gen); // Assert.AreEqual(3, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // // release writer // scopeContext.ScopeExit(true); // // Assert.IsFalse(d.Test.IsLocked); // Assert.IsNotNull(d.Test.GenObj); // Assert.AreEqual(2, d.Test.GenObj.Gen); // Assert.AreEqual(3, d.Test.LiveGen); // Assert.IsTrue(d.Test.NextGen); // // var s3 = d.CreateSnapshot(); // // Assert.IsFalse(d.Test.IsLocked); // Assert.IsNotNull(d.Test.GenObj); // Assert.AreEqual(3, d.Test.GenObj.Gen); // Assert.AreEqual(3, d.Test.LiveGen); // Assert.IsFalse(d.Test.NextGen); // } // // private ICoreScopeProvider GetScopeProvider(ScopeContext scopeContext = null) // { // var scopeProvider = Mock.Of(); // Mock.Get(scopeProvider) // .Setup(x => x.Context).Returns(scopeContext); // return scopeProvider; // } // } // // /// // /// Used for tests so that we don't have to wrap every Set/Clear call in locks // /// // public static class SnapDictionaryExtensions // { // internal static void Set(this SnapDictionary d, TKey key, TValue value) // where TValue : class // { // using (d.GetScopedWriteLock(GetScopeProvider())) // { // d.SetLocked(key, value); // } // } // // internal static void Clear(this SnapDictionary d) // where TValue : class // { // using (d.GetScopedWriteLock(GetScopeProvider())) // { // d.ClearLocked(); // } // } // // internal static void Clear(this SnapDictionary d, TKey key) // where TValue : class // { // using (d.GetScopedWriteLock(GetScopeProvider())) // { // d.ClearLocked(key); // } // } // // private static ICoreScopeProvider GetScopeProvider() // { // var scopeProvider = Mock.Of(); // Mock.Get(scopeProvider) // .Setup(x => x.Context).Returns(() => null); // return scopeProvider; // } // }