public void AffineHash_Hash_Rejects_Invalid_Arguments()
        {
            var cases = new[]
            {
                new { arguments = new object[] { null }, types = new Type[] { typeof(byte[]) }, expected = typeof(ArgumentNullException) },
                new { arguments = new object[] { null }, types = new Type[] { typeof(char[]) }, expected = typeof(ArgumentNullException) },
                new { arguments = new object[] { null }, types = new Type[] { typeof(string) }, expected = typeof(ArgumentNullException) },
                new { arguments = new object[] { null, 0, 0 }, types = new Type[] { typeof(byte[]), typeof(int), typeof(int) }, expected = typeof(ArgumentNullException) },
                new { arguments = new object[] { null, 0, 0 }, types = new Type[] { typeof(char[]), typeof(int), typeof(int) }, expected = typeof(ArgumentNullException) },
                new { arguments = new object[] { null, 0, 0 }, types = new Type[] { typeof(string), typeof(int), typeof(int) }, expected = typeof(ArgumentNullException) },
                new { arguments = new object[] { new byte[10], -1, 5 }, types = (Type[])null, expected = typeof(ArgumentOutOfRangeException) },
                new { arguments = new object[] { new byte[10], 10, 5 }, types = (Type[])null, expected = typeof(ArgumentOutOfRangeException) },
                new { arguments = new object[] { new byte[10], 5, -1 }, types = (Type[])null, expected = typeof(ArgumentOutOfRangeException) },
                new { arguments = new object[] { new byte[10], 5, 6 }, types = (Type[])null, expected = typeof(ArgumentOutOfRangeException) },
                new { arguments = new object[] { new char[10], -1, 5 }, types = (Type[])null, expected = typeof(ArgumentOutOfRangeException) },
                new { arguments = new object[] { new char[10], 10, 5 }, types = (Type[])null, expected = typeof(ArgumentOutOfRangeException) },
                new { arguments = new object[] { new char[10], 5, -1 }, types = (Type[])null, expected = typeof(ArgumentOutOfRangeException) },
                new { arguments = new object[] { new char[10], 5, 6 }, types = (Type[])null, expected = typeof(ArgumentOutOfRangeException) },
                new { arguments = new object[] { "1234567890", -1, 5 }, types = (Type[])null, expected = typeof(ArgumentOutOfRangeException) },
                new { arguments = new object[] { "1234567890", 10, 5 }, types = (Type[])null, expected = typeof(ArgumentOutOfRangeException) },
                new { arguments = new object[] { "1234567890", 5, -1 }, types = (Type[])null, expected = typeof(ArgumentOutOfRangeException) },
                new { arguments = new object[] { "1234567890", 5, 6 }, types = (Type[])null, expected = typeof(ArgumentOutOfRangeException) },
            };
            AffineHash target = new AffineHash(1L, 0L);

            for (int i = 0; i < cases.Length; i++)
            {
                var      c      = cases[i];
                Type[]   types  = c.types ?? c.arguments.Select(a => a.GetType()).ToArray();
                Delegate method = AffineHashTests.HashDelegate(target, types);
                try
                {
                    object result = method.DynamicInvoke(c.arguments);
                    Assert.Fail("index: {0}, return: {1}", i, result);
                }
                catch (TargetInvocationException ex)
                {
                    Assert.AreEqual(c.expected, ex.InnerException.GetType(), "index: {0}", i);
                }
                catch (Exception ex)
                {
                    Assert.Fail("index: {0}, exception: {1}", i, ex);
                }
            }
        }
        /// <summary>
        /// Asserts that the distribution of hash values is uniform for a given set of data.
        /// </summary>
        /// <typeparam name="T">The type of data to hash.</typeparam>
        /// <param name="target">The target hash algorithm.</param>
        /// <param name="values">The values to hash.</param>
        private static void AssertHashDistribution <T>(AffineHash target, IEnumerable <T> values)
        {
            Distribution        distribution = new Distribution();
            Dictionary <int, T> hashes       = new Dictionary <int, T>();
            Func <T, int>       method       = (Func <T, int>)AffineHashTests.HashDelegate(target, typeof(T));

            foreach (T value in values)
            {
                int hash = method(value);
                distribution.Observe(hash);
                if (hashes.ContainsKey(hash))
                {
                    Assert.Fail("scale:{0}, shift:{1}, hash:{2}, original:{3}, collision:{4}", target.Scale, target.Shift, hash, hashes[hash], value);
                }
                else
                {
                    hashes.Add(hash, value);
                }
            }

            double ks = distribution.Finish();

            Assert.IsTrue(ks < 0.1D, "scale:{0}, shift:{1}, ks:{2}", target.Scale, target.Shift, ks);
        }