public void TestEmptyListOperations() { RWList <int> a = new RWList <int>(); RWList <int> b = new RWList <int>(); a.AddRange(b); a.InsertRange(0, b); a.RemoveRange(0, 0); Assert.That(!a.Remove(0)); Assert.That(a.IsEmpty); Assert.That(a.WithoutLast(0).IsEmpty); a.Add(1); Assert.That(a.WithoutLast(1).IsEmpty); b.AddRange(a); ExpectList(b, 1); b.RemoveAt(0); Assert.That(b.IsEmpty); b.InsertRange(0, a); ExpectList(b, 1); b.RemoveRange(0, 1); Assert.That(b.IsEmpty); b.Insert(0, a[0]); ExpectList(b, 1); b.Remove(a.Last); Assert.That(b.IsEmpty); }
public void TestMutabilification() { // Make a single block mutable RVList <int> v = new RVList <int>(1, 0); RWList <int> w = v.ToRWList(); ExpectList(w, 1, 0); w[1] = 2; ExpectList(w, 1, 2); ExpectList(v, 1, 0); // Make another block, make the front block mutable, then the block-of-2 v.Push(-1); w = v.ToRWList(); w[2] = 3; ExpectList(w, 1, 0, 3); Assert.That(w.WithoutLast(1) == v.WithoutLast(1)); w[1] = 2; ExpectList(w, 1, 2, 3); Assert.That(w.WithoutLast(1) != v.WithoutLast(1)); // Now for a more complicated case: create a long immutable chain by // using a nasty access pattern, add a mutable block in front, then // make some of the immutable blocks mutable. This will cause several // immutable blocks to be consolidated into one mutable block, // shortening the chain. v = new RVList <int>(6); v = v.Add(-1).Tail.Add(5).Add(-1).Tail.Add(4).Add(-1).Tail.Add(3); v = v.Add(-1).Tail.Add(2).Add(-1).Tail.Add(1).Add(-1).Tail.Add(0); ExpectList(v, 6, 5, 4, 3, 2, 1, 0); // At this point, every block in the chain has only one item (it's // a linked list!) and the capacity of each block is 2. Assert.AreEqual(7, v.BlockChainLength); w = v.ToRWList(); w.AddRange(new int[] { 1, 2, 3, 4, 5 }); Assert.AreEqual(w.Count, 12); ExpectList(w, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5); // Indices: 0 1 2 3 4 5 6 7 8 9 10 11 // Blocks: H| G| F| E| D| C| B | block A (front of chain) Assert.AreEqual(8, w.BlockChainLength); Assert.AreEqual(4, w.LocalCount); w[3] = -3; ExpectList(w, 6, 5, 4, -3, 2, 1, 0, 1, 2, 3, 4, 5); // Indices: 0 1 2 3 4 5 6 7 8 9 10 11 // Blocks: H| G| F| block I | block A (front of chain) Assert.AreEqual(5, w.BlockChainLength); }
public void TestInsertRemove() { RWList <int> list = new RWList <int>(); for (int i = 0; i <= 12; i++) { list.Insert(0, i); } ExpectList(list, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); for (int i = 1; i <= 6; i++) { list.RemoveAt(i); } ExpectList(list, 12, 10, 8, 6, 4, 2, 0); Assert.AreEqual(0, list.Pop()); list.Insert(1, -2); ExpectList(list, 12, -2, 10, 8, 6, 4, 2); list.Insert(2, -1); ExpectList(list, 12, -2, -1, 10, 8, 6, 4, 2); Assert.That(list.Remove(-1)); Assert.That(list.Remove(12)); list[0] = 12; ExpectList(list, 12, 10, 8, 6, 4, 2); // Make sure RWList.Clear doesn't disturb FVList RVList <int> v = list.WithoutLast(4); list.Clear(); ExpectList(list); ExpectList(v, 12, 10); // Some simple InsertRange calls where some immutable items must be // converted to mutable RVList <int> oneTwo = new RVList <int>(1, 2); RVList <int> threeFour = new RVList <int>(3, 4); list = oneTwo.ToRWList(); list.InsertRange(1, threeFour); ExpectList(list, 1, 3, 4, 2); list = threeFour.ToRWList(); list.InsertRange(0, oneTwo); ExpectList(list, 1, 2, 3, 4); // More tests... list.RemoveRange(2, 2); ExpectList(list, 1, 2); list.InsertRange(2, new int[] { 3, 3, 4, 4, 4, 5, 6, 7, 8, 9 }); ExpectList(list, 1, 2, 3, 3, 4, 4, 4, 5, 6, 7, 8, 9); list.RemoveRange(3, 3); ExpectList(list, 1, 2, 3, 4, 5, 6, 7, 8, 9); v = list.ToRVList(); list.RemoveRange(5, 4); ExpectList(list, 1, 2, 3, 4, 5); ExpectList(v, 1, 2, 3, 4, 5, 6, 7, 8, 9); }
public void TestWhere() { RWList <int> one = new RWList <int>(); one.Add(3); RWList <int> two = one.Clone(); two.Add(2); RWList <int> thr = two.Clone(); thr.Add(1); ExpectList(one.Where(delegate(int i) { return(false); })); ExpectList(two.Where(delegate(int i) { return(false); })); ExpectList(thr.Where(delegate(int i) { return(false); })); Assert.That(one.Where(delegate(int i) { return(true); }).ToRVList() == one.ToRVList()); Assert.That(two.Where(delegate(int i) { return(true); }).ToRVList() == two.ToRVList()); Assert.That(thr.Where(delegate(int i) { return(true); }).ToRVList() == thr.ToRVList()); Assert.That(two.Where(delegate(int i) { return(i == 3); }).ToRVList() == two.WithoutLast(1)); Assert.That(thr.Where(delegate(int i) { return(i == 3); }).ToRVList() == thr.WithoutLast(2)); Assert.That(thr.Where(delegate(int i) { return(i > 1); }).ToRVList() == thr.WithoutLast(1)); ExpectList(two.Where(delegate(int i) { return(i == 2); }), 2); ExpectList(thr.Where(delegate(int i) { return(i == 2); }), 2); }
public void TestFork() { RWList <int> A = new RWList <int>(); A.AddRange(new int[] { 1, 2, 3 }); RWList <int> B = A.Clone(); A.Push(4); ExpectList(B, 1, 2, 3); ExpectList(A, 1, 2, 3, 4); B.Push(-4); ExpectList(B, 1, 2, 3, -4); Assert.That(A.WithoutLast(2) == B.WithoutLast(2)); }
private void TestTransform(int count, int[] expect, int commonTailLength, params XfAction[] actions) { RWList <int> list = new RWList <int>(); for (int i = 0; i < count; i++) { list.Add(i + 1); } int counter = 0; RWList <int> result = list.Transform(delegate(int i, ref int item) { if (i >= 0) { Assert.AreEqual(list[i], item); } item *= 10; return(actions[counter++]); }); Assert.AreEqual(counter, actions.Length); ExpectList(result, expect); Assert.That(result.WithoutLast(result.Count - commonTailLength) == list.WithoutLast(list.Count - commonTailLength)); // Try to ensure there's no shared mutable memory by trashing the // result starting at the head, and verifying the original list for (int i = result.Count - 1; i >= 0; i--) { result[i] = -1; } Assert.AreEqual(count, list.Count); for (int i = 0; i < count; i++) { Assert.AreEqual(i + 1, list[i]); } }
public void TestSelect() { RWList <int> one = new RWList <int>(); one.Add(3); RWList <int> two = one.Clone(); two.Add(2); RWList <int> thr = two.Clone(); thr.Add(1); ExpectList(thr, 3, 2, 1); ExpectList(one.Select(delegate(int i) { return(i + 1); }), 4); ExpectList(two.Select(delegate(int i) { return(i + 1); }), 4, 3); ExpectList(thr.Select(delegate(int i) { return(i + 1); }), 4, 3, 2); ExpectList(two.Select(delegate(int i) { return(i == 3 ? 3 : 0); }), 3, 0); ExpectList(thr.Select(delegate(int i) { return(i == 3 ? 3 : 0); }), 3, 0, 0); ExpectList(thr.Select(delegate(int i) { return(i == 1 ? 0 : i); }), 3, 2, 0); Assert.That(one.SmartSelect(delegate(int i) { return(i); }).ToRVList() == one.ToRVList()); Assert.That(two.SmartSelect(delegate(int i) { return(i); }).ToRVList() == two.ToRVList()); Assert.That(thr.SmartSelect(delegate(int i) { return(i); }).ToRVList() == thr.ToRVList()); ExpectList(one.SmartSelect(delegate(int i) { return(i + 1); }), 4); ExpectList(two.SmartSelect(delegate(int i) { return(i + 1); }), 4, 3); ExpectList(thr.SmartSelect(delegate(int i) { return(i + 1); }), 4, 3, 2); ExpectList(two.SmartSelect(delegate(int i) { return(i == 3 ? 3 : 0); }), 3, 0); ExpectList(thr.SmartSelect(delegate(int i) { return(i == 3 ? 3 : 0); }), 3, 0, 0); ExpectList(thr.SmartSelect(delegate(int i) { return(i == 1 ? 0 : i); }), 3, 2, 0); Assert.That(thr.SmartSelect(delegate(int i) { return(i == 1 ? 0 : i); }).WithoutLast(1) == thr.WithoutLast(1)); }
public void TestFalseOwnership() { // This test tries to make sure a RWList doesn't get confused about what // blocks it owns. It's possible for a RWList to share a partially-mutable // block that contains mutable items with another RWList, but only one // RWList owns the items. // Case 1: two WLists point to the same block but only one owns it: // // block 0 // owned by A // |____3| block 1 // |____2| unowned // A,B--->|Imm_1|--->|Imm_1| // |____0| |____0| // // (The location of "Imm" in each block denotes the highest immutable // item; this diagram shows there are two immutable items in each // block) RWList <int> A = new RWList <int>(); A.Resize(4); for (int i = 0; i < 4; i++) { A[i] = i; } RWList <int> B = A.Clone(); // B can't add to the second block because it's not the owner, so a // third block is created when we Add(1). B.Add(4); A.Add(-4); ExpectList(A, 0, 1, 2, 3, -4); ExpectList(B, 0, 1, 2, 3, 4); Assert.AreEqual(2, A.BlockChainLength); Assert.AreEqual(3, B.BlockChainLength); // Case 2: two WLists point to different blocks but they share a common // tail, where one list owns part of the tail and the other does not: // // block 0 // owned by B // |____8| // |____7| // |____6| // |____5| block 1 // |____4| owned by A // |____3| A |____3| block 2 // |____2| | |____2| unowned // |____1|---+---->|Imm_1|---->|Imm_1| // B--->|____0| |____0| |____0| // mutable // // Actually the previous test puts us in just this state. // // I can't think of a test that uses the public interface to detect bugs // in this case. The most important thing is that B._block.PriorIsOwned // returns false. Assert.That(B.IsOwner && !B.Block.PriorIsOwned); Assert.That(A.IsOwner); Assert.That(B.Block.Prior.ToRVList() == A.WithoutLast(1)); }