MultiDictionaryTests.cs :  » Development » TULP2G » Wintellect » PowerCollections » Tests » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Development » TULP2G 
TULP2G » Wintellect » PowerCollections » Tests » MultiDictionaryTests.cs
//******************************
// Written by Peter Golde
// Copyright (c) 2004-2005, Wintellect
//
// Use and restribution of this code is subject to the license agreement 
// contained in the file "License.txt" accompanying this file.
//******************************

using System;
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using Wintellect.PowerCollections.Tests;

namespace Wintellect.PowerCollections.Tests{
    using MyInt = OrderedDictionaryTests.MyInt;

    [TestFixture]
    public class MultiDictionaryTests
    {
        // Check the contents of a Multi-Dictionary non-destructively. Keys and Values must be in order.
        internal static void CheckMultiDictionaryContents<TKey, TValue>(MultiDictionary<TKey, TValue> dict, TKey[] keys, TValue[][] values, TKey nonKey, TValue nonValue, BinaryPredicate<TKey> keyEquals, BinaryPredicate<TValue> valueEquals)
        {
            int iKey, iValue;
            ICollection<TValue> getValues;

            if (keyEquals == null)
                keyEquals = delegate(TKey x, TKey y) { return object.Equals(x, y); };
            if (valueEquals == null)
                valueEquals = delegate(TValue x, TValue y) { return object.Equals(x, y); };

            // Check Count.
            Assert.AreEqual(keys.Length, dict.Count);

            // Check indexer, ContainsKey, Contains, TryGetValue for each key.
            for (iKey = 0; iKey < keys.Length; ++iKey) {
                Assert.IsTrue(dict.ContainsKey(keys[iKey]));
                Assert.IsTrue(dict.Contains(new KeyValuePair<TKey, ICollection<TValue>>(keys[iKey], values[iKey])));

                bool b = ((IDictionary<TKey, ICollection<TValue>>)dict).TryGetValue(keys[iKey], out getValues);
                Assert.IsTrue(b);
                iValue = 0;
                InterfaceTests.TestEnumerableElementsAnyOrder(getValues, values[iKey]);

                iValue = 0;
                foreach (TValue val in values[iKey]) {
                    Assert.IsTrue(dict.Contains(keys[iKey], val));
                    ++iValue;
                }
                Assert.IsTrue(iValue == values[iKey].Length);

                iValue = 0;
                getValues = dict[keys[iKey]];
                InterfaceTests.TestEnumerableElementsAnyOrder(getValues, values[iKey]);
            }

            // Check Keys collection.
            InterfaceTests.TestReadonlyCollectionGeneric<TKey>(dict.Keys, keys, false, null, keyEquals);

            // Check Values collection
            int a = 0;
            TValue[] vals = new TValue[dict.Values.Count];
            for (iKey = 0; iKey < keys.Length; ++iKey) {
                for (iValue = 0; iValue < values[iKey].Length; ++iValue) {
                    vals[a++] = values[iKey][iValue];
                }
            }
            Assert.AreEqual(dict.Values.Count, a);
            InterfaceTests.TestReadonlyCollectionGeneric<TValue>(dict.Values, vals, false, null, valueEquals);

            // Check KeyValuePairs collection.
            a = 0;
            KeyValuePair<TKey, TValue>[] pairs = new KeyValuePair<TKey, TValue>[dict.Values.Count];
            for (iKey = 0; iKey < keys.Length; ++iKey) {
                for (iValue = 0; iValue < values[iKey].Length; ++iValue) {
                    pairs[a++] = new KeyValuePair<TKey, TValue>(keys[iKey], values[iKey][iValue]);
                }
            }
            InterfaceTests.TestReadonlyCollectionGeneric<KeyValuePair<TKey, TValue>>(dict.KeyValuePairs, pairs, false, null, InterfaceTests.KeyValueEquals<TKey,TValue>(keyEquals,valueEquals));

            // Tests Contains, ContainsKey, TryGetValue for wrong values.
            Assert.IsFalse(dict.ContainsKey(nonKey));
            Assert.IsFalse(((IDictionary<TKey, ICollection<TValue>>)dict).TryGetValue(nonKey, out getValues));
            for (iKey = 0; iKey < keys.Length; ++iKey) {
                Assert.IsFalse(dict.Contains(keys[iKey], nonValue));
                Assert.IsFalse(dict.Contains(new KeyValuePair<TKey, ICollection<TValue>>(keys[iKey], new TValue[1] { nonValue })));
            }

            // Test IDictionary<TKey,IEnumerable<TValue>> implementation
            InterfaceTests.TestReadWriteMultiDictionaryGeneric<TKey, TValue>(dict, keys, values, nonKey, nonValue, false, "MultiDictionary", keyEquals, valueEquals);
        }

        // Do random add,remove,replaces and create an array.
        private int[,] AddRemoveRandom(Random rand, MultiDictionary<int, string> dict, bool useDups, int iter)
        {
            const int MAXKEY = 100, MAXVAL = 50;
            int[,] counts = new int[MAXKEY, MAXVAL];

            for (int x = 0; x < iter; ++x) {
                int key = rand.Next(MAXKEY);
                int val = rand.Next(MAXVAL);
                string valString = string.Format("A{0:0000}", val);

                if (counts[key, val] == 0) {
                    if (rand.Next(30) == 0) {
                        // Do a replace
                        dict.Replace(key, valString);
                        for (int i = 0; i < MAXVAL; ++i)
                            counts[key, i] = 0;
                        counts[key, val] = 1;
                    }
                    else {
                        // Do an add
                        dict.Add(key, valString);
                        counts[key, val] = 1;
                    }
                }
                else {
                    if (rand.Next(30) == 0) {
                        // Do a replace
                        dict.Replace(key, valString);
                        for (int i = 0; i < MAXVAL; ++i)
                            counts[key, i] = 0;
                        counts[key, val] = 1;
                    }
                    else if (rand.Next(5) < 2) {
                        // Do an add
                        dict.Add(key, valString);
                        if (useDups)
                            counts[key, val] += 1;
                    }
                    else {
                        // Do a remove
                        dict.Remove(key, valString);
                        counts[key, val] -= 1;
                    }
                }
            }

            return counts;
        }

        // Check an ordered multi-dictionary against an array.
        private void CheckAgainstArray(MultiDictionary<int, string> dict, int[,] array)
        {
            List<string[]> values = new List<string[]>();
            List<int> keys = new List<int>();
            List<string> vals = new List<string>();

            for (int i = 0; i < array.GetLength(0); ++i) {
                bool hasval = false;
                for (int j = 0; j < array.GetLength(1); ++j) {
                    if (array[i, j] > 0) {
                        hasval = true;
                        for (int x = 0; x < array[i, j]; ++x)
                            vals.Add(string.Format("A{0:0000}", j));
                    }
                }

                if (hasval) {
                    keys.Add(i);
                    values.Add(vals.ToArray());
                    vals.Clear();
                }
            }

            int[] keysArray = keys.ToArray();
            string[][] valsArray = values.ToArray();

            CheckMultiDictionaryContents<int, string>(dict,
                keysArray,
                valsArray,
                -1, "Foo", null, null);
        }

        [Test]
        public void RandomAdd()
        {
            Random rand = new Random(14);
            MultiDictionary<int, string> dict = new MultiDictionary<int, string>(true);

            int[,] array = AddRemoveRandom(rand, dict, true, 3000);
            CheckAgainstArray(dict, array);
        }


        [Test]
        public void Add()
        {
            // Test without duplicate values.
            MultiDictionary<string, double> dict1 = new MultiDictionary<string, double>(false);

            dict1.Add("foo", 3.5);
            dict1.Add("foo", -1.2);
            dict1.Add(null, 11.1);
            dict1.Add("foo", 8.8);
            dict1.Add(null, 11.1);
            dict1.Add("bar", 9.8);
            dict1.Add("foo", 8.8);
            dict1.Add("gib", 7.1);
            dict1.Add("S", -9);
            dict1.Add(null, 5.5);

            CheckMultiDictionaryContents<string, double>(dict1,
                new string[] { null, "bar", "foo", "gib", "S" },
                new double[][] { new double[] { 5.5, 11.1 }, new double[] { 9.8 }, new double[] { -1.2, 3.5, 8.8 }, new double[] { 7.1 }, new double[] { -9 } },
                "zip", -100, null, null);

            // Test with duplicate values.
            dict1 = new MultiDictionary<string, double>(true);

            dict1.Add("foo", 3.5);
            dict1.Add("foo", -1.2);
            dict1.Add(null, 11.1);
            dict1.Add("foo", 8.8);
            dict1.Add(null, 11.1);
            dict1.Add("bar", 9.8);
            dict1.Add("foo", 8.8);
            dict1.Add("gib", 7.1);
            dict1.Add("S", -9);
            dict1.Add(null, 5.5);

            CheckMultiDictionaryContents<string, double>(dict1,
                new string[] { null, "bar", "foo", "gib", "S" },
                new double[][] { new double[] { 5.5, 11.1, 11.1 }, new double[] { 9.8 }, new double[] { -1.2, 3.5, 8.8, 8.8 }, new double[] { 7.1 }, new double[] { -9 } },
                "zip", -100, null, null);

            // Test duplicate values with distinct equal values.
            MultiDictionary<string, string> dict2 = new MultiDictionary<string, string>(false, StringComparer.InvariantCultureIgnoreCase, StringComparer.InvariantCultureIgnoreCase);
            dict2.Add("foo", "BAR");
            dict2.Add("Foo", "bar");
            InterfaceTests.TestEnumerableElementsAnyOrder<string>(dict2.Keys, new string[] { "foo" });
            InterfaceTests.TestEnumerableElementsAnyOrder<string>(dict2["FOO"], new string[] { "bar" });
            dict2 = new MultiDictionary<string, string>(true, StringComparer.InvariantCultureIgnoreCase, StringComparer.InvariantCultureIgnoreCase);
            dict2.Add("foo", "BAR");
            dict2.Add("Foo", "bar");
            InterfaceTests.TestEnumerableElementsAnyOrder<string>(dict2.Keys, new string[] { "foo" });
            InterfaceTests.TestEnumerableElementsAnyOrder<string>(dict2["FOO"], new string[] { "BAR", "bar" });
            InterfaceTests.TestEnumerableElementsAnyOrder<KeyValuePair<string, string>>
                (dict2.KeyValuePairs, new KeyValuePair<string, string>[] { new KeyValuePair<string,string>("foo", "BAR"),
                  new KeyValuePair<string,string>("foo", "bar")}, InterfaceTests.KeyValueEquals<string, string>());
        }

        [Test]
        public void AddMany1()
        {
            // Test without duplicate values.
            MultiDictionary<string, double> dict1 = new MultiDictionary<string, double>(false, StringComparer.InvariantCultureIgnoreCase);

            dict1.AddMany("foo", AlgorithmsTests.EnumerableFromArray(new double[] { 9.8, 1.2, -9, 9.8, -9, 4 }));
            dict1.AddMany("hi", new double[0]);
            dict1.AddMany("FOO", AlgorithmsTests.EnumerableFromArray(new double[] { 8, -9 }));

            Assert.AreEqual(1, dict1.Count);
            Assert.IsTrue(dict1.ContainsKey("foo"));
            Assert.IsFalse(dict1.ContainsKey("hi"));
            InterfaceTests.TestEnumerableElementsAnyOrder(dict1.Keys, new string[] { "foo" });
            InterfaceTests.TestEnumerableElementsAnyOrder(dict1["fOo"], new double[] { -9, 1.2, 4, 8, 9.8 });
            InterfaceTests.TestEnumerableElementsAnyOrder<KeyValuePair<string, double>>
                (dict1.KeyValuePairs, new KeyValuePair<string, double>[] { 
                            new KeyValuePair<string,double>("foo", -9),
                            new KeyValuePair<string,double>("foo", 1.2),
                            new KeyValuePair<string,double>("foo", 4),
                            new KeyValuePair<string,double>("foo",8),
                            new KeyValuePair<string,double>("foo",9.8)
                            });

            // Test with duplicate values
            dict1 = new MultiDictionary<string, double>(true, StringComparer.InvariantCultureIgnoreCase);

            dict1.AddMany("foo", AlgorithmsTests.EnumerableFromArray(new double[] { 9.8, 1.2, -9, 9.8, -9, 4 }));
            dict1.AddMany("hi", new double[0]);
            dict1.AddMany("a", new double[] { 2, 1, 2 });
            dict1.AddMany("FOO", AlgorithmsTests.EnumerableFromArray(new double[] { 8, -9 }));

            Assert.AreEqual(2, dict1.Count);
            Assert.IsTrue(dict1.ContainsKey("foo"));
            Assert.IsFalse(dict1.ContainsKey("hi"));
            InterfaceTests.TestEnumerableElementsAnyOrder(dict1.Keys, new string[] { "a", "foo" });
            InterfaceTests.TestEnumerableElementsAnyOrder(dict1["fOo"], new double[] { -9, -9, -9, 1.2, 4, 8, 9.8, 9.8 });
            InterfaceTests.TestEnumerableElementsAnyOrder<KeyValuePair<string, double>>
                (dict1.KeyValuePairs, new KeyValuePair<string, double>[] { 
                            new KeyValuePair<string,double>("a", 1),
                            new KeyValuePair<string,double>("a", 2),
                            new KeyValuePair<string,double>("a", 2),
                            new KeyValuePair<string,double>("foo", -9),
                            new KeyValuePair<string,double>("foo", -9),
                            new KeyValuePair<string,double>("foo", -9),
                            new KeyValuePair<string,double>("foo", 1.2),
                            new KeyValuePair<string,double>("foo", 4),
                            new KeyValuePair<string,double>("foo",8),
                            new KeyValuePair<string,double>("foo",9.8),
                            new KeyValuePair<string,double>("foo",9.8)
                            });
        }

        [Test]
        public void Replace()
        {
            MultiDictionary<string, int> dict1 = new MultiDictionary<string, int>(true);

            dict1.Add("foo", 4);
            dict1.Add("bar", 7);
            dict1.Add("foo", 6);
            dict1.Add("z", 3);
            dict1.Add("bar", 8);
            dict1.Add("z", 3);
            dict1.Add("foo", 1);

            dict1.Replace("foo", 13);
            dict1.Replace("z", 19);
            dict1.Replace("hello", 193);
            dict1.Replace("foo", 123);
            dict1.Add("foo", 123);

            CheckMultiDictionaryContents(dict1,
                new string[] { "bar", "foo", "hello", "z" },
                new int[][] { new int[] { 7, 8 }, new int[] { 123, 123 }, new int[] { 193 }, new int[] { 19 } },
                "sailor", 19921, null, null);
        }

        [Test]
        public void ReplaceMany()
        {
            MultiDictionary<string, int> dict1 = new MultiDictionary<string, int>(false);

            dict1.Add("foo", 4);
            dict1.Add("bar", 7);
            dict1.Add("foo", 6);
            dict1.Add("z", 3);
            dict1.Add("bar", 8);
            dict1.Add("z", 3);
            dict1.Add("foo", 1);
            dict1.Add("bill", 9);

            dict1.ReplaceMany("bill", new int[0]);
            dict1.ReplaceMany("foo", new int[] { 13, 4 });
            dict1.ReplaceMany("z", new int[] { 19 });
            dict1.ReplaceMany("hello", new int[] { 193, -11, 193 });
            dict1.ReplaceMany("goodbye", new int[0]);
            dict1.ReplaceMany("foo", new int[] { 123, 0, 4 });
            dict1.Add("foo", 29);

            CheckMultiDictionaryContents(dict1,
                new string[] { "bar", "foo", "hello", "z" },
                new int[][] { new int[] { 7, 8 }, new int[] { 0, 4, 29, 123 }, new int[] { -11, 193 }, new int[] { 19 } },
                "sailor", 19921, null, null);
        }

        [Test]
        public void RemoveKey()
        {
            MultiDictionary<string, int> dict1 = new MultiDictionary<string, int>(true);

            dict1.Add("foo", 4);
            dict1.Add("bar", 7);
            dict1.Add("foo", 6);
            dict1.Add("z", 3);
            dict1.Add("bar", 8);
            dict1.Add("z", 10);
            dict1.Add("z", 3);
            dict1.Add("foo", 4);
            dict1.Add("bill", 9);

            Assert.IsTrue(dict1.ContainsKey("bill"));
            Assert.IsTrue(dict1.ContainsKey("foo"));
            Assert.IsTrue(dict1.ContainsKey("z"));

            Assert.IsTrue(dict1.Remove("bill"));
            Assert.IsFalse(dict1.Remove("bill"));
            Assert.IsFalse(dict1.Remove("smell"));
            Assert.IsTrue(dict1.Remove("foo"));

            CheckMultiDictionaryContents(dict1,
                new string[] { "bar", "z" },
                new int[][] { new int[] { 7, 8 }, new int[] { 3, 3, 10 } },
                "sailor", 19921, null, null);
        }

        [Test]
        public void RemoveManyKeys()
        {
            MultiDictionary<string, int> dict1 = new MultiDictionary<string, int>(true);

            dict1.Add("foo", 4);
            dict1.Add("bar", 7);
            dict1.Add("foo", 6);
            dict1.Add("z", 3);
            dict1.Add("bar", 8);
            dict1.Add("z", 10);
            dict1.Add("z", 3);
            dict1.Add("foo", 4);
            dict1.Add("bill", 9);

            Assert.IsTrue(dict1.ContainsKey("bill"));
            Assert.IsTrue(dict1.ContainsKey("foo"));
            Assert.IsTrue(dict1.ContainsKey("z"));

            Assert.AreEqual(2, dict1.RemoveMany(new string[] { "bill", "smell", "foo", "bill" }));

            CheckMultiDictionaryContents(dict1,
                new string[] { "bar", "z" },
                new int[][] { new int[] { 7, 8 }, new int[] { 3, 3, 10 } },
                "sailor", 19921, null, null);
        }

        [Test]
        public void Remove()
        {
            MultiDictionary<string, int> dict1 = new MultiDictionary<string, int>(true);

            dict1.Add("foo", 4);
            dict1.Add("bar", 7);
            dict1.Add("foo", 6);
            dict1.Add("z", 3);
            dict1.Add("bar", 8);
            dict1.Add("z", 10);
            dict1.Add("z", 3);
            dict1.Add("foo", 4);
            dict1.Add("bill", 9);
            dict1.Add("foo", 4);

            Assert.IsTrue(dict1.Remove("foo", 4));
            Assert.IsTrue(dict1.Remove("foo", 4));
            Assert.IsTrue(dict1.Remove("z", 10));
            Assert.IsFalse(dict1.Remove("z", 10));
            Assert.IsFalse(dict1.Remove("foo", 11));
            Assert.IsFalse(dict1.Remove(null, 0));
            Assert.IsTrue(dict1.Remove("bill", 9));

            CheckMultiDictionaryContents(dict1,
                new string[] { "bar", "foo", "z" },
                new int[][] { new int[] { 7, 8 }, new int[] { 4, 6 }, new int[] { 3, 3 } },
                "sailor", 19921, null, null);
        }

        [Test]
        public void RemoveMany1()
        {
            MultiDictionary<string, int> dict1 = new MultiDictionary<string, int>(true);

            dict1.Add("bill", 7);
            dict1.Add("foo", 4);
            dict1.Add("bar", 7);
            dict1.Add("foo", 6);
            dict1.Add("z", 3);
            dict1.Add("bar", 8);
            dict1.Add("z", 10);
            dict1.Add("z", 3);
            dict1.Add("foo", 4);
            dict1.Add("bill", 9);
            dict1.Add("foo", 4);

            Assert.AreEqual(2, dict1.RemoveMany("foo", new int[] { 4, 11, 4 }));
            Assert.AreEqual(1, dict1.RemoveMany("z", new int[] { 9, 2, 10 }));
            Assert.AreEqual(0, dict1.RemoveMany("z", new int[] { 10, 16, 144, 10 }));
            Assert.AreEqual(0, dict1.RemoveMany("foo", new int[0]));
            Assert.AreEqual(0, dict1.RemoveMany(null, new int[2] { 1, 2 }));
            Assert.AreEqual(2, dict1.RemoveMany("bill", new int[] { 9, 7 }));

            CheckMultiDictionaryContents(dict1,
                new string[] { "bar", "foo", "z" },
                new int[][] { new int[] { 7, 8 }, new int[] { 4, 6 }, new int[] { 3, 3 } },
                "sailor", 19921, null, null);
        }

        [Test]
        public void Clear()
        {
            MultiDictionary<string, int> dict1 = new MultiDictionary<string, int>(true);

            dict1.Add("foo", 4);
            dict1.Add("bill", 7);
            dict1.Add("foo", 4);
            dict1.Add("bar", 7);
            dict1.Add("foo", 6);
            dict1.Add("z", 3);
            dict1.Add("bar", 8);
            dict1.Add("z", 10);
            dict1.Add(null, 3);
            dict1.Add("foo", 4);
            dict1.Add("bill", 9);
            dict1.Add("foo", 4);

            dict1.Clear();

            Assert.AreEqual(0, dict1.Count);
            Assert.IsFalse(dict1.ContainsKey("foo"));
            Assert.IsFalse(dict1.ContainsKey("z"));
            Assert.IsFalse(dict1.ContainsKey(null));
            Assert.AreEqual(0, Algorithms.Count(dict1.Keys));
            Assert.AreEqual(0, Algorithms.Count(dict1.Values));
            Assert.AreEqual(0, Algorithms.Count(dict1.KeyValuePairs));

            CheckMultiDictionaryContents(dict1, new string[0], new int[0][], "foo", 4, null, null);
        }

        [Test]
        public void Count()
        {
            MultiDictionary<string, int> dict1 = new MultiDictionary<string, int>(true);

            dict1.Add("foo", 4);
            dict1.Add(null, 7);
            dict1.Add("bar", 11);
            dict1.Add("foo", 7);
            dict1.Add(null, 7);
            dict1.Add("hello", 11);
            dict1.Add("foo", 4);
            Assert.AreEqual(4, dict1.Count);

            MultiDictionary<string, int> dict2 = new MultiDictionary<string, int>(false);

            dict2.Add("foo", 4);
            dict2.Add(null, 7);
            dict2.Add("bar", 11);
            dict2.Add("foo", 7);
            dict2.Add(null, 7);
            dict2.Add("hello", 11);
            dict2.Add("foo", 4);
            Assert.AreEqual(4, dict2.Count);

            dict2.Remove("foo");
            Assert.AreEqual(3, dict2.Count);

            dict2.Clear();
            Assert.AreEqual(0, dict2.Count);
        }

        [Test]
        public void ContainsKey()
        {
            MultiDictionary<string, int> dict1 = new MultiDictionary<string, int>(true);

            dict1.Add("foo", 4);
            dict1.Add(null, 7);
            dict1.Add("bar", 11);
            dict1.Add("foo", 7);
            dict1.Add(null, 7);
            dict1.Add("hello", 11);
            dict1.Add("foo", 4);

            Assert.IsTrue(dict1.ContainsKey(null));
            Assert.IsTrue(dict1.ContainsKey("foo"));
            Assert.IsTrue(dict1.ContainsKey("bar"));
            Assert.IsTrue(dict1.ContainsKey("hello"));
            dict1.Remove("hello", 11);
            Assert.IsFalse(dict1.ContainsKey("hello"));
            dict1.Remove(null, 7);
            Assert.IsTrue(dict1.ContainsKey(null));
            dict1.Remove(null, 7);
            Assert.IsFalse(dict1.ContainsKey(null));
        }

        [Test]
        public void Contains()
        {
            MultiDictionary<string, int> dict1 = new MultiDictionary<string, int>(true);

            dict1.Add("foo", 4);
            dict1.Add(null, 7);
            dict1.Add("bar", 11);
            dict1.Add("foo", 7);
            dict1.Add(null, 7);
            dict1.Add("hello", 11);
            dict1.Add("foo", 4);

            Assert.IsTrue(dict1.Contains(null, 7));
            Assert.IsTrue(dict1.Contains("foo", 4));
            Assert.IsTrue(dict1.Contains("bar", 11));
            Assert.IsTrue(dict1.Contains("hello", 11));
            Assert.IsFalse(dict1.Contains("HELLO", 11));
            Assert.IsFalse(dict1.Contains("bar", 12));
            Assert.IsFalse(dict1.Contains("foo", 0));
            dict1.Remove("hello", 11);
            Assert.IsFalse(dict1.Contains("hello", 11));
            dict1.Remove(null, 7);
            Assert.IsTrue(dict1.Contains(null, 7));
            dict1.Remove(null, 7);
            Assert.IsFalse(dict1.Contains(null, 7));
        }

        [Test]
        public void KeysCollection()
        {
            MultiDictionary<string, int> dict1 = new MultiDictionary<string, int>(false, StringComparer.InvariantCultureIgnoreCase);

            dict1.Add("foo", 4);
            dict1.Add(null, 2);
            dict1.Add("bar", 3);
            dict1.Add("sailor", 0);
            dict1.Add("FOO", 9);
            dict1.Add("b", 7);
            dict1.Add("Foo", -1);
            dict1.Add("BAR", 3);
            dict1.Remove("b", 7);

            InterfaceTests.TestReadonlyCollectionGeneric<string>(dict1.Keys, new string[] { null, "bar", "foo", "sailor" }, false, null);

            Assert.IsTrue(dict1.Keys.Contains("foo"));
            Assert.IsTrue(dict1.Keys.Contains("Foo"));
            Assert.IsTrue(dict1.Keys.Contains(null));
            Assert.IsTrue(dict1.Keys.Contains("Sailor"));
            Assert.IsFalse(dict1.Keys.Contains("banana"));

            MultiDictionary<string, int> dict2 = new MultiDictionary<string, int>(false, StringComparer.InvariantCultureIgnoreCase);
            InterfaceTests.TestEnumerableElementsAnyOrder(dict2.Keys, new string[] { });
        }

        [Test]
        public void ValuesCollection1()
        {
            MultiDictionary<double, string> dict = new MultiDictionary<double, string>(false, EqualityComparer<double>.Default, StringComparer.InvariantCultureIgnoreCase);

            dict.Add(7, "Gizzle");
            dict.Add(4, "foo");
            dict.Add(6, "Foo");
            dict.Add(3, "FOO");
            dict.Add(3, "baz");
            dict.Add(3, "bar");
            dict.Add(4, "FOo");
            dict.Add(3, "BAZ");
            dict.Add(5, "bAZ");
            dict.Add(7, "hello");
            dict.Add(7, "foo");

            ICollection<string> vals = dict.Values;

            string[] expected = {
                "bar", "BAZ", "FOO", "FOo", "bAZ", "Foo", "foo", "Gizzle", "hello"};

            InterfaceTests.TestReadonlyCollectionGeneric<string>(vals, expected, false, null);

            Assert.IsTrue(vals.Contains("gizzle"));
            Assert.IsTrue(vals.Contains("FOO"));
            Assert.IsTrue(vals.Contains("fOO"));
            Assert.IsTrue(vals.Contains("hello"));
            Assert.IsTrue(vals.Contains("bar"));
            Assert.IsTrue(vals.Contains("BAR"));
            Assert.IsFalse(vals.Contains("qatar"));
        }

        [Test]
        public void ValuesCollection2()
        {
            MultiDictionary<double, string> dict = new MultiDictionary<double, string>(true, EqualityComparer<double>.Default, StringComparer.InvariantCultureIgnoreCase);

            dict.Add(7, "Gizzle");
            dict.Add(4, "foo");
            dict.Add(6, "Foo");
            dict.Add(3, "FOO");
            dict.Add(3, "baz");
            dict.Add(3, "bar");
            dict.Add(4, "FOo");
            dict.Add(3, "BAZ");
            dict.Add(5, "bAZ");
            dict.Add(7, "hello");
            dict.Add(7, "foo");

            ICollection<string> vals = dict.Values;

            string[] expected = {
                "bar", "baz", "BAZ", "FOO", "foo", "FOo", "bAZ", "Foo", "foo", "Gizzle", "hello"};

            InterfaceTests.TestReadonlyCollectionGeneric<string>(vals, expected, false, null);

            Assert.IsTrue(vals.Contains("gizzle"));
            Assert.IsTrue(vals.Contains("FOO"));
            Assert.IsTrue(vals.Contains("fOO"));
            Assert.IsTrue(vals.Contains("hello"));
            Assert.IsTrue(vals.Contains("bar"));
            Assert.IsTrue(vals.Contains("BAR"));
            Assert.IsFalse(vals.Contains("qatar"));
        }

        [Test]
        public void KeyValuesCollection1()
        {
            MultiDictionary<string, string> dict = new MultiDictionary<string, string>(false, StringComparer.InvariantCultureIgnoreCase, StringComparer.InvariantCultureIgnoreCase);

            dict.Add("7A", "Gizzle");
            dict.Add("4a", "foo");
            dict.Add("6A", "Foo");
            dict.Add("3a", "FOO");
            dict.Add("3A", "baz");
            dict.Add("3a", "bar");
            dict.Add("4a", "FOo");
            dict.Add("3A", "BAZ");
            dict.Add("5a", "bAZ");
            dict.Add("7a", "hello");
            dict.Add("7A", "foo");

            ICollection<KeyValuePair<string, string>> pairs = dict.KeyValuePairs;

            string[] expectedKeys = {
                "3a", "3a", "3a", "4a", "5a", "6A", "7A", "7A", "7A"};
            string[] expectedVals = {
                "bar", "BAZ", "FOO", "FOo", "bAZ", "Foo", "foo", "Gizzle", "hello"};
            KeyValuePair<string, string>[] expectedPairs = new KeyValuePair<string, string>[expectedKeys.Length];
            for (int i = 0; i < expectedKeys.Length; ++i)
                expectedPairs[i] = new KeyValuePair<string, string>(expectedKeys[i], expectedVals[i]);

            InterfaceTests.TestReadonlyCollectionGeneric<KeyValuePair<string, string>>(pairs, expectedPairs, false, null);

            Assert.IsTrue(pairs.Contains(new KeyValuePair<string, string>("3a", "baz")));
            Assert.IsTrue(pairs.Contains(new KeyValuePair<string, string>("3A", "baz")));
            Assert.IsTrue(pairs.Contains(new KeyValuePair<string, string>("6a", "foo")));
            Assert.IsFalse(pairs.Contains(new KeyValuePair<string, string>("7A", "bar")));
        }

        [Test]
        public void KeyValuesCollection2()
        {
            MultiDictionary<string, string> dict = new MultiDictionary<string, string>(true, StringComparer.InvariantCultureIgnoreCase, StringComparer.InvariantCultureIgnoreCase);

            dict.Add("7A", "Gizzle");
            dict.Add("4A", "foo");
            dict.Add("6A", "Foo");
            dict.Add("3a", "FOO");
            dict.Add("3A", "baz");
            dict.Add("3a", "bar");
            dict.Add("4a", "FOo");
            dict.Add("3a", "BAZ");
            dict.Add("5a", "bAZ");
            dict.Add("7a", "hello");
            dict.Add("7A", "foo");

            ICollection<KeyValuePair<string, string>> pairs = dict.KeyValuePairs;

            string[] expectedKeys = {
            "3a", "3a", "3a", "3a", "4A", "4A", "5a", "6A", "7A", "7A", "7A"};
            string[] expectedVals = {
            "bar", "baz", "BAZ", "FOO", "foo", "FOo", "bAZ", "Foo", "foo", "Gizzle", "hello"};
            KeyValuePair<string, string>[] expectedPairs = new KeyValuePair<string, string>[expectedKeys.Length];
            for (int i = 0; i < expectedKeys.Length; ++i)
                expectedPairs[i] = new KeyValuePair<string, string>(expectedKeys[i], expectedVals[i]);

            InterfaceTests.TestReadonlyCollectionGeneric<KeyValuePair<string, string>>(pairs, expectedPairs, false, null);

            Assert.IsTrue(pairs.Contains(new KeyValuePair<string, string>("3a", "baz")));
            Assert.IsTrue(pairs.Contains(new KeyValuePair<string, string>("3A", "baz")));
            Assert.IsTrue(pairs.Contains(new KeyValuePair<string, string>("6a", "foo")));
            Assert.IsFalse(pairs.Contains(new KeyValuePair<string, string>("7A", "bar")));
        }

        [Test]
        public void Indexer()
        {
            MultiDictionary<string, string> dict1 = new MultiDictionary<string, string>(true, StringComparer.InvariantCultureIgnoreCase, StringComparer.InvariantCultureIgnoreCase);

            dict1.Add("foo", "BAR");
            dict1.Add(null, "hello");
            dict1.Add("Hello", "sailor");
            dict1.Add(null, "hi");
            dict1.Add("foo", "bar");
            dict1.Add("HELLO", null);
            dict1.Add("foo", "a");
            dict1.Add("Foo", "A");
            dict1.Add("trail", "mix");

            InterfaceTests.TestEnumerableElementsAnyOrder(dict1[null], new string[] { "hello", "hi" });
            InterfaceTests.TestEnumerableElementsAnyOrder(dict1["hELLo"], new string[] { null, "sailor" });
            InterfaceTests.TestEnumerableElementsAnyOrder(dict1["foo"], new string[] { "a", "A", "BAR", "bar" });
            InterfaceTests.TestEnumerableElementsAnyOrder(dict1["trail"], new string[] { "mix" });
            InterfaceTests.TestEnumerableElementsAnyOrder(dict1["nothing"], new string[] { });
        }

        [Test]
        public void GetValueCount()
        {
            MultiDictionary<string, string> dict1 = new MultiDictionary<string, string>(true, StringComparer.InvariantCultureIgnoreCase, StringComparer.InvariantCultureIgnoreCase);

            dict1.Add("foo", "BAR");
            dict1.Add(null, "hello");
            dict1.Add("Hello", "sailor");
            dict1.Add(null, "hi");
            dict1.Add("foo", "bar");
            dict1.Add("HELLO", null);
            dict1.Add("foo", "a");
            dict1.Add("Foo", "A");
            dict1.Add("hello", null);
            dict1.Add("trail", "mix");

            Assert.AreEqual(2, dict1[null].Count);
            Assert.AreEqual(3, dict1["hELLo"].Count);
            Assert.AreEqual(4, dict1["foo"].Count);
            Assert.AreEqual(1, dict1["trail"].Count);
            Assert.AreEqual(0, dict1["nothing"].Count);

            dict1 = new MultiDictionary<string, string>(false, StringComparer.InvariantCultureIgnoreCase, StringComparer.InvariantCultureIgnoreCase);

            dict1.Add("foo", "BAR");
            dict1.Add(null, "hello");
            dict1.Add("Hello", "sailor");
            dict1.Add(null, "hi");
            dict1.Add("foo", "bar");
            dict1.Add("HELLO", null);
            dict1.Add("foo", "a");
            dict1.Add("Foo", "A");
            dict1.Add("hello", null);
            dict1.Add("trail", "mix");

            Assert.AreEqual(2, dict1[null].Count);
            Assert.AreEqual(2, dict1["hELLo"].Count);
            Assert.AreEqual(2, dict1["foo"].Count);
            Assert.AreEqual(1, dict1["trail"].Count);
            Assert.AreEqual(0, dict1["nothing"].Count);

        }

        [Test]
        public void IMultiDictionaryInterface()
        {
            MultiDictionary<string, string> dict1 = new MultiDictionary<string, string>(true);

            dict1.Add("foo", "bar");
            dict1.Add(null, "hello");
            dict1.Add("hello", "sailor");
            dict1.Add(null, "hi");
            dict1.Add("foo", "bar");
            dict1.Add("hello", null);
            dict1.Add("foo", "a");
            dict1.Add("foo", "a");
            dict1.Add("hello", null);
            dict1.Add("trail", "mix");

            CheckMultiDictionaryContents<string, string>(dict1,
                new string[] { null, "foo", "hello", "trail" },
                new string[][] { new string[] { "hello", "hi" }, new string[] { "a", "a", "bar", "bar" }, new string[] { null, null, "sailor" }, new string[] { "mix" } },
                "zippy", "pinhead", null, null);

            dict1 = new MultiDictionary<string, string>(false);

            dict1.Add("foo", "bar");
            dict1.Add(null, "hello");
            dict1.Add("hello", "sailor");
            dict1.Add(null, "hi");
            dict1.Add("foo", "bar");
            dict1.Add("hello", null);
            dict1.Add("foo", "a");
            dict1.Add("foo", "a");
            dict1.Add("hello", null);

            dict1.Add("trail", "mix");
            CheckMultiDictionaryContents<string, string>(dict1,
                new string[] { null, "foo", "hello", "trail" },
                new string[][] { new string[] { "hello", "hi" }, new string[] { "a", "bar" }, new string[] { null, "sailor" }, new string[] { "mix" } },
                "zippy", "pinhead", null, null);

        }

        [Test]
        public void CustomComparer()
        {
            IEqualityComparer<string> firstLetterComparer = new FirstLetterComparer();

            MultiDictionary<string, string> dict1 = new MultiDictionary<string, string>(false, firstLetterComparer);

            dict1.Add("hello", "AAA");
            dict1.Add("hi", "aaa");
            dict1.Add("qubert", "hello");
            dict1.Add("queztel", "hello");
            dict1.Add("alpha", "omega");
            dict1.Add("alzabar", "oz");

            InterfaceTests.TestEnumerableElementsAnyOrder(dict1.KeyValuePairs, new KeyValuePair<string, string>[] {
                new KeyValuePair<string,string>("qubert", "hello"),
                new KeyValuePair<string,string>("hello", "aaa"),
                new KeyValuePair<string,string>("hello", "AAA"),
                new KeyValuePair<string,string>("alpha", "omega"),
                new KeyValuePair<string,string>("alpha", "oz")});

            InterfaceTests.TestEnumerableElementsAnyOrder(dict1.Keys, new string[] { "qubert", "hello", "alpha" });

            MultiDictionary<string, string> dict2 = new MultiDictionary<string, string>(false, StringComparer.InvariantCultureIgnoreCase, firstLetterComparer);

            dict2.Add("qubert", "dinosaur");
            dict2.Add("Hello", "AAA");
            dict2.Add("Hi", "aaa");
            dict2.Add("qubert", "hello");
            dict2.Add("queztel", "hello");
            dict2.Add("alpha", "omega");
            dict2.Add("Alpha", "oz");
            dict2.Add("qubert", "hippy");

            InterfaceTests.TestEnumerableElementsAnyOrder(dict2.KeyValuePairs, new KeyValuePair<string, string>[] {
                new KeyValuePair<string,string>("alpha", "oz"),
                new KeyValuePair<string,string>("Hello", "AAA"),
                new KeyValuePair<string,string>("Hi", "aaa"),
                new KeyValuePair<string,string>("qubert", "hippy"),
                new KeyValuePair<string,string>("qubert", "dinosaur"),
                new KeyValuePair<string,string>("queztel", "hello")});
        }

        [Test]
        public void NotComparable1()
        {
            // This should work -- all types are comparable in a hash way via object.Equals and object.GetHashCode.
            MultiDictionary<OrderedDictionaryTests.UncomparableClass1, string> dict1 = new MultiDictionary<OrderedDictionaryTests.UncomparableClass1, string>(false);
        }

        [Test]
        public void NotComparable2()
        {
            // This should work -- all types are comparable in a hash way via object.Equals and object.GetHashCode.
            MultiDictionary<string, OrderedDictionaryTests.UncomparableClass2> dict2 = new MultiDictionary<string, OrderedDictionaryTests.UncomparableClass2>(true);
        }

        class FirstLetterComparer : IEqualityComparer<string>
        {
            public bool Equals(string x, string y)
            {
                if (x == null)
                    return y == null;
                else if (x.Length == 0)
                    return (y != null && y.Length == 0);
                else {
                    if (y == null || y.Length == 0)
                        return false;
                    else
                        return x[0] == y[0];
                }
            }

            public int GetHashCode(string obj)
            {
                if (obj == null)
                    return 0x12383;
                else if (obj.Length == 0)
                    return 17;
                else
                    return obj[0].GetHashCode();
            }
        }

        [Test]
        public void Clone()
        {
            IEqualityComparer<string> firstLetterComparer = new FirstLetterComparer();

            MultiDictionary<string, string> dict1 = new MultiDictionary<string, string>(false, StringComparer.InvariantCultureIgnoreCase, firstLetterComparer);

            dict1.Add("qubert", "dinosaur");
            dict1.Add("Hello", "AAA");
            dict1.Add("Hi", "aaa");
            dict1.Add("Qubert", "hello");
            dict1.Add("queztel", "hello");
            dict1.Add("Alpha", "omega");
            dict1.Add("alpha", "oz");
            dict1.Add("qubert", "hippy");

            MultiDictionary<string, string> dict2 = dict1.Clone();

            Assert.IsTrue(dict1 != dict2);

            dict2.Add("qubert", "hoover");
            dict2.Remove("queztel");
            dict2.Add("hello", "banana");

            InterfaceTests.TestEnumerableElementsAnyOrder(dict1.KeyValuePairs, new KeyValuePair<string, string>[] {
                new KeyValuePair<string,string>("Alpha", "oz"),
                new KeyValuePair<string,string>("Hello", "AAA"),
                new KeyValuePair<string,string>("Hi", "aaa"),
                new KeyValuePair<string,string>("qubert", "hippy"),
                new KeyValuePair<string,string>("qubert", "dinosaur"),
                new KeyValuePair<string,string>("queztel", "hello")});

            InterfaceTests.TestEnumerableElementsAnyOrder(dict2.KeyValuePairs, new KeyValuePair<string, string>[] {
                new KeyValuePair<string,string>("Alpha", "oz"),
                new KeyValuePair<string,string>("Hello", "banana"),
                new KeyValuePair<string,string>("Hello", "AAA"),
                new KeyValuePair<string,string>("Hi", "aaa"),
                new KeyValuePair<string,string>("qubert", "hoover"),
                new KeyValuePair<string,string>("qubert", "dinosaur")});

            dict2 = ((MultiDictionary<string, string>)((ICloneable)dict1).Clone());

            Assert.IsTrue(dict1 != dict2);

            dict2.Add("qubert", "hoover");
            dict2.Remove("queztel");
            dict2.Add("hello", "banana");

            InterfaceTests.TestEnumerableElementsAnyOrder(dict2.KeyValuePairs, new KeyValuePair<string, string>[] {
                new KeyValuePair<string,string>("Alpha", "oz"),
                new KeyValuePair<string,string>("Hello", "banana"),
                new KeyValuePair<string,string>("Hello", "AAA"),
                new KeyValuePair<string,string>("Hi", "aaa"),
                new KeyValuePair<string,string>("qubert", "hoover"),
                new KeyValuePair<string,string>("qubert", "dinosaur")});

            MultiDictionary<string, int> dict4 = new MultiDictionary<string, int>(true);
            MultiDictionary<string, int> dict5;
            dict5 = dict4.Clone();
            Assert.IsFalse(dict4 == dict5);
            Assert.IsTrue(dict4.Count == 0 && dict5.Count == 0);
            dict4.Add("hello", 1);
            Assert.IsTrue(dict4.Count == 1 && dict5.Count == 0);
            dict5.Add("hi", 7);
            dict4.Clear();
            Assert.IsTrue(dict4.Count == 0 && dict5.Count == 1);
        }

        void CompareClones<K, V>(MultiDictionary<K, V> d1, MultiDictionary<K, V> d2)
        {
            IEnumerable<KeyValuePair<K, V>> e1 = d1.KeyValuePairs;
            IEnumerable<KeyValuePair<K, V>> e2 = d2.KeyValuePairs;
            KeyValuePair<K, V>[] pairs1 = Algorithms.ToArray<KeyValuePair<K, V>>(e1), pairs2 = Algorithms.ToArray<KeyValuePair<K, V>>(e2);
            bool[] found = new bool[pairs2.Length];

            // Check that the arrays are equal, but not reference equals (e.g., have been cloned).
            Assert.IsTrue(pairs1.Length == pairs2.Length);
            foreach (KeyValuePair<K, V> p1 in pairs1) {
                bool f = false;
                for (int i = 0; i < pairs2.Length; ++i) {
                    if (!found[i] && object.Equals(p1.Key, pairs2[i].Key) && object.Equals(p1.Value, pairs2[i].Value)) {
                        found[i] = true;
                        f = true;
                        Assert.IsTrue(p1.Key == null || !object.ReferenceEquals(p1.Key, pairs2[i].Key));
                        Assert.IsTrue(p1.Value == null || !object.ReferenceEquals(p1.Value, pairs2[i].Value));
                        break;
                    }
                }
                Assert.IsTrue(f);
            }
        }

        private class MyIntComparer : IEqualityComparer<MyInt>
        {
            public bool Equals(MyInt x, MyInt y)
            {
                if (x == null)
                    return y == null;
                else if (y == null)
                    return x == null;
                else
                    return x.value == y.value;
            }

            public int GetHashCode(MyInt obj)
            {
                if (obj == null)
                    return 0x42834E;
                else
                    return obj.value.GetHashCode();
            }
        }

        [Test]
        public void CloneContents()
        {
            MyIntComparer comparer = new MyIntComparer();
            MultiDictionary<int, MyInt> dict1 = new MultiDictionary<int, MyInt>(true, EqualityComparer<int>.Default, comparer);

            dict1.Add(4, new MyInt(143));
            dict1.Add(7, new MyInt(2));
            dict1.Add(11, new MyInt(9));
            dict1.Add(7, new MyInt(119));
            dict1.Add(18, null);
            dict1.Add(4, new MyInt(16));
            dict1.Add(7, null);
            dict1.Add(7, new MyInt(119));
            MultiDictionary<int, MyInt> dict2 = dict1.CloneContents();
            CompareClones(dict1, dict2);

            MultiDictionary<MyInt, int> dict3 = new MultiDictionary<MyInt, int>(false, comparer);

            dict3.Add(new MyInt(4), 143);
            dict3.Add(new MyInt(7), 2);
            dict3.Add(new MyInt(11), 9);
            dict3.Add(new MyInt(7), 119);
            dict3.Add(new MyInt(18), 0);
            dict3.Add(new MyInt(4), 16);
            dict3.Add(null, 11);
            dict3.Add(new MyInt(7), 119);

            MultiDictionary<MyInt, int> dict4 = dict3.CloneContents();
            CompareClones(dict3, dict4);

            MultiDictionary<UtilTests.CloneableStruct, UtilTests.CloneableStruct> dict5 = new MultiDictionary<UtilTests.CloneableStruct, UtilTests.CloneableStruct>(true);
            dict5.Add(new UtilTests.CloneableStruct(7), new UtilTests.CloneableStruct(-14));
            dict5.Add(new UtilTests.CloneableStruct(16), new UtilTests.CloneableStruct(13));
            dict5.Add(new UtilTests.CloneableStruct(7), new UtilTests.CloneableStruct(-14));
            dict5.Add(new UtilTests.CloneableStruct(7), new UtilTests.CloneableStruct(31415));
            dict5.Add(new UtilTests.CloneableStruct(1111), new UtilTests.CloneableStruct(0));
            MultiDictionary<UtilTests.CloneableStruct, UtilTests.CloneableStruct> dict6 = dict5.CloneContents();

            Assert.IsTrue(dict5.Count == dict6.Count);

            IEnumerable<KeyValuePair<UtilTests.CloneableStruct, UtilTests.CloneableStruct>> e1 = dict5.KeyValuePairs;
            IEnumerable<KeyValuePair<UtilTests.CloneableStruct, UtilTests.CloneableStruct>> e2 = dict6.KeyValuePairs;
            KeyValuePair<UtilTests.CloneableStruct, UtilTests.CloneableStruct>[] pairs1 = Algorithms.ToArray<KeyValuePair<UtilTests.CloneableStruct, UtilTests.CloneableStruct>>(e1), pairs2 = Algorithms.ToArray<KeyValuePair<UtilTests.CloneableStruct, UtilTests.CloneableStruct>>(e2);
            bool[] found = new bool[pairs2.Length];

            // Check that the arrays are equal, but not reference equals (e.g., have been cloned).
            Assert.IsTrue(pairs1.Length == pairs2.Length);
            foreach (KeyValuePair<UtilTests.CloneableStruct, UtilTests.CloneableStruct> p1 in pairs1) {
                bool f = false;
                for (int i = 0; i < pairs2.Length; ++i) {
                    if (!found[i] && object.Equals(p1.Key, pairs2[i].Key) && object.Equals(p1.Value, pairs2[i].Value)) {
                        found[i] = true;
                        f = true;
                        Assert.IsFalse(p1.Key.Identical(pairs2[i].Key));
                        Assert.IsFalse(p1.Value.Identical(pairs2[i].Value));
                        break;
                    }
                }
                Assert.IsTrue(f);
            }

        }

        class NotCloneable { }

        [Test, ExpectedException(typeof(InvalidOperationException))]
        public void CantCloneContents()
        {
            MultiDictionary<int, NotCloneable> dict1 = new MultiDictionary<int, NotCloneable>(true);

            dict1[4] = new NotCloneable[] { new NotCloneable() };
            dict1[5] = new NotCloneable[] { new NotCloneable(), new NotCloneable() };

            MultiDictionary<int, NotCloneable> dict2 = dict1.CloneContents();
        }


        [Test]
        public void FailFastEnumerator()
        {
            MultiDictionary<string, int> dict1 = new MultiDictionary<string, int>(true);
            bool throwNow;

            dict1.Add("foo", 12);
            dict1.Add("foo", 15);
            dict1.Add("foo", 3);
            dict1.Add("foo", 12);
            dict1.Add("bar", 1);
            dict1.Add("bar", 17);

            throwNow = false;
            try {
                foreach (KeyValuePair<string, int> pair in dict1.KeyValuePairs) {
                    throwNow = false;
                    if (pair.Key == "foo") {
                        dict1.Replace("bar", 19);
                        throwNow = true;
                    }
                }
            }
            catch (Exception e) {
                Assert.IsTrue(e is InvalidOperationException);
                Assert.IsTrue(throwNow);
            }

            throwNow = false;
            try {
                foreach (string key in dict1.Keys) {
                    throwNow = false;
                    if (key == "foo") {
                        dict1.Add("grump", 117);
                        throwNow = true;
                    }
                }
            }
            catch (Exception e) {
                Assert.IsTrue(e is InvalidOperationException);
                Assert.IsTrue(throwNow);
            }

            throwNow = false;
            try {
                foreach (int value in dict1["foo"]) {
                    throwNow = false;
                    if (value == 12) {
                        dict1.Remove("grump", 117);
                        throwNow = true;
                    }
                }
            }
            catch (Exception e) {
                Assert.IsTrue(e is InvalidOperationException);
                Assert.IsTrue(throwNow);
            }

            throwNow = false;
            try {
                foreach (string key in dict1.Keys) {
                    throwNow = false;
                    if (key == "foo") {
                        dict1.Clear();
                        throwNow = true;
                    }
                }
            }
            catch (Exception e) {
                Assert.IsTrue(e is InvalidOperationException);
                Assert.IsTrue(throwNow);
            }

        }

        [Test]
        public void KeyComparerProperty()
        {
            IEqualityComparer<int> comparer1 = new GOddEvenEqualityComparer();
            MultiDictionary<int, string> dict1 = new MultiDictionary<int, string>(false, comparer1);
            Assert.AreSame(comparer1, dict1.KeyComparer);
            MultiDictionary<decimal, string> dict2 = new MultiDictionary<decimal, string>(true);
            Assert.AreSame(EqualityComparer<decimal>.Default, dict2.KeyComparer);
            MultiDictionary<string, string> dict3 = new MultiDictionary<string, string>(true, StringComparer.OrdinalIgnoreCase, StringComparer.CurrentCulture);
            Assert.AreSame(StringComparer.OrdinalIgnoreCase, dict3.KeyComparer);

            Assert.AreSame(dict1.KeyComparer, dict1.Clone().KeyComparer);
            Assert.AreSame(dict2.KeyComparer, dict2.Clone().KeyComparer);
            Assert.AreSame(dict3.KeyComparer, dict3.Clone().KeyComparer);
        }

        [Test]
        public void ValueComparerProperty()
        {
            IEqualityComparer<int> comparer1 = new GOddEvenEqualityComparer();
            MultiDictionary<string, int> dict1 = new MultiDictionary<string, int>(true, StringComparer.InvariantCulture, comparer1);
            Assert.AreSame(comparer1, dict1.ValueComparer);
            MultiDictionary<string, decimal> dict2 = new MultiDictionary<string, decimal>(false);
            Assert.AreSame(EqualityComparer<decimal>.Default, dict2.ValueComparer);
            MultiDictionary<string, string> dict3 = new MultiDictionary<string, string>(true, StringComparer.InvariantCulture, StringComparer.OrdinalIgnoreCase);
            Assert.AreSame(StringComparer.OrdinalIgnoreCase, dict3.ValueComparer);

            Assert.AreSame(dict1.ValueComparer, dict1.Clone().ValueComparer);
            Assert.AreSame(dict2.ValueComparer, dict2.Clone().ValueComparer);
            Assert.AreSame(dict3.ValueComparer, dict3.Clone().ValueComparer);
        }

        [Test]
        public void SerializeStrings()
        {
            MultiDictionary<string,double> d = new MultiDictionary<string,double>(true,StringComparer.InvariantCultureIgnoreCase);

            d.Add("hEllo", 13);
            d.Add("foo", 7);
            d.Add("world", -9.5);
            d.Add("hello", 11);
            d.Add("elvis", 0.9);
            d.Add("ELVIS", 1.4);
            d.Add(null, 1.4);
            d.Add("FOO", 7);
            d.Add("hello", 12);

            MultiDictionary<string, double> result = (MultiDictionary<string, double>)InterfaceTests.SerializeRoundTrip(d);

            CheckMultiDictionaryContents<String,double>(result, 
                new string[] {"FOO", "WORLD", "Hello", "eLVis", null},
                new double[][] {new double[]{7,7}, new double[]{-9.5}, new double[] {11,12,13}, new double[] {0.9, 1.4}, new double[] {1.4}}, 
                "zippy", 123, StringComparer.InvariantCultureIgnoreCase.Equals, null);
        }

        [Serializable]
        class UniqueStuff
        {
            public InterfaceTests.Unique[] keys;
            public InterfaceTests.Unique[] values;
            public MultiDictionary<InterfaceTests.Unique, InterfaceTests.Unique> dict;
        }


        [Test]
        public void SerializeUnique()
        {
            UniqueStuff d = new UniqueStuff(), result = new UniqueStuff();

            d.keys = new InterfaceTests.Unique[] {
                new InterfaceTests.Unique("1"), new InterfaceTests.Unique("2"), new InterfaceTests.Unique("3"), new InterfaceTests.Unique("4"), new InterfaceTests.Unique("5")
            };

            d.values = new InterfaceTests.Unique[] {
                new InterfaceTests.Unique("a"), new InterfaceTests.Unique("b"), new InterfaceTests.Unique("c"), new InterfaceTests.Unique("d"), new InterfaceTests.Unique("e"), new InterfaceTests.Unique("f"), new InterfaceTests.Unique("g")
            };


            d.dict = new MultiDictionary<InterfaceTests.Unique, InterfaceTests.Unique>(true);

            d.dict.Add(d.keys[2], d.values[4]);
            d.dict.Add(d.keys[0], d.values[0]);
            d.dict.Add(d.keys[1], d.values[1]);
            d.dict.Add(d.keys[2], d.values[2]);
            d.dict.Add(d.keys[3], d.values[5]);
            d.dict.Add(d.keys[3], d.values[6]);
            d.dict.Add(d.keys[4], d.values[6]);
            d.dict.Add(d.keys[0], d.values[0]);
            d.dict.Add(d.keys[2], d.values[3]);

            result = (UniqueStuff)InterfaceTests.SerializeRoundTrip(d);

            CheckMultiDictionaryContents<InterfaceTests.Unique, InterfaceTests.Unique>(result.dict,
                result.keys,
                new InterfaceTests.Unique[][] { new InterfaceTests.Unique[] { result.values[0], result.values[0] }, new InterfaceTests.Unique[] { result.values[1] }, new InterfaceTests.Unique[] { result.values[2], result.values[3], result.values[4] }, new InterfaceTests.Unique[] { result.values[5], result.values[6] }, new InterfaceTests.Unique[] { result.values[6] } },
                new InterfaceTests.Unique("foo"), new InterfaceTests.Unique("bar"), null, null);

            for (int i = 0; i < result.keys.Length; ++i) {
                if (result.keys[i] != null)
                    Assert.IsFalse(object.Equals(result.keys[i], d.keys[i]));
            }

            for (int i = 0; i < result.values.Length; ++i) {
                if (result.values[i] != null)
                    Assert.IsFalse(object.Equals(result.values[i], d.values[i]));
            }
        }
        
    }
}

www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.