mirror of
https://github.com/chylex/TweetDuck.git
synced 2025-05-09 14:34:05 +02:00
Add a TwoKeyDictionary collection with unit tests
This commit is contained in:
parent
7cadb1c403
commit
1e4f673f9e
100
Core/Utils/TwoKeyDictionary.cs
Normal file
100
Core/Utils/TwoKeyDictionary.cs
Normal file
@ -0,0 +1,100 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace TweetDck.Core.Utils{
|
||||
class TwoKeyDictionary<K1, K2, V>{
|
||||
private readonly Dictionary<K1, Dictionary<K2, V>> dict;
|
||||
private readonly int innerCapacity;
|
||||
|
||||
public TwoKeyDictionary() : this(16, 16){}
|
||||
|
||||
public TwoKeyDictionary(int outerCapacity, int innerCapacity){
|
||||
this.dict = new Dictionary<K1, Dictionary<K2, V>>(outerCapacity);
|
||||
this.innerCapacity = innerCapacity;
|
||||
}
|
||||
|
||||
// Properties
|
||||
|
||||
public V this[K1 outerKey, K2 innerKey]{
|
||||
get{ // throws on missing key
|
||||
return dict[outerKey][innerKey];
|
||||
}
|
||||
|
||||
set{
|
||||
Dictionary<K2, V> innerDict;
|
||||
|
||||
if (!dict.TryGetValue(outerKey, out innerDict)){
|
||||
dict.Add(outerKey, innerDict = new Dictionary<K2, V>(innerCapacity));
|
||||
}
|
||||
|
||||
innerDict[innerKey] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// Members
|
||||
|
||||
public void Add(K1 outerKey, K2 innerKey, V value){ // throws on duplicate
|
||||
Dictionary<K2, V> innerDict;
|
||||
|
||||
if (!dict.TryGetValue(outerKey, out innerDict)){
|
||||
dict.Add(outerKey, innerDict = new Dictionary<K2, V>(innerCapacity));
|
||||
}
|
||||
|
||||
innerDict.Add(innerKey, value);
|
||||
}
|
||||
|
||||
public void Clear(){
|
||||
this.dict.Clear();
|
||||
}
|
||||
|
||||
public void Clear(K1 outerKey){ // throws on missing key, but keeps the key unlike Remove(K1)
|
||||
dict[outerKey].Clear();
|
||||
}
|
||||
|
||||
public bool Contains(K1 outerKey){
|
||||
return dict.ContainsKey(outerKey);
|
||||
}
|
||||
|
||||
public bool Contains(K1 outerKey, K2 innerKey){
|
||||
Dictionary<K2, V> innerDict;
|
||||
return dict.TryGetValue(outerKey, out innerDict) && innerDict.ContainsKey(innerKey);
|
||||
}
|
||||
|
||||
public int Count(){
|
||||
return dict.Values.Sum(d => d.Count);
|
||||
}
|
||||
|
||||
public int Count(K1 outerKey){ // throws on missing key
|
||||
return dict[outerKey].Count;
|
||||
}
|
||||
|
||||
public bool Remove(K1 outerKey){
|
||||
return dict.Remove(outerKey);
|
||||
}
|
||||
|
||||
public bool Remove(K1 outerKey, K2 innerKey){
|
||||
Dictionary<K2, V> innerDict;
|
||||
|
||||
if (dict.TryGetValue(outerKey, out innerDict) && innerDict.Remove(innerKey)){
|
||||
if (innerDict.Count == 0){
|
||||
dict.Remove(outerKey);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
public bool TryGetValue(K1 outerKey, K2 innerKey, out V value){
|
||||
Dictionary<K2, V> innerDict;
|
||||
|
||||
if (dict.TryGetValue(outerKey, out innerDict)){
|
||||
return innerDict.TryGetValue(innerKey, out value);
|
||||
}
|
||||
else{
|
||||
value = default(V);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -192,6 +192,7 @@
|
||||
</Compile>
|
||||
<Compile Include="Core\Notification\NotificationFlags.cs" />
|
||||
<Compile Include="Core\Notification\Screenshot\TweetScreenshotManager.cs" />
|
||||
<Compile Include="Core\Utils\TwoKeyDictionary.cs" />
|
||||
<Compile Include="Core\Utils\WindowState.cs" />
|
||||
<Compile Include="Core\Utils\WindowsUtils.cs" />
|
||||
<Compile Include="Core\Bridge\TweetDeckBridge.cs" />
|
||||
|
201
tests/Core/Utils/TestTwoKeyDictionary.cs
Normal file
201
tests/Core/Utils/TestTwoKeyDictionary.cs
Normal file
@ -0,0 +1,201 @@
|
||||
using System;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using TweetDck.Core.Utils;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnitTests.Core.Utils{
|
||||
[TestClass]
|
||||
public class TestTwoKeyDictionary{
|
||||
private static TwoKeyDictionary<string, int, string> CreateDict(){
|
||||
TwoKeyDictionary<string, int, string> dict = new TwoKeyDictionary<string, int, string>();
|
||||
|
||||
dict.Add("aaa", 0, "x");
|
||||
dict.Add("aaa", 1, "y");
|
||||
dict.Add("aaa", 2, "z");
|
||||
|
||||
dict.Add("bbb", 0, "test 1");
|
||||
dict.Add("bbb", 10, "test 2");
|
||||
dict.Add("bbb", 20, "test 3");
|
||||
dict.Add("bbb", 30, "test 4");
|
||||
|
||||
dict.Add("ccc", -5, "");
|
||||
dict.Add("", 0, "");
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestAdd(){
|
||||
CreateDict();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(ArgumentException))]
|
||||
public void TestAddDuplicate(){
|
||||
var dict = new TwoKeyDictionary<string, int, string>();
|
||||
|
||||
dict.Add("aaa", 0, "test");
|
||||
dict.Add("aaa", 0, "oops");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestAccessor(){
|
||||
var dict = CreateDict();
|
||||
|
||||
// get
|
||||
|
||||
Assert.AreEqual("x", dict["aaa", 0]);
|
||||
Assert.AreEqual("y", dict["aaa", 1]);
|
||||
Assert.AreEqual("z", dict["aaa", 2]);
|
||||
|
||||
Assert.AreEqual("test 3", dict["bbb", 20]);
|
||||
|
||||
Assert.AreEqual("", dict["ccc", -5]);
|
||||
Assert.AreEqual("", dict["", 0]);
|
||||
|
||||
// set
|
||||
|
||||
dict["aaa", 0] = "replaced entry";
|
||||
Assert.AreEqual("replaced entry", dict["aaa", 0]);
|
||||
|
||||
dict["aaa", 3] = "new entry";
|
||||
Assert.AreEqual("new entry", dict["aaa", 3]);
|
||||
|
||||
dict["xxxxx", 150] = "new key and entry";
|
||||
Assert.AreEqual("new key and entry", dict["xxxxx", 150]);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(KeyNotFoundException))]
|
||||
public void TestAccessorMissingKey1(){
|
||||
var _ = CreateDict()["missing", 0];
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(KeyNotFoundException))]
|
||||
public void TestAccessorMissingKey2(){
|
||||
var _ = CreateDict()["aaa", 3];
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestClear(){
|
||||
var dict = CreateDict();
|
||||
|
||||
Assert.IsTrue(dict.Contains("bbb"));
|
||||
dict.Clear("bbb");
|
||||
Assert.IsTrue(dict.Contains("bbb"));
|
||||
|
||||
Assert.IsTrue(dict.Contains(""));
|
||||
dict.Clear("");
|
||||
Assert.IsTrue(dict.Contains(""));
|
||||
|
||||
Assert.IsTrue(dict.Contains("aaa"));
|
||||
Assert.IsTrue(dict.Contains("ccc"));
|
||||
dict.Clear();
|
||||
Assert.IsFalse(dict.Contains("aaa"));
|
||||
Assert.IsFalse(dict.Contains("ccc"));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(KeyNotFoundException))]
|
||||
public void TestClearMissingKey(){
|
||||
CreateDict().Clear("missing");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestContains(){
|
||||
var dict = CreateDict();
|
||||
|
||||
// positive
|
||||
|
||||
Assert.IsTrue(dict.Contains("aaa"));
|
||||
Assert.IsTrue(dict.Contains("aaa", 0));
|
||||
Assert.IsTrue(dict.Contains("aaa", 1));
|
||||
Assert.IsTrue(dict.Contains("aaa", 2));
|
||||
|
||||
Assert.IsTrue(dict.Contains("ccc"));
|
||||
Assert.IsTrue(dict.Contains("ccc", -5));
|
||||
|
||||
Assert.IsTrue(dict.Contains(""));
|
||||
Assert.IsTrue(dict.Contains("", 0));
|
||||
|
||||
// negative
|
||||
|
||||
Assert.IsFalse(dict.Contains("missing"));
|
||||
Assert.IsFalse(dict.Contains("missing", 999));
|
||||
|
||||
Assert.IsFalse(dict.Contains("aaa", 3));
|
||||
Assert.IsFalse(dict.Contains("", -1));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestCount(){
|
||||
var dict = CreateDict();
|
||||
|
||||
Assert.AreEqual(9, dict.Count());
|
||||
Assert.AreEqual(3, dict.Count("aaa"));
|
||||
Assert.AreEqual(4, dict.Count("bbb"));
|
||||
Assert.AreEqual(1, dict.Count("ccc"));
|
||||
Assert.AreEqual(1, dict.Count(""));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(KeyNotFoundException))]
|
||||
public void TestCountMissingKey(){
|
||||
CreateDict().Count("missing");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestRemove(){
|
||||
var dict = CreateDict();
|
||||
|
||||
// negative
|
||||
Assert.IsFalse(dict.Remove("missing"));
|
||||
Assert.IsFalse(dict.Remove("aaa", 3));
|
||||
|
||||
// positive
|
||||
|
||||
Assert.IsTrue(dict.Contains("aaa"));
|
||||
Assert.IsTrue(dict.Remove("aaa"));
|
||||
Assert.IsFalse(dict.Contains("aaa"));
|
||||
|
||||
Assert.IsTrue(dict.Contains("bbb", 10));
|
||||
Assert.IsTrue(dict.Remove("bbb", 10));
|
||||
Assert.IsFalse(dict.Contains("bbb", 10));
|
||||
Assert.IsTrue(dict.Contains("bbb"));
|
||||
Assert.IsTrue(dict.Contains("bbb", 20));
|
||||
|
||||
Assert.IsTrue(dict.Remove("bbb", 0));
|
||||
Assert.IsTrue(dict.Remove("bbb", 20));
|
||||
Assert.IsTrue(dict.Remove("bbb", 30));
|
||||
Assert.IsFalse(dict.Contains("bbb"));
|
||||
|
||||
Assert.IsTrue(dict.Contains(""));
|
||||
Assert.IsTrue(dict.Remove("", 0));
|
||||
Assert.IsFalse(dict.Contains(""));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestTryGetValue(){
|
||||
var dict = CreateDict();
|
||||
string val;
|
||||
|
||||
// positive
|
||||
|
||||
Assert.IsTrue(dict.TryGetValue("bbb", 10, out val));
|
||||
Assert.AreEqual("test 2", val);
|
||||
|
||||
Assert.IsTrue(dict.TryGetValue("ccc", -5, out val));
|
||||
Assert.AreEqual("", val);
|
||||
|
||||
Assert.IsTrue(dict.TryGetValue("", 0, out val));
|
||||
Assert.AreEqual("", val);
|
||||
|
||||
// negative
|
||||
|
||||
Assert.IsFalse(dict.TryGetValue("ccc", -50, out val));
|
||||
Assert.IsFalse(dict.TryGetValue("", 1, out val));
|
||||
Assert.IsFalse(dict.TryGetValue("missing", 0, out val));
|
||||
}
|
||||
}
|
||||
}
|
@ -51,6 +51,7 @@
|
||||
<Compile Include="Core\Utils\TestBrowserUtils.cs" />
|
||||
<Compile Include="Core\Utils\TestCommandLineArgs.cs" />
|
||||
<Compile Include="Core\Utils\TestCommandLineArgsParser.cs" />
|
||||
<Compile Include="Core\Utils\TestTwoKeyDictionary.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="TestUtils.cs" />
|
||||
</ItemGroup>
|
||||
|
Loading…
Reference in New Issue
Block a user