public void ConstantHoister_TypeSeparation()
        {
            var e   = Expression.Add(Expression.Constant(new Bar()), Expression.Constant(new Foo()));
            var res = ConstantHoister.Hoist(e, useDefaultForNull: false);

            Assert.AreEqual(2, res.Environment.Count);
        }
        public void ConstantHoister_ManOrBoy()
        {
#pragma warning disable IDE0079 // The following supression is flagged as unnecessary on .NET Framework (but is required for other targets)
#pragma warning disable CA1845  // Use span-based 'string.Concat' and 'AsSpan' instead of 'Substring'
            var e = (Expression <Func <IEnumerable <int>, IEnumerable <string> > >)(xs => from x in xs let y = x + 1 where y > 0 let s = x.ToString() where !s.EndsWith("Foo") select s.Substring(0, 1) + "Foo");
#pragma warning restore CA1847
#pragma warning restore IDE0079
            var c = ConstantHoister.Hoist(e, useDefaultForNull: false);

            Assert.AreEqual(3, c.Environment.Count);
            Assert.IsTrue(c.Environment.Values.Contains(0));
            Assert.IsTrue(c.Environment.Values.Contains(1));
            Assert.IsTrue(c.Environment.Values.Contains("Foo"));

            var i = (Expression)c.ToInvocation();

            Assert.AreEqual("((Func<int, int, string, Func<IEnumerable<int>, IEnumerable<string>>>)((int @p0, int @p1, string @p2) => (IEnumerable<int> xs) => xs.Select((int x) => new { x, y = x + @p0 }).Where(t => t.y > @p1).Select(t => new { t, s = t.x.ToString() }).Where(t => !t.s.EndsWith(@p2)).Select(t => t.s.Substring(@p1, @p0) + @p2)))(1, 0, \"Foo\")", i.ToCSharpString());
            Assert.AreEqual("int @p0 = 1;\r\nint @p1 = 0;\r\nstring @p2 = \"Foo\";\r\nreturn (IEnumerable<int> xs) => xs.Select((int x) => new { x, y = x + @p0 }).Where(t => t.y > @p1).Select(t => new { t, s = t.x.ToString() }).Where(t => !t.s.EndsWith(@p2)).Select(t => t.s.Substring(@p1, @p0) + @p2);\r\n", c.ToCSharpString());

            var t = c.ToString();
            var u = Regex.Replace(t, @"\<\>f__AnonymousType[\da-fA-F]*", "anon");
            var v = Regex.Replace(u, @"\<\>h__TransparentIdentifier[\da-fA-F]*", "tran");

            Assert.AreEqual("(xs => xs.Select(x => new anon`2(x = x, y = (x + @p0))).Where(tran => (tran.y > @p1)).Select(tran => new anon`2(tran = tran, s = tran.x.ToString())).Where(tran => Not(tran.s.EndsWith(@p2))).Select(tran => (tran.s.Substring(@p1, @p0) + @p2)))[|@p0 : System.Int32 = 1, @p1 : System.Int32 = 0, @p2 : System.String = \"Foo\"|]", v);

            i = AnonymousTypeTupletizer.Tupletize(i, Expression.Constant(value: null));
            i = CompilerGeneratedNameEliminator.Prettify(i);

            var f = i.Evaluate <Func <IEnumerable <int>, IEnumerable <string> > >();
            var g = f(new[] { 123, 234, 987, 876 });
            Assert.IsTrue(new[] { "1Foo", "2Foo", "9Foo", "8Foo" }.SequenceEqual(g));

            Assert.AreEqual(@"Invoke((@p0, @p1, @p2) => xs => xs.Select(x => new Tuple`2(x, (x + @p0))).Where(t => (t.Item2 > @p1)).Select(t => new Tuple`2(t, t.Item1.ToString())).Where(t => Not(t.Item2.EndsWith(@p2))).Select(t => (t.Item2.Substring(@p1, @p0) + @p2)), 1, 0, ""Foo"")", i.ToString());
        }
        public void ConstantHoister_Null1()
        {
            var c   = Expression.Constant(value: null, typeof(string));
            var res = ConstantHoister.Hoist(c, useDefaultForNull: false);

            Assert.AreEqual(1, res.Environment.Count);
            var e = res.Environment.Single();

            Assert.AreEqual(c.Type, e.Key.Type);
            Assert.AreEqual(default(string), e.Value);
        }
        public void ConstantHoister_Null3()
        {
            var c   = Expression.Constant(value: null, typeof(string));
            var res = ConstantHoister.Hoist(c, useDefaultForNull: true);

            Assert.AreEqual(0, res.Environment.Count);
            var e = res.Expression as DefaultExpression;

            Assert.IsNotNull(e);
            Assert.AreEqual(c.Type, e.Type);
        }
        private static ExpressionWithEnvironment HoistAndEval(ConstantHoister h, Expression e)
        {
            var c = h.Hoist(e);

            var i = c.ToInvocation().Evaluate();

            var r = e.Evaluate();

            Assert.AreEqual(r, i);

            return(c);
        }
        private static ExpressionWithEnvironment HoistAndEval(Expression e)
        {
            var c1 = ConstantHoister.Hoist(e, useDefaultForNull: false);
            var c2 = ConstantHoister.Hoist(e, useDefaultForNull: true);

            var i1 = c1.ToInvocation().Evaluate();
            var i2 = c2.ToInvocation().Evaluate();

            var e1 = e.Evaluate();

            Assert.AreEqual(e1, i1);
            Assert.AreEqual(e1, i2);

            return(c1);
        }
 public void ConstantHoister_ArgumentChecking()
 {
     AssertEx.ThrowsException <ArgumentNullException>(() => ConstantHoister.Hoist(expression: null, useDefaultForNull: false), ex => Assert.AreEqual("expression", ex.ParamName));
     AssertEx.ThrowsException <ArgumentNullException>(() => ConstantHoister.Create(useDefaultForNull: false, exclusions: null), ex => Assert.AreEqual("exclusions", ex.ParamName));
     AssertEx.ThrowsException <ArgumentNullException>(() => ConstantHoister.Create(useDefaultForNull: false).Hoist(expression: null), ex => Assert.AreEqual("expression", ex.ParamName));
 }