From 5390a66eb8be20863535c5c3378d880e95ccee34 Mon Sep 17 00:00:00 2001 From: Jon Hanna Date: Wed, 4 Jan 2017 01:45:36 +0000 Subject: Fill some gaps in S.L.Expression testing (#14464) * Fill some testing gaps related to array expressions. * Test TypeAs expressions between nullables. * Test fault and finally after many such blocks (catch regressions in a non-optimised path hit in this case). --- .../tests/Array/ArrayAccessTests.cs | 44 +++++++++++++ .../tests/Array/ArrayIndexTests.cs | 52 ++++++++++++++++ .../tests/Cast/AsNullable.cs | 72 ++++++++++++++++++++++ .../ExceptionHandlingExpressions.cs | 28 +++++++++ 4 files changed, 196 insertions(+) (limited to 'src') diff --git a/src/System.Linq.Expressions/tests/Array/ArrayAccessTests.cs b/src/System.Linq.Expressions/tests/Array/ArrayAccessTests.cs index df6dc385d0..8ae11e8660 100644 --- a/src/System.Linq.Expressions/tests/Array/ArrayAccessTests.cs +++ b/src/System.Linq.Expressions/tests/Array/ArrayAccessTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections.Generic; using System.Reflection; using Xunit; @@ -9,6 +10,8 @@ namespace System.Linq.Expressions.Tests { public static class ArrayAccessTests { + private static IEnumerable Ranks() => Enumerable.Range(1, 5).Select(i => new object[] {i}); + [Theory] [ClassData(typeof(CompilationTypes))] public static void ArrayAccess_MultiDimensionalOf1(bool useInterpreter) @@ -73,5 +76,46 @@ namespace System.Linq.Expressions.Tests MemberExpression index = Expression.Property(null, typeof(Unreadable).GetProperty(nameof(Unreadable.WriteOnly))); Assert.Throws("indexes", () => Expression.ArrayAccess(instance, index)); } + + [Theory, ClassData(typeof(CompilationTypes))] + public static void NonZeroBasedOneDimensionalArrayAccess(bool useInterpreter) + { + Array arrayObj = Array.CreateInstance(typeof(int), new[] { 3 }, new[] { -1 }); + arrayObj.SetValue(5, -1); + arrayObj.SetValue(6, 0); + arrayObj.SetValue(7, 1); + ConstantExpression array = Expression.Constant(arrayObj); + IndexExpression indexM1 = Expression.ArrayAccess(array, Expression.Constant(-1)); + IndexExpression index0 = Expression.ArrayAccess(array, Expression.Constant(0)); + IndexExpression index1 = Expression.ArrayAccess(array, Expression.Constant(1)); + Action setValues = Expression.Lambda( + Expression.Block( + Expression.Assign(indexM1, Expression.Constant(5)), + Expression.Assign(index0, Expression.Constant(6)), + Expression.Assign(index1, Expression.Constant(7)))).Compile(useInterpreter); + setValues(); + Assert.Equal(5, arrayObj.GetValue(-1)); + Assert.Equal(6, arrayObj.GetValue(0)); + Assert.Equal(7, arrayObj.GetValue(1)); + Func testValues = Expression.Lambda>( + Expression.And( + Expression.Equal(indexM1, Expression.Constant(5)), + Expression.And( + Expression.Equal(index0, Expression.Constant(6)), + Expression.Equal(index1, Expression.Constant(7))))).Compile(useInterpreter); + Assert.True(testValues()); + } + + [Theory, PerCompilationType(nameof(Ranks))] + public static void DifferentRanks(int rank, bool useInterpreter) + { + Array arrayObj = Array.CreateInstance(typeof(string), Enumerable.Repeat(1, rank).ToArray()); + arrayObj.SetValue("solitary value", Enumerable.Repeat(0, rank).ToArray()); + ConstantExpression array = Expression.Constant(arrayObj); + IEnumerable indices = Enumerable.Repeat(Expression.Default(typeof(int)), rank); + Func func = Expression.Lambda>( + Expression.ArrayAccess(array, indices)).Compile(useInterpreter); + Assert.Equal("solitary value", func()); + } } } diff --git a/src/System.Linq.Expressions/tests/Array/ArrayIndexTests.cs b/src/System.Linq.Expressions/tests/Array/ArrayIndexTests.cs index 7c6a3f1e48..feab3582d6 100644 --- a/src/System.Linq.Expressions/tests/Array/ArrayIndexTests.cs +++ b/src/System.Linq.Expressions/tests/Array/ArrayIndexTests.cs @@ -2769,5 +2769,57 @@ namespace System.Linq.Expressions.Tests Expression index = Expression.Property(null, typeof(Unreadable), nameof(Unreadable.WriteOnly)); Assert.Throws("index", () => Expression.ArrayIndex(array, index)); } + + [Theory, ClassData(typeof(CompilationTypes))] + public static void NonZeroBasedOneDimensionalArrayIndex(bool useInterpreter) + { + Array arrayObj = Array.CreateInstance(typeof(int), new[] { 3 }, new[] { -1 }); + arrayObj.SetValue(5, -1); + arrayObj.SetValue(6, 0); + arrayObj.SetValue(7, 1); + ConstantExpression array = Expression.Constant(arrayObj); + BinaryExpression indexM1 = Expression.ArrayIndex(array, Expression.Constant(-1)); + BinaryExpression index0 = Expression.ArrayIndex(array, Expression.Constant(0)); + BinaryExpression index1 = Expression.ArrayIndex(array, Expression.Constant(1)); + Func testValues = Expression.Lambda>( + Expression.And( + Expression.Equal(indexM1, Expression.Constant(5)), + Expression.And( + Expression.Equal(index0, Expression.Constant(6)), + Expression.Equal(index1, Expression.Constant(7))))).Compile(useInterpreter); + Assert.True(testValues()); + } + + [Theory, ClassData(typeof(CompilationTypes))] + public static void NonZeroBasedOneDimensionalArrayIndexMethod(bool useInterpreter) + { + Array arrayObj = Array.CreateInstance(typeof(int), new[] { 3 }, new[] { -1 }); + arrayObj.SetValue(5, -1); + arrayObj.SetValue(6, 0); + arrayObj.SetValue(7, 1); + ConstantExpression array = Expression.Constant(arrayObj); + MethodCallExpression indexM1 = Expression.ArrayIndex(array, new [] { Expression.Constant(-1)}); + MethodCallExpression index0 = Expression.ArrayIndex(array, new[] { Expression.Constant(0)}); + MethodCallExpression index1 = Expression.ArrayIndex(array, new[] { Expression.Constant(1)}); + Func testValues = Expression.Lambda>( + Expression.And( + Expression.Equal(indexM1, Expression.Constant(5)), + Expression.And( + Expression.Equal(index0, Expression.Constant(6)), + Expression.Equal(index1, Expression.Constant(7))))).Compile(useInterpreter); + Assert.True(testValues()); + } + + [Theory, ClassData(typeof(CompilationTypes))] + public static void HighRankArrayIndex(bool useInterpreter) + { + string[,,,,,,,,,] arrayObj = {{{{{{{{{{"hugz"}}}}}}}}}}; + ConstantExpression array = Expression.Constant(arrayObj); + Func func = Expression.Lambda>( + Expression.ArrayIndex(array, Enumerable.Repeat(Expression.Constant(0), 10))).Compile(useInterpreter); + Assert.Equal("hugz", func()); + } + + } } diff --git a/src/System.Linq.Expressions/tests/Cast/AsNullable.cs b/src/System.Linq.Expressions/tests/Cast/AsNullable.cs index 480b30530a..37c3080235 100644 --- a/src/System.Linq.Expressions/tests/Cast/AsNullable.cs +++ b/src/System.Linq.Expressions/tests/Cast/AsNullable.cs @@ -27,6 +27,46 @@ namespace System.Linq.Expressions.Tests } } + [Theory, ClassData(typeof(CompilationTypes))] + public static void CheckEnumAsNullableEnumTypeTest(bool useInterpreter) + { + E[] array = { 0, E.A, E.B, (E)int.MaxValue, (E)int.MinValue }; + for (int i = 0; i < array.Length; i++) + { + VerifyEnumAsNullableEnumType(array[i], useInterpreter); + } + } + + [Theory, ClassData(typeof(CompilationTypes))] + public static void CheckNullableEnumAsNullableEnumTypeTest(bool useInterpreter) + { + E?[] array = { null, 0, E.A, E.B, (E)int.MaxValue, (E)int.MinValue }; + for (int i = 0; i < array.Length; i++) + { + VerifyNullableEnumAsNullableEnumType(array[i], useInterpreter); + } + } + + [Theory, ClassData(typeof(CompilationTypes))] + public static void CheckLongAsNullableEnumTypeTest(bool useInterpreter) + { + long[] array = { 0, 1, long.MinValue, long.MaxValue }; + foreach (long value in array) + { + VerifyLongAsNullableEnumType(value, useInterpreter); + } + } + + [Theory, ClassData(typeof(CompilationTypes))] + public static void CheckNullableLongAsNullableEnumTypeTest(bool useInterpreter) + { + long?[] array = { null, 0, 1, long.MinValue, long.MaxValue }; + foreach (long? value in array) + { + VerifyNullableLongAsNullableEnumType(value, useInterpreter); + } + } + [Theory, ClassData(typeof(CompilationTypes))] public static void CheckNullableEnumAsObjectTest(bool useInterpreter) { @@ -160,6 +200,38 @@ namespace System.Linq.Expressions.Tests Assert.Equal(value as ValueType, f()); } + private static void VerifyEnumAsNullableEnumType(E value, bool useInterpreter) + { + Expression> e = Expression.Lambda>( + Expression.TypeAs(Expression.Constant(value), typeof(E?))); + Func f = e.Compile(useInterpreter); + Assert.Equal(value, f()); + } + + private static void VerifyNullableEnumAsNullableEnumType(E? value, bool useInterpreter) + { + Expression> e = Expression.Lambda>( + Expression.TypeAs(Expression.Constant(value, typeof(E?)), typeof(E?))); + Func f = e.Compile(useInterpreter); + Assert.Equal(value, f()); + } + + private static void VerifyLongAsNullableEnumType(long value, bool useInterpreter) + { + Expression> e = Expression.Lambda>( + Expression.TypeAs(Expression.Constant(value), typeof(E?))); + Func f = e.Compile(useInterpreter); + Assert.False(f().HasValue); + } + + private static void VerifyNullableLongAsNullableEnumType(long? value, bool useInterpreter) + { + Expression> e = Expression.Lambda>( + Expression.TypeAs(Expression.Constant(value, typeof(long?)), typeof(E?))); + Func f = e.Compile(useInterpreter); + Assert.False(f().HasValue); + } + private static void VerifyNullableEnumAsObject(E? value, bool useInterpreter) { Expression> e = diff --git a/src/System.Linq.Expressions/tests/ExceptionHandling/ExceptionHandlingExpressions.cs b/src/System.Linq.Expressions/tests/ExceptionHandling/ExceptionHandlingExpressions.cs index b47d2cdabe..f57cb5a6da 100644 --- a/src/System.Linq.Expressions/tests/ExceptionHandling/ExceptionHandlingExpressions.cs +++ b/src/System.Linq.Expressions/tests/ExceptionHandling/ExceptionHandlingExpressions.cs @@ -526,6 +526,34 @@ namespace System.Linq.Expressions.Tests FaultTriggeredOnThrow(false); } + [Theory, InlineData(true)] + public void FinallyAndFaultAfterManyLabels(bool useInterpreter) + { + // There is a caching optimisation used below a certain number of faults or + // finally, so go past that to catch any regressions in the non-optimised + // path. + ParameterExpression variable = Expression.Parameter(typeof(int)); + LabelTarget target = Expression.Label(typeof(int)); + BlockExpression block = Expression.Block( + new[] { variable }, + Expression.Assign(variable, Expression.Constant(1)), + Expression.TryCatch( + Expression.Block( + Enumerable.Repeat(Expression.TryFinally(Expression.Empty(), Expression.Empty()), 40).Append( + Expression.TryFault( + Expression.Throw(Expression.Constant(new TestException())), + Expression.Assign(variable, Expression.Constant(2)) + ) + ) + ), + Expression.Catch(typeof(TestException), Expression.Empty()) + ), + Expression.Return(target, variable), + Expression.Label(target, Expression.Default(typeof(int))) + ); + Assert.Equal(2, Expression.Lambda>(block).Compile(useInterpreter)()); + } + [Theory] [ClassData(typeof(CompilationTypes))] public void FinallyTriggeredOnNoThrow(bool useInterpreter) -- cgit v1.2.3