using System; using System.Collections.Generic; using System.Linq; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Renci.SshNet.Tests.Classes { [TestClass] public class OrderedDictionaryTest { private static void AssertEqual(List> expected, OrderedDictionary o) { Assert.AreEqual(expected.Count, o.Count); CollectionAssert.AreEqual(expected, ToList(o)); // Test the enumerator for (int i = 0; i < expected.Count; i++) { Assert.AreEqual(expected[i], o.GetAt(i)); Assert.AreEqual(expected[i].Value, o[expected[i].Key]); Assert.IsTrue(o.TryGetValue(expected[i].Key, out TValue value)); Assert.AreEqual(expected[i].Value, value); Assert.IsTrue(o.TryGetValue(expected[i].Key, out value, out int index)); Assert.AreEqual(expected[i].Value, value); Assert.AreEqual(i, index); Assert.IsTrue(((ICollection>)o).Contains(expected[i])); Assert.IsTrue(o.ContainsKey(expected[i].Key)); Assert.IsTrue(o.ContainsValue(expected[i].Value)); Assert.IsTrue(o.Keys.Contains(expected[i].Key)); Assert.IsTrue(o.Values.Contains(expected[i].Value)); Assert.AreEqual(i, o.IndexOf(expected[i].Key)); Assert.IsFalse(o.TryAdd(expected[i].Key, default)); Assert.IsFalse(o.TryAdd(expected[i].Key, default, out index)); Assert.AreEqual(i, index); } Assert.AreEqual(expected.Count, o.Keys.Count); CollectionAssert.AreEqual(expected.Select(kvp => kvp.Key).ToList(), ToList(o.Keys)); CollectionAssert.AreEqual(ToList(o.Keys), ToList(((IReadOnlyDictionary)o).Keys)); Assert.AreEqual(expected.Count, o.Values.Count); CollectionAssert.AreEqual(expected.Select(kvp => kvp.Value).ToList(), ToList(o.Values)); CollectionAssert.AreEqual(ToList(o.Values), ToList(((IReadOnlyDictionary)o).Values)); // Test CopyTo var kvpArray = new KeyValuePair[1 + expected.Count + 1]; ((ICollection>)o).CopyTo(kvpArray, 1); CollectionAssert.AreEqual( (List>)[default, .. expected, default], kvpArray); var keysArray = new TKey[1 + expected.Count + 1]; o.Keys.CopyTo(keysArray, 1); CollectionAssert.AreEqual( (List)[default, .. expected.Select(kvp => kvp.Key), default], keysArray); var valuesArray = new TValue[1 + expected.Count + 1]; o.Values.CopyTo(valuesArray, 1); CollectionAssert.AreEqual( (List)[default, .. expected.Select(kvp => kvp.Value), default], valuesArray); // Creates a List via enumeration, avoiding the ICollection.CopyTo // optimisation in the List constructor. static List ToList(IEnumerable values) { List list = new(); foreach (T t in values) { list.Add(t); } return list; } } [TestMethod] public void NullKey_ThrowsArgumentNull() { OrderedDictionary o = new() { { "a", 4 } }; Assert.ThrowsException(() => o[null]); Assert.ThrowsException(() => o.Add(null, 1)); Assert.ThrowsException(() => ((ICollection>)o).Add(new KeyValuePair(null, 1))); Assert.ThrowsException(() => ((ICollection>)o).Contains(new KeyValuePair(null, 1))); Assert.ThrowsException(() => o.ContainsKey(null)); Assert.ThrowsException(() => o.IndexOf(null)); Assert.ThrowsException(() => o.Insert(0, null, 1)); Assert.ThrowsException(() => o.Remove(null, out _)); Assert.ThrowsException(() => o.Remove(null)); Assert.ThrowsException(() => ((ICollection>)o).Remove(new KeyValuePair(null, 1))); Assert.ThrowsException(() => o.SetAt(0, null, 1)); Assert.ThrowsException(() => o.SetPosition(null, 0)); Assert.ThrowsException(() => o.TryAdd(null, 1)); Assert.ThrowsException(() => o.TryAdd(null, 1, out _)); Assert.ThrowsException(() => o.TryGetValue(null, out _)); Assert.ThrowsException(() => o.TryGetValue(null, out _, out _)); } [TestMethod] public void Indexer_Match_GetterReturnsValue() { OrderedDictionary o = new() { { "a", 4 }, { "b", 8 } }; Assert.AreEqual(8, o["b"]); } [TestMethod] public void Indexer_Match_SetterChangesValue() { OrderedDictionary o = new() { { "a", 4 }, { "b", 8 } }; o["a"] = 5; AssertEqual([new("a", 5), new("b", 8)], o); } [TestMethod] public void Indexer_NoMatch_GetterThrowsKeyNotFound() { OrderedDictionary o = new() { { "a", 4 } }; Assert.ThrowsException(() => o["b"]); } [TestMethod] public void Indexer_NoMatch_SetterAddsItem() { OrderedDictionary o = new() { { "a", 4 } }; o["b"] = 8; AssertEqual([new("a", 4), new("b", 8)], o); } [TestMethod] public void Add_Match() { OrderedDictionary o = new() { { "a", 4 } }; Assert.ThrowsException(() => o.Add("a", 8)); Assert.ThrowsException(() => ((ICollection>)o).Add(new KeyValuePair("a", 8))); } [TestMethod] public void Clear() { OrderedDictionary o = new() { { "a", 4 }, { "b", 8 } }; AssertEqual([new("a", 4), new("b", 8)], o); o.Clear(); AssertEqual([], o); } [TestMethod] public void CopyTo() { OrderedDictionary o = new() { { "a", 4 }, { "b", 8 } }; Assert.ThrowsException(() => ((ICollection>)o).CopyTo(null, 0)); Assert.ThrowsException(() => ((ICollection>)o).CopyTo(new KeyValuePair[3], -1)); Assert.ThrowsException(() => ((ICollection>)o).CopyTo(new KeyValuePair[3], 3)); Assert.ThrowsException(() => ((ICollection>)o).CopyTo(new KeyValuePair[3], 2)); Assert.ThrowsException(() => o.Keys.CopyTo(null, 0)); Assert.ThrowsException(() => o.Keys.CopyTo(new string[3], -1)); Assert.ThrowsException(() => o.Keys.CopyTo(new string[3], 3)); Assert.ThrowsException(() => o.Keys.CopyTo(new string[3], 2)); Assert.ThrowsException(() => o.Values.CopyTo(null, 0)); Assert.ThrowsException(() => o.Values.CopyTo(new int[3], -1)); Assert.ThrowsException(() => o.Values.CopyTo(new int[3], 3)); Assert.ThrowsException(() => o.Values.CopyTo(new int[3], 2)); } [TestMethod] public void ContainsKvp_ChecksKeyAndValue() { OrderedDictionary o = new() { { "a", 4 } }; Assert.IsFalse(((ICollection>)o).Contains(new KeyValuePair("a", 8))); Assert.IsTrue(((ICollection>)o).Contains(new KeyValuePair("a", 4))); } [TestMethod] public void NullValues_Permitted() { OrderedDictionary o = new() { { "a", "1" } }; Assert.IsFalse(o.ContainsValue(null)); o.Add("b", null); AssertEqual([new("a", "1"), new("b", null)], o); } [TestMethod] public void GetAt_OutOfRange() { OrderedDictionary o = new() { { "a", "1" } }; Assert.ThrowsException(() => o.GetAt(-2)); Assert.ThrowsException(() => o.GetAt(-1)); Assert.ThrowsException(() => o.GetAt(1)); } [TestMethod] public void RemoveKvp_ChecksKeyAndValue() { OrderedDictionary o = new() { { "a", 4 } }; Assert.IsFalse(((ICollection>)o).Remove(new KeyValuePair("a", 8))); AssertEqual([new("a", 4)], o); Assert.IsTrue(((ICollection>)o).Remove(new KeyValuePair("a", 4))); AssertEqual([], o); } [TestMethod] public void SetAt() { OrderedDictionary o = new(); Assert.ThrowsException(() => o.SetAt(-2, 1.1)); Assert.ThrowsException(() => o.SetAt(-1, 1.1)); Assert.ThrowsException(() => o.SetAt(0, 1.1)); Assert.ThrowsException(() => o.SetAt(1, 1.1)); o.Add("a", 4); Assert.ThrowsException(() => o.SetAt(-2, 1.1)); Assert.ThrowsException(() => o.SetAt(-1, 1.1)); o.SetAt(0, 1.1); AssertEqual([new("a", 1.1)], o); Assert.ThrowsException(() => o.SetAt(1, 5.5)); } [TestMethod] public void SetAt3Params_OutOfRange() { OrderedDictionary o = new() { { "a", 4 }, { "b", 8 }, { "c", 12 } }; Assert.ThrowsException(() => o.SetAt(-1, "d", 16)); Assert.ThrowsException(() => o.SetAt(3, "d", 16)); } [TestMethod] public void SetAt3Params_ExistingKeyCorrectIndex_PermitsChangingValue() { OrderedDictionary o = new() { { "a", 4 }, { "b", 8 }, { "c", 12 } }; o.SetAt(2, "c", 16); AssertEqual([new("a", 4), new("b", 8), new("c", 16)], o); } [TestMethod] public void SetAt3Params_ExistingKeyDifferentIndex_Throws() { OrderedDictionary o = new() { { "a", 4 }, { "b", 8 }, { "c", 12 } }; Assert.ThrowsException(() => o.SetAt(1, "c", 16)); } [TestMethod] public void SetAt3Params_PermitsChangingToNewKey() { OrderedDictionary o = new() { { "a", 4 }, { "b", 8 }, { "c", 12 } }; o.SetAt(1, "d", 16); AssertEqual([new("a", 4), new("d", 16), new("c", 12)], o); } [TestMethod] public void Get_NonExistent() { OrderedDictionary o = new() { { "a", 4 } }; Assert.ThrowsException(() => o["doesn't exist"]); Assert.IsFalse(((ICollection>)o).Contains(new KeyValuePair("doesn't exist", 1))); Assert.IsFalse(o.ContainsKey("doesn't exist")); Assert.IsFalse(o.ContainsValue(999)); Assert.AreEqual(-1, o.IndexOf("doesn't exist")); Assert.IsFalse(o.Remove("doesn't exist", out float value)); Assert.AreEqual(default, value); Assert.IsFalse(o.Remove("doesn't exist")); Assert.IsFalse(((ICollection>)o).Remove(new KeyValuePair("doesn't exist", 1))); Assert.IsFalse(o.TryGetValue("doesn't exist", out value)); Assert.AreEqual(default, value); Assert.IsFalse(o.TryGetValue("doesn't exist", out value, out int index)); Assert.AreEqual(default, value); Assert.AreEqual(-1, index); AssertEqual([new("a", 4)], o); } [TestMethod] public void Insert() { OrderedDictionary o = new() { { "a", 4 }, { "b", 8 } }; Assert.ThrowsException(() => o.Insert(-1, "c", 12)); o.Insert(0, "c", 12); // Start AssertEqual([new("c", 12), new("a", 4), new("b", 8)], o); o.Insert(2, "d", 12); // Middle AssertEqual([new("c", 12), new("a", 4), new("d", 12), new("b", 8)], o); o.Insert(o.Count, "e", 16); // End AssertEqual([new("c", 12), new("a", 4), new("d", 12), new("b", 8), new("e", 16)], o); Assert.ThrowsException(() => o.Insert(o.Count + 1, "f", 16)); // Existing key Assert.ThrowsException(() => o.Insert(0, "a", 12)); } [TestMethod] public void Remove_Success() { OrderedDictionary o = new() { { "a", 4 }, { "b", 8 }, { "c", 12 } }; Assert.IsTrue(o.Remove("b")); AssertEqual([new("a", 4), new("c", 12)], o); Assert.IsTrue(o.Remove("a", out float value)); Assert.AreEqual(4, value); AssertEqual([new("c", 12)], o); // ICollection.Remove must match Key and Value Assert.IsFalse(((ICollection>)o).Remove(new KeyValuePair("c", -1))); AssertEqual([new("c", 12)], o); Assert.IsTrue(((ICollection>)o).Remove(new KeyValuePair("c", 12))); AssertEqual([], o); } [TestMethod] public void RemoveAt() { OrderedDictionary o = new() { { "a", 4 }, { "b", 8 }, { "c", 12 }, { "d", 16 } }; Assert.ThrowsException(() => o.RemoveAt(-2)); Assert.ThrowsException(() => o.RemoveAt(-1)); o.RemoveAt(0); // Start AssertEqual([new("b", 8), new("c", 12), new("d", 16)], o); o.RemoveAt(1); // Middle AssertEqual([new("b", 8), new("d", 16)], o); o.RemoveAt(1); // End AssertEqual([new("b", 8)], o); Assert.ThrowsException(() => o.RemoveAt(1)); } [TestMethod] public void SetPosition_ByIndex() { OrderedDictionary o = new() { { "a", 4 }, { "b", 8 }, { "c", 12 }, { "d", 16 } }; ArgumentOutOfRangeException ex; ex = Assert.ThrowsException(() => o.SetPosition(-1, 0)); Assert.AreEqual("index", ex.ParamName); ex = Assert.ThrowsException(() => o.SetPosition(0, -1)); Assert.AreEqual("newIndex", ex.ParamName); ex = Assert.ThrowsException(() => o.SetPosition(0, 4)); Assert.AreEqual("newIndex", ex.ParamName); ex = Assert.ThrowsException(() => o.SetPosition(4, 0)); Assert.AreEqual("index", ex.ParamName); o.SetPosition(1, 0); AssertEqual([new("b", 8), new("a", 4), new("c", 12), new("d", 16)], o); o.SetPosition(0, 1); AssertEqual([new("a", 4), new("b", 8), new("c", 12), new("d", 16)], o); o.SetPosition(1, 2); AssertEqual([new("a", 4), new("c", 12), new("b", 8), new("d", 16)], o); o.SetPosition(2, 1); AssertEqual([new("a", 4), new("b", 8), new("c", 12), new("d", 16)], o); o.SetPosition(0, 3); AssertEqual([new("b", 8), new("c", 12), new("d", 16), new("a", 4)], o); o.SetPosition(3, 1); AssertEqual([new("b", 8), new("a", 4), new("c", 12), new("d", 16)], o); o.SetPosition(1, 1); // No-op AssertEqual([new("b", 8), new("a", 4), new("c", 12), new("d", 16)], o); } [TestMethod] public void SetPosition_ByKey() { OrderedDictionary o = new() { { "a", 4 }, { "b", 8 }, { "c", 12 }, { "d", 16 } }; Assert.ThrowsException(() => o.SetPosition("a", -1)); Assert.ThrowsException(() => o.SetPosition("a", 4)); Assert.ThrowsException(() => o.SetPosition("e", 0)); o.SetPosition("b", 0); AssertEqual([new("b", 8), new("a", 4), new("c", 12), new("d", 16)], o); o.SetPosition("b", 1); AssertEqual([new("a", 4), new("b", 8), new("c", 12), new("d", 16)], o); o.SetPosition("a", 3); AssertEqual([new("b", 8), new("c", 12), new("d", 16), new("a", 4)], o); o.SetPosition("d", 2); // No-op AssertEqual([new("b", 8), new("c", 12), new("d", 16), new("a", 4)], o); } [TestMethod] public void TryAdd_Success() { OrderedDictionary o = new() { { "a", 4 }, { "b", 8 } }; Assert.IsTrue(o.TryAdd("c", 12)); AssertEqual([new("a", 4), new("b", 8), new("c", 12)], o); Assert.IsTrue(o.TryAdd("d", 16, out int index)); Assert.AreEqual(3, index); AssertEqual([new("a", 4), new("b", 8), new("c", 12), new("d", 16)], o); } [TestMethod] public void KeysAndValuesAreReadOnly() { OrderedDictionary o = new() { { "a", 4 }, { "b", 8 } }; Assert.IsTrue(o.Keys.IsReadOnly); Assert.ThrowsException(() => o.Keys.Add("c")); Assert.ThrowsException(o.Keys.Clear); Assert.ThrowsException(() => o.Keys.Remove("a")); Assert.IsTrue(o.Values.IsReadOnly); Assert.ThrowsException(() => o.Values.Add(12)); Assert.ThrowsException(o.Values.Clear); Assert.ThrowsException(() => o.Values.Remove(4)); } } }