PageRenderTime 49ms CodeModel.GetById 11ms app.highlight 31ms RepoModel.GetById 1ms app.codeStats 0ms

/DLR_Main/Languages/IronPython/IronPythonTest/LightExceptionTests.cs

https://bitbucket.org/mdavid/dlr
C# | 318 lines | 262 code | 41 blank | 15 comment | 22 complexity | ae8d9a49a9995a02f2d592b88b39e404 MD5 | raw file
  1/* ****************************************************************************
  2 *
  3 * Copyright (c) Microsoft Corporation. 
  4 *
  5 * This source code is subject to terms and conditions of the Apache License, Version 2.0. A 
  6 * copy of the license can be found in the License.html file at the root of this distribution. If 
  7 * you cannot locate the  Apache License, Version 2.0, please send an email to 
  8 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
  9 * by the terms of the Apache License, Version 2.0.
 10 *
 11 * You must not remove this notice, or any other, from this software.
 12 *
 13 *
 14 * ***************************************************************************/
 15
 16#if !CLR2
 17using System.Linq.Expressions;
 18using Microsoft.Scripting.Ast;
 19#else
 20using Microsoft.Scripting.Ast;
 21#endif
 22
 23using System;
 24using System.Collections.Generic;
 25using System.Dynamic;
 26using System.Runtime.CompilerServices;
 27
 28using Microsoft.Scripting.Generation;
 29using Microsoft.Scripting.Utils;
 30
 31using IronPython.Runtime;
 32using System.Reflection;
 33using Microsoft.Scripting.Runtime;
 34using Microsoft.Scripting.Actions;
 35
 36namespace IronPythonTest {
 37    class LightExceptionTests {
 38        private Func<LightExceptionTests, IEnumerable<Expression>>[] StatementBuilders = new[] { 
 39            new Func<LightExceptionTests, IEnumerable<Expression>>(TryCatchBuilder), 
 40            new Func<LightExceptionTests, IEnumerable<Expression>>(TryFinallyBuilder), 
 41            new Func<LightExceptionTests, IEnumerable<Expression>>(ThrowBuilder), 
 42            new Func<LightExceptionTests, IEnumerable<Expression>>(CallBuilder), 
 43            new Func<LightExceptionTests, IEnumerable<Expression>>(ReturnBuilder), 
 44        };
 45        private static ParameterExpression _input = Expression.Parameter(typeof(List<string>), "log");
 46        private static MethodInfo _addLog = typeof(List<string>).GetMethod("Add");
 47        private static LabelTarget _ret = Expression.Label(typeof(object), "return");
 48        private static Expression[] _catchExtras = new[] { (Expression)Expression.Default(typeof(void)), Expression.Rethrow() };
 49
 50        public static void RunTests() {
 51            var param = Expression.Parameter(typeof(Exception), "foo");
 52            var lambdax = Expression.Lambda<Func<object>>(
 53                Expression.Block(
 54                    LightExceptions.RewriteExternal(
 55                        Expression.TryCatch(
 56                            Expression.Default(typeof(object)),
 57                            Expression.Catch(param, Expression.Default(typeof(object)))
 58                        )
 59                    ),
 60                    LightExceptions.RewriteExternal(
 61                        Expression.TryCatch(
 62                            Expression.Default(typeof(object)),
 63                            Expression.Catch(param, Expression.Default(typeof(object)))
 64                        )
 65                    )
 66                )
 67            );
 68
 69            lambdax.Compile()();
 70            CompilerHelpers.LightCompile(lambdax)();
 71
 72            var builder = new LightExceptionTests();
 73            List<string> record = new List<string>();
 74            List<string> rewriteRecord = new List<string>();
 75            int testCount = 0;
 76            try {                
 77                foreach (var lambda in builder.MakeLambda()) {
 78                    // run each test in normal and lightweight exception modes, make sure they have the same result
 79                    try {
 80                        
 81                        object res = lambda.Compile()(record);
 82                        if (res != null) {
 83                            record.Add(res.ToString());
 84                        }
 85                    } catch (Exception e) {
 86                        record.Add(String.Format("EXCEPTION {0}", e.GetType()));
 87                    }
 88
 89                    try {
 90                        object res = ((Expression<Func<List<string>, object>>)LightExceptions.Rewrite(lambda)).Compile()(rewriteRecord);
 91                        Exception e = LightExceptions.GetLightException(res);
 92                        if (e != null) {
 93                            rewriteRecord.Add(String.Format("EXCEPTION {0}", e.GetType()));
 94                        } else if (res != null) {
 95                            rewriteRecord.Add(res.ToString());
 96                        }
 97                    } catch (Exception e) {
 98                        rewriteRecord.Add(String.Format("EXCEPTION {0}", e.GetType()));
 99                    }
100
101                    if (record.Count != rewriteRecord.Count) {
102                        PrintLambda(lambda, record, rewriteRecord);
103                        throw new Exception("Records differ in length");
104                    }
105                    for (int i = 0; i < record.Count; i++) {
106                        if (record[i] != rewriteRecord[i]) {
107                            PrintLambda(lambda, record, rewriteRecord);
108                            throw new Exception("Records differ");
109                        }
110                    }
111
112                    record.Clear();
113                    rewriteRecord.Clear();
114                    testCount++;
115                }
116            } finally {
117                Console.Write("Ran {0} tests", testCount);
118            }
119        }
120        
121        private static void PrintLambda(Expression<Func<List<string>, object>> lambda, List<string> record, List<string> rewriteRecord) {
122            for (int i = 0; i < Math.Min(record.Count, rewriteRecord.Count); i++) {
123                Console.WriteLine(record[i]);
124                Console.WriteLine(rewriteRecord[i]);
125                Console.WriteLine();
126            }
127#if CLR2
128            Console.WriteLine("Before: " + Environment.NewLine + lambda.DebugView);
129            Console.WriteLine("After: " + Environment.NewLine + LightExceptions.Rewrite(lambda).DebugView);
130#endif
131        }
132
133        private int _depth = 0;
134
135        private IEnumerable<Expression<Func<List<string>, object>>> MakeLambda() {
136            foreach (var expr in GetStatements()) {
137                var res = expr;
138                if (res.Type != typeof(object)) {
139                    res = Expression.Block(expr, Expression.Default(typeof(object)));
140                }
141                yield return Expression.Lambda<Func<List<string>, object>>(
142                    Expression.Label(_ret, res),
143                    _input
144                );
145            }
146        }
147
148        public IEnumerable<Expression> GetStatements() {
149            if (_depth < 2) {
150                foreach (var func in StatementBuilders) {
151                    foreach (var expr in func(this)) { yield return expr; }
152                }
153            }
154        }
155
156        private static Expression AddLogging(Expression expr, string log) {
157            return Expression.Block(
158                Expression.Call(
159                    _input,
160                    _addLog,
161                    Expression.Constant(log)
162                ),
163                expr
164            );
165        }
166
167        private static IEnumerable<Expression> ReturnBuilder(LightExceptionTests self) {
168            yield return Expression.Return(_ret, Expression.Default(typeof(object)));
169        }
170
171        private static IEnumerable<Expression> TryCatchBuilder(LightExceptionTests self) {
172            using (new DepthHolder(self)) {
173                foreach (var body in self.GetStatements()) {
174                    foreach (var handler in self.GetStatements()) {
175                        for (int i = 0; i < _catchExtras.Length; i++) {
176                            var extra = _catchExtras[i];
177
178                            yield return AddLogging(
179                                Expression.TryCatch(
180                                    Expression.Block(typeof(void), body),
181                                    Expression.Catch(
182                                        typeof(Exception),
183                                        AddLogging(Expression.Block(typeof(void), handler, extra), "catch " + i)
184                                    )
185                                ),
186                                "try"
187                            );
188
189                            yield return AddLogging(
190                                Expression.TryCatch(
191                                    Expression.Block(typeof(void), body),
192                                    Expression.Catch(
193                                        typeof(InvalidOperationException),
194                                        AddLogging(Expression.Block(typeof(void), handler, extra), "invalidEx catch 1 " + i)
195                                    )
196                                ),
197                                "try"
198                            );
199
200                            yield return AddLogging(
201                                Expression.TryCatch(
202                                    Expression.Block(typeof(void), body),
203                                    Expression.Catch(
204                                        typeof(InvalidOperationException),
205                                        AddLogging(Expression.Block(typeof(void), handler, extra), "invalidEx catch 2 " + i)
206                                    ),
207                                    Expression.Catch(
208                                        typeof(InvalidOperationException),
209                                        AddLogging(Expression.Block(typeof(void), handler, extra), "catch " + i)
210                                    )
211                                ),
212                                "try"
213                            );
214                        }
215
216                    }
217                }
218            }
219        }
220
221        private static IEnumerable<Expression> TryFinallyBuilder(LightExceptionTests self) {
222            using (new DepthHolder(self)) {
223                foreach (var body in self.GetStatements()) {
224                    foreach (var handler in self.GetStatements()) {
225                        yield return Expression.TryFinally(AddLogging(body, "try finally"), AddLogging(handler, "finally"));
226                    }
227                }
228            }
229        }
230
231        private static IEnumerable<Expression> ThrowBuilder(LightExceptionTests self) {
232            yield return AddLogging(Expression.Throw(Expression.New(typeof(Exception))), "throw ex");
233            yield return AddLogging(Expression.Throw(Expression.New(typeof(InvalidOperationException))), "throw invalidEx");
234        }
235
236        private static IEnumerable<Expression> CallBuilder(LightExceptionTests self) {
237            yield return AddLogging(LightExceptions.CheckAndThrow(Expression.Call(typeof(LightExceptionTests).GetMethod("SomeCall"))), "call");
238            yield return AddLogging(Expression.Call(typeof(LightExceptionTests).GetMethod("ThrowingCall")), "call throw");
239            yield return AddLogging(Expression.Call(typeof(LightExceptionTests).GetMethod("ThrowingCallInvalidOp")), "call throw invalidop");
240            yield return AddLogging(LightExceptions.CheckAndThrow(Expression.Call(typeof(LightExceptionTests).GetMethod("LightThrowingCall"))), "call throw");
241            yield return AddLogging(LightExceptions.CheckAndThrow(Expression.Call(typeof(LightExceptionTests).GetMethod("LightThrowingCallInvalidOp"))), "call throw invalidop");
242            yield return AddLogging(Expression.Dynamic(new LightExBinder("test", false), typeof(object), Expression.Constant(42)), "dynamic throw");
243            yield return AddLogging(
244                Expression.Dynamic(new LightExBinder("test", false), typeof(object), 
245                Expression.Dynamic(new LightExBinder("foo", false), typeof(object), Expression.Constant(42))), "dynamic nothrow");
246        }
247
248        public static object SomeCall() {
249            return null;
250        }
251
252        public static object ThrowingCall() {
253            throw new Exception();
254        }
255
256        public static object ThrowingCallInvalidOp() {
257            throw new InvalidOperationException();
258        }
259
260        public static object LightThrowingCall() {
261            return LightExceptions.Throw(new Exception());
262        }
263
264        public static object LightThrowingCallInvalidOp() {
265            return LightExceptions.Throw(new InvalidOperationException());
266        }
267
268        struct DepthHolder : IDisposable {
269            private LightExceptionTests Builder;
270            public DepthHolder(LightExceptionTests builder) {
271                Builder = builder;
272                builder._depth++;
273            }
274
275            public void Dispose() {
276                Builder._depth--;
277            }
278        }
279
280        class LightExBinder : GetMemberBinder, ILightExceptionBinder {
281            private bool _supportsLightEx;
282            public LightExBinder(string name, bool supportsLightEx)
283                : base(name, false) {
284                _supportsLightEx = supportsLightEx;
285            }
286
287            public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion) {
288                var ex = Expression.New(typeof(MissingMemberException));
289                Expression body;
290                if (Name == "foo") {
291                    body = target.Expression;
292                } else if (_supportsLightEx) {
293                    body = LightExceptions.Throw(ex, typeof(object));
294                } else {
295                    body = Expression.Throw(ex, typeof(object));
296                }
297
298                return new DynamicMetaObject(
299                    body,
300                    BindingRestrictions.GetTypeRestriction(target.Expression, target.Value.GetType())
301                );
302            }
303
304            #region ILightExceptionBinder Members
305
306            public bool SupportsLightThrow {
307                get { return _supportsLightEx; }
308            }
309
310            public CallSiteBinder GetLightExceptionBinder() {
311                return new LightExBinder(Name, true);
312            }
313
314            #endregion
315        }
316
317    }
318}