File: Utilities\ValueSetTests.cs
Web Access
Project: src\src\Compilers\CSharp\Test\Semantic\Microsoft.CodeAnalysis.CSharp.Semantic.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Semantic.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
#nullable disable
 
using System;
using Xunit;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
    using static BinaryOperatorKind;
    using static Microsoft.CodeAnalysis.CSharp.ValueSetFactory;
 
    /// <summary>
    /// Test some internal implementation data structures used in <see cref="DecisionDagBuilder"/>.
    /// </summary>
    public class ValueSetTests
    {
        private static readonly Random Random = new Random();
 
        [Theory]
        [InlineData(0)]
        [InlineData(1)]
        [InlineData(2)]
        [InlineData(3)]
        [InlineData(4)]
        [InlineData(-1)]
        [InlineData(-2)]
        [InlineData(-3)]
        [InlineData(-4)]
        [InlineData(int.MinValue)]
        [InlineData(int.MaxValue)]
        public void TestGE_01(int i1)
        {
            IValueSet<int> values = ForInt.Related(GreaterThanOrEqual, i1);
            Assert.Equal($"[{i1}..{int.MaxValue}]", values.ToString());
        }
 
        [Fact]
        public void TestGE_02()
        {
            for (int i = 0; i < 100; i++)
            {
                int i1 = Random.Next(int.MinValue, int.MaxValue);
                IValueSet<int> values = ForInt.Related(GreaterThanOrEqual, i1);
                Assert.Equal($"[{i1}..{int.MaxValue}]", values.ToString());
            }
        }
 
        [Theory]
        [InlineData(0)]
        [InlineData(1)]
        [InlineData(2)]
        [InlineData(3)]
        [InlineData(4)]
        [InlineData(-1)]
        [InlineData(-2)]
        [InlineData(-3)]
        [InlineData(-4)]
        [InlineData(int.MinValue)]
        [InlineData(int.MaxValue)]
        public void TestGT_01(int i1)
        {
            IValueSet<int> values = ForInt.Related(GreaterThan, i1);
            Assert.Equal((i1 == int.MaxValue) ? "" : $"[{i1 + 1}..{int.MaxValue}]", values.ToString());
        }
 
        [Fact]
        public void TestGT_02()
        {
            for (int i = 0; i < 100; i++)
            {
                int i1 = Random.Next(int.MinValue, int.MaxValue);
                IValueSet<int> values = ForInt.Related(GreaterThan, i1);
                Assert.Equal($"[{i1 + 1}..{int.MaxValue}]", values.ToString());
            }
        }
 
        [Theory]
        [InlineData(0)]
        [InlineData(1)]
        [InlineData(2)]
        [InlineData(3)]
        [InlineData(4)]
        [InlineData(-1)]
        [InlineData(-2)]
        [InlineData(-3)]
        [InlineData(-4)]
        [InlineData(int.MinValue)]
        [InlineData(int.MaxValue)]
        public void TestLE_01(int i1)
        {
            IValueSet<int> values = ForInt.Related(LessThanOrEqual, i1);
            Assert.Equal($"[{int.MinValue}..{i1}]", values.ToString());
        }
 
        [Fact]
        public void TestLE_02()
        {
            for (int i = 0; i < 100; i++)
            {
                int i1 = Random.Next(int.MinValue, int.MaxValue) + 1;
                IValueSet<int> values = ForInt.Related(LessThanOrEqual, i1);
                Assert.Equal($"[{int.MinValue}..{i1}]", values.ToString());
            }
        }
 
        [Theory]
        [InlineData(0)]
        [InlineData(1)]
        [InlineData(2)]
        [InlineData(3)]
        [InlineData(4)]
        [InlineData(-1)]
        [InlineData(-2)]
        [InlineData(-3)]
        [InlineData(-4)]
        [InlineData(int.MinValue)]
        [InlineData(int.MaxValue)]
        public void TestLT_01(int i1)
        {
            IValueSet<int> values = ForInt.Related(LessThan, i1);
            Assert.Equal((i1 == int.MinValue) ? "" : $"[{int.MinValue}..{i1 - 1}]", values.ToString());
        }
 
        [Fact]
        public void TestLT_02()
        {
            for (int i = 0; i < 100; i++)
            {
                int i1 = Random.Next(int.MinValue, int.MaxValue) + 1;
                IValueSet<int> values = ForInt.Related(LessThan, i1);
                Assert.Equal($"[{int.MinValue}..{i1 - 1}]", values.ToString());
            }
        }
 
        [Theory]
        [InlineData(0)]
        [InlineData(1)]
        [InlineData(2)]
        [InlineData(3)]
        [InlineData(4)]
        [InlineData(-1)]
        [InlineData(-2)]
        [InlineData(-3)]
        [InlineData(-4)]
        [InlineData(int.MinValue)]
        [InlineData(int.MaxValue)]
        public void TestEQ_01(int i1)
        {
            IValueSet<int> values = ForInt.Related(Equal, i1);
            Assert.Equal($"[{i1}..{i1}]", values.ToString());
        }
 
        [Fact]
        public void TestEQ_02()
        {
            for (int i = 0; i < 100; i++)
            {
                int i1 = Random.Next(int.MinValue, int.MaxValue);
                IValueSet<int> values = ForInt.Related(Equal, i1);
                Assert.Equal($"[{i1}..{i1}]", values.ToString());
            }
        }
 
        [Fact]
        public void TestIntersect_01()
        {
            for (int i = 0; i < 100; i++)
            {
                int i1 = Random.Next(int.MinValue + 1, int.MaxValue);
                int i2 = Random.Next(int.MinValue, int.MaxValue);
                if (i1 > i2) (i1, i2) = (i2, i1);
                IValueSet<int> values1 = ForInt.Related(GreaterThanOrEqual, i1).Intersect(ForInt.Related(LessThanOrEqual, i2));
                Assert.Equal($"[{i1}..{i2}]", values1.ToString());
                IValueSet<int> values2 = ForInt.Related(LessThanOrEqual, i2).Intersect(ForInt.Related(GreaterThanOrEqual, i1));
                Assert.Equal(values1, values2);
            }
        }
 
        [Fact]
        public void TestIntersect_02()
        {
            for (int i = 0; i < 100; i++)
            {
                int i1 = Random.Next(int.MinValue + 1, int.MaxValue);
                int i2 = Random.Next(int.MinValue, int.MaxValue);
                if (i1 < i2) (i1, i2) = (i2, i1);
                if (i1 == i2) continue;
                IValueSet<int> values1 = ForInt.Related(GreaterThanOrEqual, i1).Intersect(ForInt.Related(LessThanOrEqual, i2));
                Assert.Equal($"", values1.ToString());
                IValueSet<int> values2 = ForInt.Related(LessThanOrEqual, i2).Intersect(ForInt.Related(GreaterThanOrEqual, i1));
                Assert.Equal(values1, values2);
            }
        }
 
        [Fact]
        public void TestUnion_01()
        {
            for (int i = 0; i < 100; i++)
            {
                int i1 = Random.Next(int.MinValue + 1, int.MaxValue);
                int i2 = Random.Next(int.MinValue, int.MaxValue);
                if (i1 > i2) (i1, i2) = (i2, i1);
                if ((i1 + 1) >= i2) continue;
                IValueSet<int> values1 = ForInt.Related(LessThanOrEqual, i1).Union(ForInt.Related(GreaterThanOrEqual, i2));
                Assert.Equal($"[{int.MinValue}..{i1}],[{i2}..{int.MaxValue}]", values1.ToString());
                IValueSet<int> values2 = ForInt.Related(GreaterThanOrEqual, i2).Union(ForInt.Related(LessThanOrEqual, i1));
                Assert.Equal(values1, values2);
            }
        }
 
        [Fact]
        public void TestUnion_02()
        {
            for (int i = 0; i < 100; i++)
            {
                int i1 = Random.Next(int.MinValue + 1, int.MaxValue);
                int i2 = Random.Next(int.MinValue, int.MaxValue);
                if (i1 < i2) (i1, i2) = (i2, i1);
                IValueSet<int> values1 = ForInt.Related(LessThanOrEqual, i1).Union(ForInt.Related(GreaterThanOrEqual, i2));
                Assert.Equal($"[{int.MinValue}..{int.MaxValue}]", values1.ToString());
                IValueSet<int> values2 = ForInt.Related(GreaterThanOrEqual, i2).Union(ForInt.Related(LessThanOrEqual, i1));
                Assert.Equal(values1, values2);
            }
        }
 
        [Fact]
        public void TestComplement_01()
        {
            for (int i = 0; i < 100; i++)
            {
                int i1 = Random.Next(int.MinValue + 1, int.MaxValue);
                int i2 = Random.Next(int.MinValue, int.MaxValue);
                if (i1 > i2) (i1, i2) = (i2, i1);
                if ((i1 + 1) >= i2) continue;
                IValueSet<int> values1 = ForInt.Related(LessThanOrEqual, i1).Union(ForInt.Related(GreaterThanOrEqual, i2));
                Assert.Equal($"[{int.MinValue}..{i1}],[{i2}..{int.MaxValue}]", values1.ToString());
                IValueSet<int> values2 = values1.Complement();
                Assert.Equal(values1, values2.Complement());
                Assert.Equal($"[{i1 + 1}..{i2 - 1}]", values2.ToString());
            }
        }
 
        [Fact]
        public void TestAny_01()
        {
            for (int i = 0; i < 100; i++)
            {
                int i1 = Random.Next(int.MinValue, int.MaxValue);
                int i2 = Random.Next(int.MinValue, int.MaxValue);
                if (i1 > i2) (i1, i2) = (i2, i1);
                IValueSet<int> values = ForInt.Related(GreaterThanOrEqual, i1).Intersect(ForInt.Related(LessThanOrEqual, i2));
                Assert.Equal($"[{i1}..{i2}]", values.ToString());
                test(int.MinValue);
                if (i1 != int.MinValue) test(i1 - 1);
                test(i1);
                test(i1 + 1);
                test(int.MaxValue);
                if (i2 != int.MinValue) test(i2 - 1);
                test(i2);
                test(i2 + 1);
                void test(int val)
                {
                    Assert.Equal(val >= i1 && val <= i2, values.Any(Equal, val));
                    Assert.Equal(val >= i1, values.Any(LessThanOrEqual, val));
                    Assert.Equal(val > i1, values.Any(LessThan, val));
                    Assert.Equal(val <= i2, values.Any(GreaterThanOrEqual, val));
                    Assert.Equal(i2 > val, values.Any(GreaterThan, val));
                }
            }
        }
 
        [Fact]
        public void TestIsEmpty_01()
        {
            for (int i = 0; i < 100; i++)
            {
                int i1 = Random.Next(int.MinValue, int.MaxValue);
                int i2 = Random.Next(int.MinValue, int.MaxValue);
                IValueSet<int> values = ForInt.Related(GreaterThanOrEqual, i1).Intersect(ForInt.Related(LessThanOrEqual, i2));
                Assert.Equal(values.ToString().Length == 0, values.IsEmpty);
            }
        }
 
        [Fact]
        public void TestDouble_01()
        {
            for (int i = 0; i < 100; i++)
            {
                double d1 = Random.NextDouble() * 100 - 50;
                double d2 = Random.NextDouble() * 100 - 50;
                if (d1 > d2) (d1, d2) = (d2, d1);
                IValueSet<double> values = ForDouble.Related(GreaterThanOrEqual, d1).Intersect(ForDouble.Related(LessThanOrEqual, d2));
                Assert.Equal(FormattableString.Invariant($"[{d1:G17}..{d2:G17}]"), values.ToString());
            }
        }
 
        [Fact]
        public void TestChar_01()
        {
            IValueSet<char> gea1 = ForChar.Related(GreaterThanOrEqual, 'a');
            IValueSet<char> lez1 = ForChar.Related(LessThanOrEqual, 'z');
            IValueSet<char> gea2 = ForChar.Related(GreaterThanOrEqual, 'A');
            IValueSet<char> lez2 = ForChar.Related(LessThanOrEqual, 'Z');
            var letters = gea1.Intersect(lez1).Union(gea2.Intersect(lez2));
            Assert.Equal("['A'..'Z'],['a'..'z']", letters.ToString());
        }
 
        [Fact]
        public void TestDouble_02()
        {
            Assert.Equal("[-Inf..-Inf]", ForDouble.Related(LessThan, double.MinValue).ToString());
            var lt = ForDouble.Related(LessThan, 0.0);
            Assert.Equal(FormattableString.Invariant($"[-Inf..{-double.Epsilon:G17}]"), lt.ToString());
            var gt = ForDouble.Related(GreaterThan, 0.0);
            Assert.Equal(FormattableString.Invariant($"[{double.Epsilon:G17}..Inf]"), gt.ToString());
            var eq = ForDouble.Related(Equal, 0.0);
            Assert.Equal("[0..0]", eq.ToString());
            var none = lt.Complement().Intersect(gt.Complement()).Intersect(eq.Complement());
            Assert.Equal("NaN", none.ToString());
            Assert.False(none.IsEmpty);
        }
 
        [Fact]
        public void TestFloat_01()
        {
            Assert.Equal("[-Inf..-Inf]", ForFloat.Related(LessThan, float.MinValue).ToString());
            var lt = ForFloat.Related(LessThan, 0.0f);
            Assert.Equal(FormattableString.Invariant($"[-Inf..{-float.Epsilon:G9}]"), lt.ToString());
            var gt = ForFloat.Related(GreaterThan, 0.0f);
            Assert.Equal(FormattableString.Invariant($"[{float.Epsilon:G9}..Inf]"), gt.ToString());
            var eq = ForFloat.Related(Equal, 0.0f);
            Assert.Equal("[0..0]", eq.ToString());
            var none = lt.Complement().Intersect(gt.Complement()).Intersect(eq.Complement());
            Assert.Equal("NaN", none.ToString());
            Assert.False(none.IsEmpty);
        }
 
        [Fact]
        public void TestDouble_03()
        {
            Assert.Equal("NaN", ForDouble.Related(Equal, double.NaN).ToString());
            Assert.Equal("NaN", ForFloat.Related(Equal, float.NaN).ToString());
            Assert.True(ForDouble.Related(Equal, double.NaN).Any(Equal, double.NaN));
            Assert.True(ForFloat.Related(Equal, float.NaN).Any(Equal, float.NaN));
            Assert.Equal("[Inf..Inf]", ForDouble.Related(Equal, double.PositiveInfinity).ToString());
            Assert.Equal("[Inf..Inf]", ForFloat.Related(Equal, float.PositiveInfinity).ToString());
            Assert.Equal("[-Inf..-Inf]", ForDouble.Related(Equal, double.NegativeInfinity).ToString());
            Assert.Equal("[-Inf..-Inf]", ForFloat.Related(Equal, float.NegativeInfinity).ToString());
        }
 
        [Fact]
        public void TestDouble_04()
        {
            var neg = ForDouble.Related(LessThan, 0.0);
            Assert.True(neg.Any(LessThan, double.MinValue));
            Assert.False(neg.Any(GreaterThan, double.MaxValue));
 
            var mi = ForDouble.Related(Equal, double.NegativeInfinity);
            Assert.True(mi.All(LessThan, 0.0));
            Assert.True(mi.Any(LessThan, 0.0));
            Assert.True(mi.All(LessThanOrEqual, 0.0));
            Assert.True(mi.Any(LessThanOrEqual, 0.0));
            Assert.False(mi.All(GreaterThan, 0.0));
            Assert.False(mi.Any(GreaterThan, 0.0));
            Assert.False(mi.All(GreaterThanOrEqual, 0.0));
            Assert.False(mi.Any(GreaterThanOrEqual, 0.0));
 
            var i = ForDouble.Related(Equal, double.PositiveInfinity);
            Assert.False(i.All(LessThan, 0.0));
            Assert.False(i.Any(LessThan, 0.0));
            Assert.False(i.All(LessThanOrEqual, 0.0));
            Assert.False(i.Any(LessThanOrEqual, 0.0));
            Assert.True(i.All(GreaterThan, 0.0));
            Assert.True(i.Any(GreaterThan, 0.0));
            Assert.True(i.All(GreaterThanOrEqual, 0.0));
            Assert.True(i.Any(GreaterThanOrEqual, 0.0));
        }
 
        [Fact]
        public void TestString_01()
        {
            var notaset = ForString.Related(Equal, "a").Complement();
            var bset = ForString.Related(Equal, "b");
            var intersect = bset.Intersect(notaset);
            Assert.False(intersect.Any(Equal, "c"));
        }
 
        [Fact]
        public void TestBool_Cov_01()
        {
            var t = ForBool.Related(Equal, true);
            var f = ForBool.Related(Equal, false);
            var em = t.Intersect(f);
            Assert.True(em.IsEmpty);
            var q = t.Intersect(t);
            Assert.Same(t, q);
            IValueSet b = t;
            Assert.Same(b.Intersect(b), b);
            Assert.Same(b.Union(b), b);
        }
 
        [Fact]
        public void TestByte_Cov_01()
        {
            var s = ForByte.Related(GreaterThan, 10).Intersect(ForByte.Related(LessThan, 100));
            Assert.Equal("[11..99]", s.ToString());
        }
 
        [Fact]
        public void TestString_Cov_01()
        {
            var s1 = ForString.Related(Equal, "a");
            var s2 = ForString.Related(Equal, "b");
            Assert.True(s1.Intersect(s2).IsEmpty);
            Assert.True(s1.Complement().Union(s2.Complement()).Complement().IsEmpty);
            Assert.Equal(s1.Union(s2).Complement(), s1.Complement().Intersect(s2.Complement()));
            IValueSet b = s1;
            Assert.Same(b.Intersect(b), b);
            Assert.Same(b.Union(b), b);
            Assert.False(s1.Union(s2).All(Equal, "a"));
        }
 
        [Fact]
        public void TestDouble_Cov_01()
        {
            var s1 = ForDouble.Related(LessThan, 3.14d);
            IValueSet b = s1;
            Assert.Same(s1, s1.Intersect(s1));
            Assert.Same(s1, s1.Union(s1));
            var s2 = ForDouble.Related(GreaterThan, 31.4d);
            var s3 = b.Complement().Intersect(s2.Complement());
            Assert.Equal("NaN,[3.1400000000000001..31.399999999999999]", s3.ToString());
            var s4 = b.Union(s2).Complement();
            Assert.Equal(s3, s4);
        }
 
        [Fact]
        public void TestLong_Cov_01()
        {
            var s1 = ForLong.Related(LessThan, 2);
            Assert.Equal($"[{long.MinValue}..1]", s1.ToString());
            Assert.True(s1.All(LessThan, 2));
            Assert.True(s1.All(LessThanOrEqual, 1));
            Assert.False(s1.All(GreaterThan, 0));
            Assert.False(s1.All(GreaterThanOrEqual, 0));
            Assert.False(s1.All(Equal, 0));
 
            Assert.False(s1.All(LessThan, -10));
            Assert.False(s1.All(LessThanOrEqual, -10));
            Assert.False(s1.All(GreaterThan, -10));
            Assert.False(s1.All(GreaterThanOrEqual, -10));
            Assert.False(s1.All(Equal, -10));
            Assert.True(s1.All(LessThan, 10));
            Assert.True(s1.All(LessThanOrEqual, 10));
            Assert.False(s1.All(GreaterThan, 10));
            Assert.False(s1.All(GreaterThanOrEqual, 10));
            Assert.False(s1.All(Equal, 10));
 
            var s2 = ForLong.Related(GreaterThan, -5).Intersect(s1);
            Assert.Equal($"[-4..1]", s2.ToString());
            Assert.False(s2.All(LessThan, -10));
            Assert.False(s2.All(LessThanOrEqual, -10));
            Assert.True(s2.All(GreaterThan, -10));
            Assert.True(s2.All(GreaterThanOrEqual, -10));
            Assert.False(s2.All(Equal, -10));
            Assert.True(s2.All(LessThan, 10));
            Assert.True(s2.All(LessThanOrEqual, 10));
            Assert.False(s2.All(GreaterThan, 10));
            Assert.False(s2.All(GreaterThanOrEqual, 10));
            Assert.False(s2.All(Equal, 10));
        }
 
        [Fact]
        public void TestNext_Cov_01()
        {
            Assert.Equal("[10..100]", ForSByte.Related(GreaterThanOrEqual, 10).Intersect(ForSByte.Related(LessThanOrEqual, 100)).ToString());
            Assert.Equal("[10..100]", ForShort.Related(GreaterThanOrEqual, 10).Intersect(ForShort.Related(LessThanOrEqual, 100)).ToString());
            Assert.Equal("[10..100]", ForUInt.Related(GreaterThanOrEqual, 10).Intersect(ForUInt.Related(LessThanOrEqual, 100)).ToString());
            Assert.Equal("[10..100]", ForULong.Related(GreaterThanOrEqual, 10).Intersect(ForULong.Related(LessThanOrEqual, 100)).ToString());
            Assert.Equal("[10..100]", ForUShort.Related(GreaterThanOrEqual, 10).Intersect(ForUShort.Related(LessThanOrEqual, 100)).ToString());
            Assert.Equal("[10..100]", ForFloat.Related(GreaterThanOrEqual, 10).Intersect(ForFloat.Related(LessThanOrEqual, 100)).ToString());
            Assert.Equal("[-100..-10]", ForFloat.Related(GreaterThanOrEqual, -100).Intersect(ForFloat.Related(LessThanOrEqual, -10)).ToString());
            Assert.Equal("[-10..10]", ForFloat.Related(GreaterThanOrEqual, -10).Intersect(ForFloat.Related(LessThanOrEqual, 10)).ToString());
        }
 
        [Fact]
        public void TestAPI_01()
        {
            Assert.Same(ForByte, ForSpecialType(SpecialType.System_Byte));
            Assert.Same(ForSByte, ForSpecialType(SpecialType.System_SByte));
            Assert.Same(ForShort, ForSpecialType(SpecialType.System_Int16));
            Assert.Same(ForUShort, ForSpecialType(SpecialType.System_UInt16));
            Assert.Same(ForInt, ForSpecialType(SpecialType.System_Int32));
            Assert.Same(ForUInt, ForSpecialType(SpecialType.System_UInt32));
            Assert.Same(ForLong, ForSpecialType(SpecialType.System_Int64));
            Assert.Same(ForULong, ForSpecialType(SpecialType.System_UInt64));
            Assert.Same(ForFloat, ForSpecialType(SpecialType.System_Single));
            Assert.Same(ForDouble, ForSpecialType(SpecialType.System_Double));
            Assert.Same(ForString, ForSpecialType(SpecialType.System_String));
            Assert.Same(ForDecimal, ForSpecialType(SpecialType.System_Decimal));
            Assert.Same(ForChar, ForSpecialType(SpecialType.System_Char));
            Assert.Same(ForBool, ForSpecialType(SpecialType.System_Boolean));
            Assert.Same(ForNint, ForSpecialType(SpecialType.System_IntPtr, isNative: true));
            Assert.Same(ForNuint, ForSpecialType(SpecialType.System_UIntPtr, isNative: true));
            Assert.Null(ForSpecialType(SpecialType.System_Enum));
        }
 
        [Fact]
        public void TestDecimalRelations_01()
        {
            Assert.Equal("[-79228162514264337593543950335..-0.0000000000000000000000000001]", ForDecimal.Related(LessThan, 0.0m).ToString());
            Assert.Equal("[-79228162514264337593543950335..0.0000000000000000000000000000]", ForDecimal.Related(LessThanOrEqual, 0.0m).ToString());
            Assert.Equal("[0.0000000000000000000000000001..79228162514264337593543950335]", ForDecimal.Related(GreaterThan, 0.0m).ToString());
            Assert.Equal("[0.0000000000000000000000000000..79228162514264337593543950335]", ForDecimal.Related(GreaterThanOrEqual, 0.0m).ToString());
        }
 
        [Fact]
        public void TestNintRelations_01()
        {
            Assert.Equal("Small,[-2147483648..9]", ForNint.Related(LessThan, 10).ToString());
            Assert.Equal("Small,[-2147483648..10]", ForNint.Related(LessThanOrEqual, 10).ToString());
            Assert.Equal("[11..2147483647],Large", ForNint.Related(GreaterThan, 10).ToString());
            Assert.Equal("[10..2147483647],Large", ForNint.Related(GreaterThanOrEqual, 10).ToString());
        }
 
        [Fact]
        public void TestNuintRelations_01()
        {
            Assert.Equal("[0..9]", ForNuint.Related(LessThan, 10).ToString());
            Assert.Equal("[0..10]", ForNuint.Related(LessThanOrEqual, 10).ToString());
            Assert.Equal("[11..4294967295],Large", ForNuint.Related(GreaterThan, 10).ToString());
            Assert.Equal("[10..4294967295],Large", ForNuint.Related(GreaterThanOrEqual, 10).ToString());
        }
 
        [Fact]
        public void TestDecimalEdges_01()
        {
            for (byte scale = 0; scale < 29; scale++)
            {
                var l = new decimal(~0, ~0, ~0, false, scale);
                check(l);
                l = new decimal(~0, ~0, ~0, true, scale);
                check(l);
            }
 
            for (byte scale = 0; scale < 29; scale++)
            {
                var l = new decimal(unchecked((int)0x99999999), unchecked((int)0x99999999), 0x19999999, false, scale);
                check(l);
                l = new decimal(unchecked((int)0x99999999), unchecked((int)0x99999999), 0x19999999, true, scale);
                check(l);
                l = new decimal(unchecked((int)0x99999998), unchecked((int)0x99999999), 0x19999999, false, scale);
                check(l);
                l = new decimal(unchecked((int)0x99999998), unchecked((int)0x99999999), 0x19999999, true, scale);
                check(l);
                l = new decimal(unchecked((int)0x9999999A), unchecked((int)0x99999999), 0x19999999, false, scale);
                check(l);
                l = new decimal(unchecked((int)0x9999999A), unchecked((int)0x99999999), 0x19999999, true, scale);
                check(l);
            }
 
            for (int high = 0; high < 2; high++)
            {
                for (int mid = 0; mid < 2; mid++)
                {
                    for (int p2 = 0; p2 < 32; p2++)
                    {
                        int low = 1 << p2;
                        var l = new decimal(low, mid, high, false, 28);
                        check(l);
                        l = new decimal(low, mid, high, true, 28);
                        check(l);
                    }
                }
            }
 
            void check(decimal d)
            {
                Assert.False(ForDecimal.Related(LessThan, d).Any(Equal, d));
                Assert.True(ForDecimal.Related(LessThanOrEqual, d).Any(Equal, d));
                Assert.False(ForDecimal.Related(GreaterThan, d).Any(Equal, d));
                Assert.True(ForDecimal.Related(GreaterThanOrEqual, d).Any(Equal, d));
            }
        }
 
        [Fact]
        public void TestNumbers_Fuzz_01()
        {
            var Random = new Random(123445);
 
            foreach (var fac in new IValueSetFactory[] {
                ForByte, ForSByte, ForShort, ForUShort,
                ForInt, ForUInt, ForLong, ForULong,
                ForFloat, ForDouble, ForDecimal, ForNint,
                ForNuint, ForChar, ForLength,
                })
            {
                for (int i = 0; i < 100; i++)
                {
                    var s1 = fac.Random(10, Random);
                    var s2 = fac.Random(10, Random);
                    var u1 = s1.Union(s2);
                    var u2 = s1.Complement().Intersect(s2.Complement()).Complement();
                    Assert.Equal(u1, u2);
                    var i1 = s1.Intersect(s2);
                    var i2 = s1.Complement().Union(s2.Complement()).Complement();
                    Assert.Equal(i1, i2);
                }
            }
        }
 
        [Fact]
        public void TestNumbers_Fuzz_02()
        {
            foreach (var fac in new IValueSetFactory[] {
                ForByte, ForSByte, ForShort, ForUShort,
                ForInt, ForUInt, ForLong, ForULong,
                ForDecimal, ForNint,
                ForNuint, ForChar, ForLength })
            {
                for (int i = 0; i < 100; i++)
                {
                    ConstantValue value = fac.RandomValue(Random);
                    var s1 = fac.Related(LessThan, value);
                    var s2 = fac.Related(GreaterThanOrEqual, value);
                    Assert.Equal(s1.Complement(), s2);
                    Assert.Equal(s2.Complement(), s1);
                    Assert.True(s2.Any(Equal, value));
                    Assert.False(s1.Any(Equal, value));
                    Assert.True(s1.All(LessThan, value));
                    Assert.False(s2.Any(LessThan, value));
                    Assert.True(s2.All(GreaterThanOrEqual, value));
                    Assert.False(s1.Any(GreaterThanOrEqual, value));
 
                    s1 = fac.Related(GreaterThan, value);
                    s2 = fac.Related(LessThanOrEqual, value);
                    Assert.Equal(s1.Complement(), s2);
                    Assert.Equal(s2.Complement(), s1);
                    Assert.True(s2.Any(Equal, value));
                    Assert.False(s1.Any(Equal, value));
                    Assert.True(s1.All(GreaterThan, value));
                    Assert.False(s2.Any(GreaterThan, value));
                    Assert.True(s2.All(LessThanOrEqual, value));
                    Assert.False(s1.Any(LessThanOrEqual, value));
                }
            }
        }
 
        [Fact]
        public void TestString_Fuzz_02()
        {
            for (int i = 0; i < 100; i++)
            {
                var s1 = ForString.Random(9, Random);
                var s2 = ForString.Random(11, Random);
 
                Assert.Equal(s1.Complement().Complement(), s1);
 
                var u1 = s1.Union(s2);
                var u2 = s1.Complement().Intersect(s2.Complement()).Complement();
                var u3 = s2.Union(s1);
                var u4 = s2.Complement().Intersect(s1.Complement()).Complement();
                Assert.Equal(u1, u2);
                Assert.Equal(u1, u3);
                Assert.Equal(u1, u4);
 
                var i1 = s1.Intersect(s2);
                var i2 = s1.Complement().Union(s2.Complement()).Complement();
                var i3 = s2.Intersect(s1);
                var i4 = s2.Complement().Union(s1.Complement()).Complement();
                Assert.Equal(i1, i2);
                Assert.Equal(i1, i3);
                Assert.Equal(i1, i4);
 
                s1 = s1.Complement();
 
                u1 = s1.Union(s2);
                u2 = s1.Complement().Intersect(s2.Complement()).Complement();
                u3 = s2.Union(s1);
                u4 = s2.Complement().Intersect(s1.Complement()).Complement();
                Assert.Equal(u1, u2);
                Assert.Equal(u1, u3);
                Assert.Equal(u1, u4);
 
                i1 = s1.Intersect(s2);
                i2 = s1.Complement().Union(s2.Complement()).Complement();
                i3 = s2.Intersect(s1);
                i4 = s2.Complement().Union(s1.Complement()).Complement();
                Assert.Equal(i1, i2);
                Assert.Equal(i1, i3);
                Assert.Equal(i1, i4);
 
                s2 = s2.Complement();
 
                u1 = s1.Union(s2);
                u2 = s1.Complement().Intersect(s2.Complement()).Complement();
                u3 = s2.Union(s1);
                u4 = s2.Complement().Intersect(s1.Complement()).Complement();
                Assert.Equal(u1, u2);
                Assert.Equal(u1, u3);
                Assert.Equal(u1, u4);
 
                i1 = s1.Intersect(s2);
                i2 = s1.Complement().Union(s2.Complement()).Complement();
                i3 = s2.Intersect(s1);
                i4 = s2.Complement().Union(s1.Complement()).Complement();
                Assert.Equal(i1, i2);
                Assert.Equal(i1, i3);
                Assert.Equal(i1, i4);
            }
        }
 
        [Fact]
        public void TestAnyFuzz_01()
        {
            for (int i = 0; i < 100; i++)
            {
                var s1 = ForInt.Related(BinaryOperatorKind.Equal, i);
                Assert.True(s1.Any(LessThan, i + 1));
                Assert.False(s1.Any(LessThan, i));
                Assert.False(s1.Any(LessThan, i - 1));
                Assert.True(s1.Any(LessThanOrEqual, i + 1));
                Assert.True(s1.Any(LessThanOrEqual, i));
                Assert.False(s1.Any(LessThanOrEqual, i - 1));
                Assert.False(s1.Any(GreaterThan, i + 1));
                Assert.False(s1.Any(GreaterThan, i));
                Assert.True(s1.Any(GreaterThan, i - 1));
                Assert.False(s1.Any(GreaterThanOrEqual, i + 1));
                Assert.True(s1.Any(GreaterThanOrEqual, i));
                Assert.True(s1.Any(GreaterThanOrEqual, i - 1));
            }
        }
 
        [Fact]
        public void TestAnyFuzz_02()
        {
            for (int i = 0; i < 100; i++)
            {
                int j = Random.Next();
                var s1 = ForInt.Related(BinaryOperatorKind.Equal, j);
                Assert.True(s1.Any(LessThan, j + 1));
                Assert.False(s1.Any(LessThan, j));
                Assert.False(s1.Any(LessThan, j - 1));
                Assert.True(s1.Any(LessThanOrEqual, j + 1));
                Assert.True(s1.Any(LessThanOrEqual, j));
                Assert.False(s1.Any(LessThanOrEqual, j - 1));
                Assert.False(s1.Any(GreaterThan, j + 1));
                Assert.False(s1.Any(GreaterThan, j));
                Assert.True(s1.Any(GreaterThan, j - 1));
                Assert.False(s1.Any(GreaterThanOrEqual, j + 1));
                Assert.True(s1.Any(GreaterThanOrEqual, j));
                Assert.True(s1.Any(GreaterThanOrEqual, j - 1));
            }
        }
 
        [Fact]
        public void TestAllFuzz_01()
        {
            for (int i = 0; i < 100; i++)
            {
                var s1 = ForInt.Related(BinaryOperatorKind.LessThan, i);
                Assert.True(s1.All(LessThan, i + 1));
                Assert.True(s1.All(LessThan, i));
                Assert.False(s1.All(LessThan, i - 1));
                Assert.True(s1.All(LessThanOrEqual, i + 1));
                Assert.True(s1.All(LessThanOrEqual, i));
                Assert.True(s1.All(LessThanOrEqual, i - 1));
                Assert.False(s1.All(LessThanOrEqual, i - 2));
                s1 = ForInt.Related(BinaryOperatorKind.GreaterThan, i);
                Assert.False(s1.All(GreaterThan, i + 1));
                Assert.True(s1.All(GreaterThan, i));
                Assert.True(s1.All(GreaterThan, i - 1));
                Assert.False(s1.All(GreaterThanOrEqual, i + 2));
                Assert.True(s1.All(GreaterThanOrEqual, i + 1));
                Assert.True(s1.All(GreaterThanOrEqual, i));
                Assert.True(s1.All(GreaterThanOrEqual, i - 1));
            }
        }
 
        [Fact]
        public void TestAllFuzz_02()
        {
            for (int i = 0; i < 100; i++)
            {
                int j = Random.Next(0, int.MaxValue - 1);
                var s1 = ForInt.Related(BinaryOperatorKind.LessThan, j);
                Assert.True(s1.All(LessThan, j + 1));
                Assert.True(s1.All(LessThan, j));
                Assert.False(s1.All(LessThan, j - 1));
                Assert.True(s1.All(LessThanOrEqual, j + 1));
                Assert.True(s1.All(LessThanOrEqual, j));
                Assert.True(s1.All(LessThanOrEqual, j - 1));
                Assert.False(s1.All(LessThanOrEqual, j - 2));
                s1 = ForInt.Related(BinaryOperatorKind.GreaterThan, j);
                Assert.False(s1.All(GreaterThan, j + 1));
                Assert.True(s1.All(GreaterThan, j));
                Assert.True(s1.All(GreaterThan, j - 1));
                Assert.False(s1.All(GreaterThanOrEqual, j + 2));
                Assert.True(s1.All(GreaterThanOrEqual, j + 1));
                Assert.True(s1.All(GreaterThanOrEqual, j));
                Assert.True(s1.All(GreaterThanOrEqual, j - 1));
            }
        }
 
        [Fact]
        public void TestAllFuzz_03()
        {
            for (int i = 0; i < 100; i++)
            {
                var s1 = ForInt.Related(BinaryOperatorKind.Equal, i);
                Assert.True(s1.All(LessThan, i + 1));
                Assert.False(s1.All(LessThan, i));
                Assert.False(s1.All(LessThan, i - 1));
                Assert.True(s1.All(LessThanOrEqual, i + 1));
                Assert.True(s1.All(LessThanOrEqual, i));
                Assert.False(s1.All(LessThanOrEqual, i - 1));
                Assert.False(s1.All(GreaterThan, i + 1));
                Assert.False(s1.All(GreaterThan, i));
                Assert.True(s1.All(GreaterThan, i - 1));
                Assert.False(s1.All(GreaterThanOrEqual, i + 1));
                Assert.True(s1.All(GreaterThanOrEqual, i));
                Assert.True(s1.All(GreaterThanOrEqual, i - 1));
            }
        }
 
        [Fact]
        public void TestAllFuzz_04()
        {
            for (int i = 0; i < 100; i++)
            {
                int j = Random.Next(0, int.MaxValue - 1);
                var s1 = ForInt.Related(BinaryOperatorKind.Equal, j);
                Assert.True(s1.All(LessThan, j + 1));
                Assert.False(s1.All(LessThan, j));
                Assert.False(s1.All(LessThan, j - 1));
                Assert.True(s1.All(LessThanOrEqual, j + 1));
                Assert.True(s1.All(LessThanOrEqual, j));
                Assert.False(s1.All(LessThanOrEqual, j - 1));
                Assert.False(s1.All(GreaterThan, j + 1));
                Assert.False(s1.All(GreaterThan, j));
                Assert.True(s1.All(GreaterThan, j - 1));
                Assert.False(s1.All(GreaterThanOrEqual, j + 1));
                Assert.True(s1.All(GreaterThanOrEqual, j));
                Assert.True(s1.All(GreaterThanOrEqual, j - 1));
            }
        }
 
        [Fact]
        public void DoNotCrashOnBadInput()
        {
            // For error recovery, do not throw exceptions on bad inputs.
            var ctors = new IValueSetFactory[]
            {
                    ForByte,
                    ForSByte,
                    ForChar,
                    ForShort,
                    ForUShort,
                    ForInt,
                    ForUInt,
                    ForLong,
                    ForULong,
                    ForBool,
                    ForFloat,
                    ForDouble,
                    ForString,
                    ForDecimal,
                    ForNint,
                    ForNuint,
                    ForLength,
            };
            ConstantValue badConstant = ConstantValue.Bad;
            foreach (IValueSetFactory fac in ctors)
            {
                foreach (BinaryOperatorKind relation in new[] { LessThan, Equal, NotEqual })
                {
                    IValueSet set = fac.Related(relation, badConstant);
                    _ = set.All(relation, badConstant);
                    _ = set.Any(relation, badConstant);
                }
            }
        }
    }
}