~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/nrefactory/ICSharpCode.NRefactory.Tests/CSharp/QueryExpressionExpanderTests.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
ļ»æ// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
 
2
// 
 
3
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
 
4
// software and associated documentation files (the "Software"), to deal in the Software
 
5
// without restriction, including without limitation the rights to use, copy, modify, merge,
 
6
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
 
7
// to whom the Software is furnished to do so, subject to the following conditions:
 
8
// 
 
9
// The above copyright notice and this permission notice shall be included in all copies or
 
10
// substantial portions of the Software.
 
11
// 
 
12
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 
13
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 
14
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
 
15
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 
16
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 
17
// DEALINGS IN THE SOFTWARE.
 
18
 
 
19
using System;
 
20
using System.Collections.Generic;
 
21
using System.IO;
 
22
using System.Linq;
 
23
using System.Linq.Expressions;
 
24
using System.Text;
 
25
using System.Text.RegularExpressions;
 
26
using ICSharpCode.NRefactory.CSharp.Parser;
 
27
using ICSharpCode.NRefactory.CSharp.Resolver;
 
28
using NUnit.Framework;
 
29
 
 
30
namespace ICSharpCode.NRefactory.CSharp {
 
31
        [TestFixture]
 
32
        public class QueryExpressionExpanderTests {
 
33
                private dynamic ElementAt(dynamic d, int index) {
 
34
                        int i = 0;
 
35
                        foreach (var o in d) {
 
36
                                if (i++ == index)
 
37
                                        return o;
 
38
                        }
 
39
                        throw new ArgumentException();
 
40
                }
 
41
 
 
42
                private void AssertCorrect(AstNode actual, string expected) {
 
43
                        Assert.That(Regex.Replace(actual.GetText(), @"\s+", "").Replace("<>", ""), Is.EqualTo(Regex.Replace(expected, @"\s+", "")));
 
44
                }
 
45
 
 
46
                private void AssertLookupCorrect<T, U>(IEnumerable<KeyValuePair<T, U>> actual, IList<Tuple<TextLocation, AstNode>> expected) where T : AstNode where U : AstNode {
 
47
                        var actualList = actual.OrderBy(x => x.Key.StartLocation).ThenBy(x => x.Key.GetType().ToString()).ToList();
 
48
                        Assert.That(actualList.Select(x => x.Key.StartLocation).ToList(), Is.EqualTo(expected.Select(x => x.Item1).ToList()));
 
49
                        for (int i = 0; i < actualList.Count; i++) {
 
50
                                Assert.That(actualList[i].Value, Is.Not.SameAs(actualList[i].Key));
 
51
                                Assert.That(actualList[i].Value, Is.SameAs(expected[i].Item2));
 
52
                        }
 
53
                }
 
54
 
 
55
                [Test]
 
56
                public void QueryExpressionWithFromAndSelectWorks() {
 
57
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from a in args select int.Parse(a)");
 
58
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
59
                        AssertCorrect(actual.AstNode, "args.Select(a => int.Parse(a))");
 
60
                        dynamic astNode = actual.AstNode;
 
61
                        AssertLookupCorrect(actual.RangeVariables, new[] { Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Arguments, 0).Parameters, 0)) });
 
62
                        AssertLookupCorrect(actual.Expressions, new[] { Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target), Tuple.Create(new TextLocation(1, 16), actual.AstNode) });
 
63
                }
 
64
 
 
65
                [Test]
 
66
                public void QueryExpressionWithSingleFromAndExplicitTypeWorks() {
 
67
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from object a in args select int.Parse(a)");
 
68
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
69
                        AssertCorrect(actual.AstNode, "args.Cast<object>().Select(a => int.Parse(a))");
 
70
                        dynamic astNode = actual.AstNode;
 
71
                        AssertLookupCorrect(actual.RangeVariables, new[] { Tuple.Create(new TextLocation(1, 13), (AstNode)ElementAt(ElementAt(astNode.Arguments, 0).Parameters, 0)) });
 
72
                        AssertLookupCorrect(actual.Expressions, new[] { Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target), Tuple.Create(new TextLocation(1, 23), actual.AstNode) });
 
73
                }
 
74
 
 
75
                [Test]
 
76
                public void QueryExpressionWithLetWorks() {
 
77
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from a in args let b = int.Parse(a) select a + b.ToString()");
 
78
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
79
                        AssertCorrect(actual.AstNode, "args.Select(a => new { a, b = int.Parse(a) }).Select(x0 => x0.a + x0.b.ToString())");
 
80
                        dynamic astNode = actual.AstNode;
 
81
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
82
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Arguments, 0).Parameters, 0)),
 
83
                                Tuple.Create(new TextLocation(1, 20), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Arguments, 0).Body.Initializers, 1).NameToken),
 
84
                        });
 
85
                        AssertLookupCorrect(actual.Expressions, new[] {
 
86
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target.Target.Target),
 
87
                                Tuple.Create(new TextLocation(1, 16), (AstNode)astNode.Target.Target),
 
88
                                Tuple.Create(new TextLocation(1, 37), actual.AstNode),
 
89
                        });
 
90
                }
 
91
 
 
92
                [Test]
 
93
                public void QueryExpressionWithTwoLetsWorks() {
 
94
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from a in args let b = int.Parse(a) let c = b + 1 select a + b.ToString() + c.ToString()");
 
95
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
96
                        AssertCorrect(actual.AstNode, "args.Select(a => new { a, b = int.Parse(a) }).Select(x0 => new { x0, c = x0.b + 1 }).Select(x1 => x1.x0.a + x1.x0.b.ToString() + x1.c.ToString())");
 
97
                        dynamic astNode = actual.AstNode;
 
98
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
99
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Target.Target.Arguments, 0).Parameters, 0)),
 
100
                                Tuple.Create(new TextLocation(1, 20), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Target.Target.Arguments, 0).Body.Initializers, 1).NameToken),
 
101
                                Tuple.Create(new TextLocation(1, 41), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Arguments, 0).Body.Initializers, 1).NameToken),
 
102
                        });
 
103
                        AssertLookupCorrect(actual.Expressions, new[] {
 
104
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target.Target.Target.Target.Target),
 
105
                                Tuple.Create(new TextLocation(1, 16), (AstNode)astNode.Target.Target.Target.Target),
 
106
                                Tuple.Create(new TextLocation(1, 37), (AstNode)astNode.Target.Target),
 
107
                                Tuple.Create(new TextLocation(1, 51), actual.AstNode),
 
108
                        });
 
109
                }
 
110
 
 
111
                [Test]
 
112
                public void TwoFromClausesFollowedBySelectWorks() {
 
113
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in arr1 from j in arr2 select i + j");
 
114
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
115
                        AssertCorrect(actual.AstNode, "arr1.SelectMany(i => arr2, (i, j) => i + j)");
 
116
                        dynamic astNode = actual.AstNode;
 
117
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
118
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Arguments, 0).Parameters, 0)),
 
119
                                Tuple.Create(new TextLocation(1, 21), (AstNode)ElementAt(ElementAt(astNode.Arguments, 1).Parameters, 1)),
 
120
                        });
 
121
                        AssertLookupCorrect(actual.Expressions, new[] {
 
122
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target),
 
123
                                Tuple.Create(new TextLocation(1, 16), actual.AstNode),
 
124
                                Tuple.Create(new TextLocation(1, 31), actual.AstNode),
 
125
                        });
 
126
                }
 
127
 
 
128
                [Test]
 
129
                public void SelectManyFollowedBySelectWorksWhenTheTargetIsTransparentAndTheCollectionsAreCorrelated() {
 
130
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in outer let j = F(i) from k in j.Result select i + j + k");
 
131
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
132
                        AssertCorrect(actual.AstNode, "outer.Select(i => new { i, j = F(i) }).SelectMany(x0 => x0.j.Result, (x1, k) => x1.i + x1.j + k)");
 
133
                        dynamic astNode = actual.AstNode;
 
134
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
135
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Arguments, 0).Parameters, 0)),
 
136
                                Tuple.Create(new TextLocation(1, 21), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Arguments, 0).Body.Initializers, 1).NameToken),
 
137
                                Tuple.Create(new TextLocation(1, 35), (AstNode)ElementAt(ElementAt(astNode.Arguments, 1).Parameters, 1)),
 
138
                        });
 
139
                        AssertLookupCorrect(actual.Expressions, new[] {
 
140
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target.Target.Target),
 
141
                                Tuple.Create(new TextLocation(1, 17), (AstNode)astNode.Target.Target),
 
142
                                Tuple.Create(new TextLocation(1, 30), actual.AstNode),
 
143
                                Tuple.Create(new TextLocation(1, 49), actual.AstNode),
 
144
                        });
 
145
                }
 
146
 
 
147
                [Test]
 
148
                public void SelectManyFollowedByLetWorksWhenTheTargetIsTransparentAndTheCollectionsAreCorrelated() {
 
149
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in outer let j = F(i) from k in j.Result let l = i + j + k select i + j + k + l");
 
150
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
151
                        AssertCorrect(actual.AstNode, "outer.Select(i => new { i, j = F(i) }).SelectMany(x0 => x0.j.Result, (x1, k) => new { x1, k }).Select(x2 => new { x2, l = x2.x1.i + x2.x1.j + x2.k }).Select(x3 => x3.x2.x1.i + x3.x2.x1.j + x3.x2.k + x3.l)");
 
152
                        dynamic astNode = actual.AstNode;
 
153
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
154
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Target.Target.Target.Target.Arguments, 0).Parameters, 0)),
 
155
                                Tuple.Create(new TextLocation(1, 21), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Target.Target.Target.Target.Arguments, 0).Body.Initializers, 1).NameToken),
 
156
                                Tuple.Create(new TextLocation(1, 35), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Target.Target.Arguments, 1).Parameters, 1)),
 
157
                                Tuple.Create(new TextLocation(1, 53), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Arguments, 0).Body.Initializers, 1).NameToken),
 
158
                        });
 
159
                        AssertLookupCorrect(actual.Expressions, new[] {
 
160
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target.Target.Target.Target.Target.Target.Target),
 
161
                                Tuple.Create(new TextLocation(1, 17), (AstNode)astNode.Target.Target.Target.Target.Target.Target),
 
162
                                Tuple.Create(new TextLocation(1, 30), (AstNode)astNode.Target.Target.Target.Target),
 
163
                                Tuple.Create(new TextLocation(1, 49), (AstNode)astNode.Target.Target),
 
164
                                Tuple.Create(new TextLocation(1, 67), (AstNode)astNode),
 
165
                        });
 
166
                }
 
167
 
 
168
                [Test]
 
169
                public void TwoFromClausesFollowedByLetWorks() {
 
170
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in arr1 from j in arr2 let k = i + j select i + j + k");
 
171
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
172
                        AssertCorrect(actual.AstNode, "arr1.SelectMany(i => arr2, (i, j) => new { i, j }).Select(x0 => new { x0, k = x0.i + x0.j }).Select(x1 => x1.x0.i + x1.x0.j + x1.k)");
 
173
                        dynamic astNode = actual.AstNode;
 
174
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
175
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Target.Target.Arguments, 0).Parameters, 0)),
 
176
                                Tuple.Create(new TextLocation(1, 21), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Target.Target.Arguments, 1).Parameters, 1)),
 
177
                                Tuple.Create(new TextLocation(1, 35), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Arguments, 0).Body.Initializers, 1).NameToken),
 
178
                        });
 
179
                        AssertLookupCorrect(actual.Expressions, new[] {
 
180
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target.Target.Target.Target.Target),
 
181
                                Tuple.Create(new TextLocation(1, 16), (AstNode)astNode.Target.Target.Target.Target),
 
182
                                Tuple.Create(new TextLocation(1, 31), (AstNode)astNode.Target.Target),
 
183
                                Tuple.Create(new TextLocation(1, 45), actual.AstNode),
 
184
                        });
 
185
                }
 
186
 
 
187
                [Test]
 
188
                public void ThreeFromClausesFollowedBySelectWorks() {
 
189
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in arr1 from j in arr2 from k in arr3 select i + j + k");
 
190
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
191
                        AssertCorrect(actual.AstNode, "arr1.SelectMany(i => arr2, (i, j) => new { i, j }).SelectMany(x0 => arr3, (x1, k) => x1.i + x1.j + k)");
 
192
                        dynamic astNode = actual.AstNode;
 
193
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
194
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Arguments, 0).Parameters, 0)),
 
195
                                Tuple.Create(new TextLocation(1, 21), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Arguments, 1).Parameters, 1)),
 
196
                                Tuple.Create(new TextLocation(1, 36), (AstNode)ElementAt(ElementAt(astNode.Arguments, 1).Parameters, 1)),
 
197
                        });
 
198
                        AssertLookupCorrect(actual.Expressions, new[] {
 
199
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target.Target.Target),
 
200
                                Tuple.Create(new TextLocation(1, 16), (AstNode)astNode.Target.Target),
 
201
                                Tuple.Create(new TextLocation(1, 31), (AstNode)astNode),
 
202
                                Tuple.Create(new TextLocation(1, 46), (AstNode)astNode),
 
203
                        });
 
204
                }
 
205
 
 
206
                [Test]
 
207
                public void GroupByWithSimpleValue() {
 
208
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in arr group i by i.field");
 
209
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
210
                        AssertCorrect(actual.AstNode, "arr.GroupBy(i => i.field)");
 
211
                        dynamic astNode = actual.AstNode;
 
212
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
213
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Arguments, 0).Parameters, 0)),
 
214
                        });
 
215
                        AssertLookupCorrect(actual.Expressions, new[] {
 
216
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target),
 
217
                                Tuple.Create(new TextLocation(1, 15), (AstNode)astNode),
 
218
                        });
 
219
                }
 
220
 
 
221
                [Test]
 
222
                public void GroupByWithProjectedValue() {
 
223
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in arr group i.something by i.field");
 
224
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
225
                        AssertCorrect(actual.AstNode, "arr.GroupBy(i => i.field, i => i.something)");
 
226
                        dynamic astNode = actual.AstNode;
 
227
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
228
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Arguments, 0).Parameters, 0)),
 
229
                        });
 
230
                        AssertLookupCorrect(actual.Expressions, new[] {
 
231
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target),
 
232
                                Tuple.Create(new TextLocation(1, 15), (AstNode)astNode),
 
233
                        });
 
234
                }
 
235
 
 
236
                [Test]
 
237
                public void GroupByWhenThereIsATransparentIdentifer() {
 
238
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in arr let j = F(i) group i by i.field");
 
239
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
240
                        AssertCorrect(actual.AstNode, "arr.Select(i => new { i, j = F(i) }).GroupBy(x0 => x0.i.field, x1 => x1.i)");
 
241
                        dynamic astNode = actual.AstNode;
 
242
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
243
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Arguments, 0).Parameters, 0)),
 
244
                                Tuple.Create(new TextLocation(1, 19), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Arguments, 0).Body.Initializers, 1).NameToken),
 
245
                        });
 
246
                        AssertLookupCorrect(actual.Expressions, new[] {
 
247
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target.Target.Target),
 
248
                                Tuple.Create(new TextLocation(1, 15), (AstNode)astNode.Target.Target),
 
249
                                Tuple.Create(new TextLocation(1, 28), (AstNode)astNode),
 
250
                        });
 
251
                }
 
252
 
 
253
                [Test]
 
254
                public void JoinFollowedBySelect() {
 
255
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in arr1 join j in arr2 on i.keyi equals j.keyj select i + j");
 
256
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
257
                        AssertCorrect(actual.AstNode, "arr1.Join(arr2, i => i.keyi, j => j.keyj, (i, j) => i + j)");
 
258
                        dynamic astNode = actual.AstNode;
 
259
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
260
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Arguments, 1).Parameters, 0)),
 
261
                                Tuple.Create(new TextLocation(1, 21), (AstNode)ElementAt(ElementAt(astNode.Arguments, 2).Parameters, 0)),
 
262
                        });
 
263
                        AssertLookupCorrect(actual.Expressions, new[] {
 
264
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target),
 
265
                                Tuple.Create(new TextLocation(1, 16), (AstNode)astNode),
 
266
                                Tuple.Create(new TextLocation(1, 55), (AstNode)astNode),
 
267
                        });
 
268
                }
 
269
 
 
270
                [Test]
 
271
                public void JoinFollowedByLet() {
 
272
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in arr1 join j in arr2 on i.keyi equals j.keyj let k = i + j select i + j + k");
 
273
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
274
                        AssertCorrect(actual.AstNode, "arr1.Join(arr2, i => i.keyi, j => j.keyj, (i, j) => new { i, j }).Select(x0 => new { x0, k = x0.i + x0.j }).Select(x1 => x1.x0.i + x1.x0.j + x1.k)");
 
275
                        dynamic astNode = actual.AstNode;
 
276
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
277
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Target.Target.Arguments, 1).Parameters, 0)),
 
278
                                Tuple.Create(new TextLocation(1, 21), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Target.Target.Arguments, 2).Parameters, 0)),
 
279
                                Tuple.Create(new TextLocation(1, 59), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Arguments, 0).Body.Initializers, 1).NameToken),
 
280
                        });
 
281
                        AssertLookupCorrect(actual.Expressions, new[] {
 
282
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target.Target.Target.Target.Target),
 
283
                                Tuple.Create(new TextLocation(1, 16), (AstNode)astNode.Target.Target.Target.Target),
 
284
                                Tuple.Create(new TextLocation(1, 55), (AstNode)astNode.Target.Target),
 
285
                                Tuple.Create(new TextLocation(1, 69), (AstNode)astNode),
 
286
                        });
 
287
                }
 
288
 
 
289
                [Test]
 
290
                public void JoinFollowedBySelectWhenThereIsATransparentIdentifier() {
 
291
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in arr1 let j = F(i) join k in arr2 on j.keyj equals k.keyk select i + j + k");
 
292
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
293
                        AssertCorrect(actual.AstNode, "arr1.Select(i => new { i, j = F(i) }).Join(arr2, x0 => x0.j.keyj, k => k.keyk, (x1, k) => x1.i + x1.j + k)");
 
294
                        dynamic astNode = actual.AstNode;
 
295
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
296
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Arguments, 0).Parameters, 0)),
 
297
                                Tuple.Create(new TextLocation(1, 20), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Arguments, 0).Body.Initializers, 1).NameToken),
 
298
                                Tuple.Create(new TextLocation(1, 34), (AstNode)ElementAt(ElementAt(astNode.Arguments, 2).Parameters, 0)),
 
299
                        });
 
300
                        AssertLookupCorrect(actual.Expressions, new[] {
 
301
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target.Target.Target),
 
302
                                Tuple.Create(new TextLocation(1, 16), (AstNode)astNode.Target.Target),
 
303
                                Tuple.Create(new TextLocation(1, 29), (AstNode)astNode),
 
304
                                Tuple.Create(new TextLocation(1, 68), (AstNode)astNode),
 
305
                        });
 
306
                }
 
307
 
 
308
                [Test]
 
309
                public void GroupJoinFollowedBySelect() {
 
310
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in arr1 join j in arr2 on i.keyi equals j.keyj into g select F(i, g)");
 
311
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
312
                        AssertCorrect(actual.AstNode, "arr1.GroupJoin(arr2, i => i.keyi, j => j.keyj, (i, g) => F(i, g))");
 
313
                        dynamic astNode = actual.AstNode;
 
314
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
315
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Arguments, 1).Parameters, 0)),
 
316
                                Tuple.Create(new TextLocation(1, 60), (AstNode)ElementAt(ElementAt(astNode.Arguments, 3).Parameters, 1)),
 
317
                        });
 
318
                        AssertLookupCorrect(actual.Expressions, new[] {
 
319
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target),
 
320
                                Tuple.Create(new TextLocation(1, 16), (AstNode)astNode),
 
321
                                Tuple.Create(new TextLocation(1, 62), (AstNode)astNode),
 
322
                        });
 
323
                }
 
324
 
 
325
                [Test]
 
326
                public void GroupJoinFollowedByLet() {
 
327
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in arr1 join j in arr2 on i.keyi equals j.keyj into g let k = i + g select i + g + k");
 
328
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
329
                        AssertCorrect(actual.AstNode, "arr1.GroupJoin(arr2, i => i.keyi, j => j.keyj, (i, g) => new { i, g }).Select(x0 => new { x0, k = x0.i + x0.g }).Select(x1 => x1.x0.i + x1.x0.g + x1.k)");
 
330
                        dynamic astNode = actual.AstNode;
 
331
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
332
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Target.Target.Arguments, 1).Parameters, 0)),
 
333
                                Tuple.Create(new TextLocation(1, 60), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Target.Target.Arguments, 3).Parameters, 1)),
 
334
                                Tuple.Create(new TextLocation(1, 66), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Arguments, 0).Body.Initializers, 1).NameToken),
 
335
                        });
 
336
                        AssertLookupCorrect(actual.Expressions, new[] {
 
337
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target.Target.Target.Target.Target),
 
338
                                Tuple.Create(new TextLocation(1, 16), (AstNode)astNode.Target.Target.Target.Target),
 
339
                                Tuple.Create(new TextLocation(1, 62), (AstNode)astNode.Target.Target),
 
340
                                Tuple.Create(new TextLocation(1, 76), (AstNode)astNode),
 
341
                        });
 
342
                }
 
343
 
 
344
                [Test]
 
345
                public void GroupJoinFollowedBySelectWhenThereIsATransparentIdentifier() {
 
346
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in arr1 let j = F(i) join k in arr2 on j.keyj equals k.keyk into g select F(i, j, g)");
 
347
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
348
                        AssertCorrect(actual.AstNode, "arr1.Select(i => new { i, j = F(i) }).GroupJoin(arr2, x0 => x0.j.keyj, k => k.keyk, (x1, g) => F(x1.i, x1.j, g))");
 
349
                        dynamic astNode = actual.AstNode;
 
350
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
351
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Arguments, 0).Parameters, 0)),
 
352
                                Tuple.Create(new TextLocation(1, 20), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Arguments, 0).Body.Initializers, 1).NameToken),
 
353
                                Tuple.Create(new TextLocation(1, 73), (AstNode)ElementAt(ElementAt(astNode.Arguments, 3).Parameters, 1)),
 
354
                        });
 
355
                        AssertLookupCorrect(actual.Expressions, new[] {
 
356
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target.Target.Target),
 
357
                                Tuple.Create(new TextLocation(1, 16), (AstNode)astNode.Target.Target),
 
358
                                Tuple.Create(new TextLocation(1, 29), (AstNode)astNode),
 
359
                                Tuple.Create(new TextLocation(1, 75), (AstNode)astNode),
 
360
                        });
 
361
                }
 
362
 
 
363
                [Test]
 
364
                public void WhereWorks() {
 
365
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in arr1 where i > 5 select i + 1");
 
366
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
367
                        AssertCorrect(actual.AstNode, "arr1.Where(i => i > 5).Select(i => i + 1)");
 
368
                        dynamic astNode = actual.AstNode;
 
369
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
370
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Arguments, 0).Parameters, 0)),
 
371
                        });
 
372
                        AssertLookupCorrect(actual.Expressions, new[] {
 
373
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target.Target.Target),
 
374
                                Tuple.Create(new TextLocation(1, 16), (AstNode)astNode.Target.Target),
 
375
                                Tuple.Create(new TextLocation(1, 28), (AstNode)astNode),
 
376
                        });
 
377
                }
 
378
 
 
379
                [Test]
 
380
                public void WhereWorksWhenThereIsATransparentIdentifier() {
 
381
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in arr1 let j = i + 1 where i > j select i + j");
 
382
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
383
                        AssertCorrect(actual.AstNode, "arr1.Select(i => new { i, j = i + 1 }).Where(x0 => x0.i > x0.j).Select(x1 => x1.i + x1.j)");
 
384
                        dynamic astNode = actual.AstNode;
 
385
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
386
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Target.Target.Arguments, 0).Parameters, 0)),
 
387
                                Tuple.Create(new TextLocation(1, 20), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Target.Target.Arguments, 0).Body.Initializers, 1).NameToken),
 
388
                        });
 
389
                        AssertLookupCorrect(actual.Expressions, new[] {
 
390
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target.Target.Target.Target.Target),
 
391
                                Tuple.Create(new TextLocation(1, 16), (AstNode)astNode.Target.Target.Target.Target),
 
392
                                Tuple.Create(new TextLocation(1, 30), (AstNode)astNode.Target.Target),
 
393
                                Tuple.Create(new TextLocation(1, 42), (AstNode)astNode),
 
394
                        });
 
395
                }
 
396
 
 
397
                [Test]
 
398
                public void TrivialSelectIsEliminatedAfterWhere() {
 
399
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in arr1 where i > 5 select i");
 
400
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
401
                        AssertCorrect(actual.AstNode, "arr1.Where(i => i > 5)");
 
402
                        dynamic astNode = actual.AstNode;
 
403
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
404
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Arguments, 0).Parameters, 0)),
 
405
                        });
 
406
                        AssertLookupCorrect(actual.Expressions, new[] {
 
407
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target),
 
408
                                Tuple.Create(new TextLocation(1, 16), (AstNode)astNode),
 
409
                                Tuple.Create(new TextLocation(1, 28), (AstNode)astNode),
 
410
                        });
 
411
                }
 
412
 
 
413
                [Test]
 
414
                public void TrivialSelectIsEliminatedAfterWhereEvenWhenParenthesized() {
 
415
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in arr1 where i > 5 select (i)");
 
416
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
417
                        AssertCorrect(actual.AstNode, "arr1.Where(i => i > 5)");
 
418
                        dynamic astNode = actual.AstNode;
 
419
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
420
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Arguments, 0).Parameters, 0)),
 
421
                        });
 
422
                        AssertLookupCorrect(actual.Expressions, new[] {
 
423
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target),
 
424
                                Tuple.Create(new TextLocation(1, 16), (AstNode)astNode),
 
425
                                Tuple.Create(new TextLocation(1, 28), (AstNode)astNode),
 
426
                        });
 
427
                }
 
428
 
 
429
                [Test]
 
430
                public void TrivialSelectIsNotEliminatingWhenTheOnlyOperation() {
 
431
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in arr1 select i");
 
432
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
433
                        AssertCorrect(actual.AstNode, "arr1.Select(i => i)");
 
434
                        dynamic astNode = actual.AstNode;
 
435
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
436
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Arguments, 0).Parameters, 0)),
 
437
                        });
 
438
                        AssertLookupCorrect(actual.Expressions, new[] {
 
439
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target),
 
440
                                Tuple.Create(new TextLocation(1, 16), (AstNode)astNode),
 
441
                        });
 
442
                }
 
443
 
 
444
                [Test]
 
445
                public void OrderingWorks() {
 
446
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in arr1 orderby i.field1 select i");
 
447
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
448
                        AssertCorrect(actual.AstNode, "arr1.OrderBy(i => i.field1)");
 
449
                        dynamic astNode = actual.AstNode;
 
450
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
451
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Arguments, 0).Parameters, 0)),
 
452
                        });
 
453
                        AssertLookupCorrect(actual.Expressions, new[] {
 
454
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target),
 
455
                                Tuple.Create(new TextLocation(1, 16), (AstNode)astNode),
 
456
                                Tuple.Create(new TextLocation(1, 24), (AstNode)astNode),
 
457
                                Tuple.Create(new TextLocation(1, 33), (AstNode)astNode),
 
458
                        });
 
459
                }
 
460
 
 
461
                [Test]
 
462
                public void OrderingWorksWhenThereIsATransparentIdentifier() {
 
463
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in arr1 let j = i + 1 orderby i + j select i");
 
464
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
465
                        AssertCorrect(actual.AstNode, "arr1.Select(i => new { i, j = i + 1 }).OrderBy(x0 => x0.i + x0.j).Select(x1 => x1.i)");
 
466
                        dynamic astNode = actual.AstNode;
 
467
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
468
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Target.Target.Arguments, 0).Parameters, 0)),
 
469
                                Tuple.Create(new TextLocation(1, 20), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Target.Target.Arguments, 0).Body.Initializers, 1).NameToken),
 
470
                        });
 
471
                        AssertLookupCorrect(actual.Expressions, new[] {
 
472
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target.Target.Target.Target.Target),
 
473
                                Tuple.Create(new TextLocation(1, 16), (AstNode)astNode.Target.Target.Target.Target),
 
474
                                Tuple.Create(new TextLocation(1, 30), (AstNode)astNode.Target.Target),
 
475
                                Tuple.Create(new TextLocation(1, 38), (AstNode)astNode.Target.Target),
 
476
                                Tuple.Create(new TextLocation(1, 44), (AstNode)astNode),
 
477
                        });
 
478
                }
 
479
 
 
480
                [Test]
 
481
                public void ThenByWorks() {
 
482
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in arr1 orderby i.field1, i.field2 select i");
 
483
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
484
                        AssertCorrect(actual.AstNode, "arr1.OrderBy(i => i.field1).ThenBy(i => i.field2)");
 
485
                        dynamic astNode = actual.AstNode;
 
486
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
487
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Arguments, 0).Parameters, 0)),
 
488
                        });
 
489
                        AssertLookupCorrect(actual.Expressions, new[] {
 
490
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target.Target.Target),
 
491
                                Tuple.Create(new TextLocation(1, 16), (AstNode)astNode),        // This should be the orderby at location 16, but a parser bug causes 24 to be returned. change this to 16 after fixing the parser bug.
 
492
                                Tuple.Create(new TextLocation(1, 24), (AstNode)astNode.Target.Target),
 
493
                                Tuple.Create(new TextLocation(1, 34), (AstNode)astNode),
 
494
                                Tuple.Create(new TextLocation(1, 43), (AstNode)astNode),
 
495
                        });
 
496
                }
 
497
 
 
498
                [Test]
 
499
                public void OrderingDescendingWorks() {
 
500
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in arr1 orderby i.field1 descending, i.field2 descending select i");
 
501
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
502
 
 
503
                        AssertCorrect(actual.AstNode, "arr1.OrderByDescending(i => i.field1).ThenByDescending(i => i.field2)");
 
504
                        dynamic astNode = actual.AstNode;
 
505
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
506
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Arguments, 0).Parameters, 0)),
 
507
                        });
 
508
                        AssertLookupCorrect(actual.Expressions, new[] {
 
509
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target.Target.Target),
 
510
                                Tuple.Create(new TextLocation(1, 24), (AstNode)astNode),        // This should be the orderby at location 16, but a parser bug causes 24 to be returned. change this to 16 after fixing the parser bug.
 
511
                                Tuple.Create(new TextLocation(1, 24), (AstNode)astNode.Target.Target),
 
512
                                Tuple.Create(new TextLocation(1, 45), (AstNode)astNode),
 
513
                                Tuple.Create(new TextLocation(1, 65), (AstNode)astNode),
 
514
                        });
 
515
                }
 
516
 
 
517
                [Test]
 
518
                public void QueryContinuation() {
 
519
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in arr1 from j in arr2 select i + j into a where a > 5 select a + 1");
 
520
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
521
                        AssertCorrect(actual.AstNode, "arr1.SelectMany(i => arr2, (i, j) => i + j).Where(a => a > 5).Select(a => a + 1)");
 
522
                        dynamic astNode = actual.AstNode;
 
523
                        AssertLookupCorrect(actual.RangeVariables, new[] {
 
524
                                Tuple.Create(new TextLocation(1, 6), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Target.Target.Arguments, 0).Parameters, 0)),
 
525
                                Tuple.Create(new TextLocation(1, 21), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Target.Target.Arguments, 1).Parameters, 1)),
 
526
                                Tuple.Create(new TextLocation(1, 49), (AstNode)ElementAt(ElementAt(astNode.Target.Target.Arguments, 0).Parameters, 0)),
 
527
                        });
 
528
                        AssertLookupCorrect(actual.Expressions, new[] {
 
529
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target.Target.Target),
 
530
                                Tuple.Create(new TextLocation(1, 1), (AstNode)astNode.Target.Target.Target.Target.Target.Target),
 
531
                                Tuple.Create(new TextLocation(1, 16), (AstNode)astNode.Target.Target.Target.Target),
 
532
                                Tuple.Create(new TextLocation(1, 31), (AstNode)astNode.Target.Target.Target.Target),
 
533
                                Tuple.Create(new TextLocation(1, 51), (AstNode)astNode.Target.Target),
 
534
                                Tuple.Create(new TextLocation(1, 63), (AstNode)astNode),
 
535
                        });
 
536
                }
 
537
 
 
538
                [Test]
 
539
                public void NestedQueries() {
 
540
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in arr1 from j in arr2 let l = new { i, j } group l by l.i into g select new { g.Key, a = from q in g select new { q.i, q.j } }");
 
541
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
542
                        AssertCorrect(actual.AstNode, "arr1.SelectMany(i => arr2, (i, j) => new { i, j }).Select(x0 => new { x0, l = new { x0.i, x0.j } }).GroupBy(x1 => x1.l.i, x2 => x2.l).Select(g => new { g.Key, a = g.Select(q => new { q.i, q.j }) })");
 
543
                }
 
544
 
 
545
                [Test]
 
546
                public void NestedQueryUsingRangeVariableFromOuter() {
 
547
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from i in arr1 from j in arr2 let k = new[] { i, j } select (from l in k let m = l + 1 select l + m + i)");
 
548
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
549
                        AssertCorrect(actual.AstNode, "arr1.SelectMany(i => arr2, (i, j) => new { i, j }).Select(x0 => new { x0, k = new[] { x0.i, x0.j } }).Select(x1 => (x1.k.Select(l => new { l, m = l + 1 }).Select(x2 => x2.l + x2.m + x1.x0.i)))");
 
550
                }
 
551
 
 
552
                [Test]
 
553
                public void RangeVariablesAreNotInScopeInJoinEquals() {
 
554
                        var node = ParseUtilCSharp.ParseExpression<QueryExpression>("from a in args let a2 = a select (from b in args let b2 = b join c in args on b[0] equals b + a into g select g)");
 
555
                        var actual = new QueryExpressionExpander().ExpandQueryExpressions(node);
 
556
                        AssertCorrect(actual.AstNode, "args.Select(a => new { a, a2 = a }).Select(x0 => (args.Select(b => new { b, b2 = b }).GroupJoin(args, x1 => x1.b[0], c => b + x0.a, (x2, g) => g)))");
 
557
                }
 
558
        }
 
559
}