/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/LinqTests.cs
C# | 396 lines | 354 code | 25 blank | 17 comment | 0 complexity | e7164b452ba422aeb9d1799e304a2bbb MD5 | raw file
Possible License(s): CC-BY-SA-3.0
1// Copyright (c) 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
19using System;
20using System.Linq;
21using ICSharpCode.NRefactory.Semantics;
22using ICSharpCode.NRefactory.TypeSystem;
23using ICSharpCode.NRefactory.TypeSystem.Implementation;
24using NUnit.Framework;
25
26namespace ICSharpCode.NRefactory.CSharp.Resolver
27{
28 [TestFixture]
29 public class LinqTests : ResolverTestBase
30 {
31 [Test]
32 public void SimpleLinq()
33 {
34 string program = @"using System; using System.Linq;
35class TestClass {
36 void Test(string[] input) {
37 var r = from e in input
38 where e.StartsWith(""/"")
39 select e.Trim();
40 r.ToString();
41 }
42}
43";
44 LocalResolveResult lrr = Resolve<LocalResolveResult>(program.Replace("where e", "where $e$"));
45 Assert.AreEqual("System.String", lrr.Type.ReflectionName);
46 lrr = Resolve<LocalResolveResult>(program.Replace("select e", "select $e$"));
47 Assert.AreEqual("System.String", lrr.Type.ReflectionName);
48 lrr = Resolve<LocalResolveResult>(program.Replace("from e", "from $e$"));
49 Assert.AreEqual("System.String", lrr.Type.ReflectionName);
50
51 lrr = Resolve<LocalResolveResult>(program.Replace("r.ToString", "$r$.ToString"));
52 Assert.AreEqual("System.Collections.Generic.IEnumerable", lrr.Type.FullName);
53 Assert.AreEqual("System.String", ((ParameterizedType)lrr.Type).TypeArguments[0].FullName);
54 }
55
56 [Test]
57 public void Group()
58 {
59 string program = @"using System; using System.Linq;
60class TestClass {
61 void Test(string[] input) {
62 var r = from e in input
63 group e.ToUpper() by e.Length;
64 $r$.ToString();
65 }
66}
67";
68 LocalResolveResult lrr = Resolve<LocalResolveResult>(program);
69 Assert.AreEqual("System.Collections.Generic.IEnumerable", lrr.Type.FullName);
70 ParameterizedType rt = (ParameterizedType)((ParameterizedType)lrr.Type).TypeArguments[0];
71 Assert.AreEqual("System.Linq.IGrouping", rt.FullName);
72 Assert.AreEqual("System.Int32", rt.TypeArguments[0].FullName);
73 Assert.AreEqual("System.String", rt.TypeArguments[1].FullName);
74 }
75
76 [Test]
77 public void QueryableGroup()
78 {
79 string program = @"using System; using System.Linq;
80class TestClass {
81 void Test(IQueryable<string> input) {
82 var r = from e in input
83 group e.ToUpper() by e.Length;
84 $r$.ToString();
85 }
86}
87";
88 LocalResolveResult lrr = Resolve<LocalResolveResult>(program);
89 Assert.AreEqual("System.Linq.IQueryable", lrr.Type.FullName);
90 ParameterizedType rt = (ParameterizedType)((ParameterizedType)lrr.Type).TypeArguments[0];
91 Assert.AreEqual("System.Linq.IGrouping", rt.FullName);
92 Assert.AreEqual("System.Int32", rt.TypeArguments[0].FullName);
93 Assert.AreEqual("System.String", rt.TypeArguments[1].FullName);
94 }
95
96 [Test]
97 public void Parenthesized()
98 {
99 string program = @"using System; using System.Linq;
100class TestClass {
101 void Test(string[] input) {
102 $(from e in input select e.Length)$.ToArray();
103 }
104}
105";
106 var rr = Resolve<ConversionResolveResult>(program);
107 Assert.IsTrue(rr.Conversion.IsIdentityConversion);
108 Assert.AreEqual("System.Collections.Generic.IEnumerable", rr.Type.FullName);
109 Assert.AreEqual("System.Int32", ((ParameterizedType)rr.Type).TypeArguments[0].FullName);
110 }
111
112 [Test]
113 public void SelectReturnType()
114 {
115 string program = @"using System;
116class TestClass { static void M() {
117 (from a in new XYZ() $select a.ToUpper()$).ToString();
118}}
119class XYZ {
120 public int Select<U>(Func<string, U> f) { return 42; }
121}";
122 var rr = Resolve<CSharpInvocationResolveResult>(program);
123 Assert.AreEqual("XYZ.Select", rr.Member.FullName);
124 Assert.AreEqual("System.Int32", rr.Type.FullName);
125 }
126
127 [Test]
128 public void Continuation()
129 {
130 string program = @"using System; using System.Linq;
131class TestClass {
132 void Test(string[] input) {
133 var r = from x in input
134 select x.GetHashCode() into x
135 where x == 42
136 select x * x;
137 r.ToString();
138 }
139}
140";
141 LocalResolveResult lrr = Resolve<LocalResolveResult>(program.Replace("from x", "from $x$"));
142 Assert.AreEqual("System.String", lrr.Type.ReflectionName);
143 lrr = Resolve<LocalResolveResult>(program.Replace("select x.G", "select $x$.G"));
144 Assert.AreEqual("System.String", lrr.Type.ReflectionName);
145 lrr = Resolve<LocalResolveResult>(program.Replace("into x", "into $x$"));
146 Assert.AreEqual("System.Int32", lrr.Type.ReflectionName);
147 lrr = Resolve<LocalResolveResult>(program.Replace("where x", "where $x$"));
148 Assert.AreEqual("System.Int32", lrr.Type.ReflectionName);
149 lrr = Resolve<LocalResolveResult>(program.Replace("select x * x", "select x * $x$"));
150 Assert.AreEqual("System.Int32", lrr.Type.ReflectionName);
151
152 lrr = Resolve<LocalResolveResult>(program.Replace("r.ToString", "$r$.ToString"));
153 Assert.AreEqual("System.Collections.Generic.IEnumerable`1[[System.Int32]]", lrr.Type.ReflectionName);
154 }
155
156 [Test]
157 public void OrderingWithSelectCall()
158 {
159 string program = @"using System; using System.Linq;
160class TestClass {
161 void Test(string[] input) {
162 $var$ r = from x in input
163 orderby x.Length
164 select x + x;
165 }
166}
167";
168 TypeResolveResult rr = Resolve<TypeResolveResult>(program);
169 Assert.AreEqual("System.Collections.Generic.IEnumerable`1[[System.String]]", rr.Type.ReflectionName);
170 }
171
172 [Test]
173 public void OrderingWithoutSelectCall()
174 {
175 string program = @"using System; using System.Linq;
176class TestClass {
177 void Test(string[] input) {
178 $var$ r = from x in input
179 orderby x.Length
180 select x;
181 }
182}
183";
184 TypeResolveResult rr = Resolve<TypeResolveResult>(program);
185 Assert.AreEqual("System.Linq.IOrderedEnumerable`1[[System.String]]", rr.Type.ReflectionName);
186 }
187
188 [Test]
189 public void OrderingWithSelectCallDueToSecondRangeVariable1()
190 {
191 string program = @"using System; using System.Linq;
192class TestClass {
193 void Test(string[] input) {
194 $var$ r = from x in input
195 from y in input
196 orderby x.Length
197 select x;
198 }
199}
200";
201 TypeResolveResult rr = Resolve<TypeResolveResult>(program);
202 Assert.AreEqual("System.Collections.Generic.IEnumerable`1[[System.String]]", rr.Type.ReflectionName);
203 }
204
205 [Test]
206 public void OrderingWithSelectCallDueToSecondRangeVariable2()
207 {
208 string program = @"using System; using System.Linq;
209class TestClass {
210 void Test(string[] input) {
211 $var$ r = from x in input
212 join y in input on x equals y
213 orderby x.Length
214 select x;
215 }
216}
217";
218 TypeResolveResult rr = Resolve<TypeResolveResult>(program);
219 Assert.AreEqual("System.Collections.Generic.IEnumerable`1[[System.String]]", rr.Type.ReflectionName);
220 }
221
222 [Test]
223 public void OrderingWithSelectCallDueToSecondRangeVariable3()
224 {
225 string program = @"using System; using System.Linq;
226class TestClass {
227 void Test(string[] input) {
228 $var$ r = from x in input
229 join y in input on x equals y into g
230 orderby x.Length
231 select x;
232 }
233}
234";
235 TypeResolveResult rr = Resolve<TypeResolveResult>(program);
236 Assert.AreEqual("System.Collections.Generic.IEnumerable`1[[System.String]]", rr.Type.ReflectionName);
237 }
238
239 [Test]
240 public void OrderingWithSelectCallDueToSecondRangeVariable4()
241 {
242 string program = @"using System; using System.Linq;
243class TestClass {
244 void Test(string[] input) {
245 $var$ r = from x in input
246 let y = x
247 orderby x.Length
248 select x;
249 }
250}
251";
252 TypeResolveResult rr = Resolve<TypeResolveResult>(program);
253 Assert.AreEqual("System.Collections.Generic.IEnumerable`1[[System.String]]", rr.Type.ReflectionName);
254 }
255
256 [Test]
257 public void DegenerateQuery()
258 {
259 string program = @"using System; using System.Linq;
260class TestClass {
261 void Test(string[] input) {
262 $var$ r = from x in input select x;
263 }
264}
265";
266 TypeResolveResult rr = Resolve<TypeResolveResult>(program);
267 Assert.AreEqual("System.Collections.Generic.IEnumerable`1[[System.String]]", rr.Type.ReflectionName);
268 }
269
270 [Test]
271 public void GroupJoinWithCustomMethod()
272 {
273 string program = @"using System;
274using System.Collections.Generic;
275class TestClass { static void M(long [] args) {
276 var q = (from a in new XYZ() join b in args on a equals b into g select g);
277}}
278class XYZ {
279 public XYZ GroupJoin<T, R>(IEnumerable<T> f, Func<string, object> key1, Func<T, object> key2, Func<string, decimal, R> s) { return this; }
280 public int Select<U>(Func<string, U> f) { return 42; }
281}";
282 var local = Resolve<LocalResolveResult>(program.Replace("into g", "into $g$"));
283 Assert.AreEqual("System.Decimal", local.Type.FullName);
284
285 local = Resolve<LocalResolveResult>(program.Replace("select g", "select $g$"));
286 Assert.AreEqual("System.Decimal", local.Type.FullName);
287
288 var trr = Resolve<TypeResolveResult>(program.Replace("var", "$var$"));
289 Assert.AreEqual("XYZ", trr.Type.FullName); // because 'Select' is done as part of GroupJoin()
290 }
291
292 [Test]
293 public void GroupJoinWithOverloadedCustomMethod()
294 {
295 string program = @"using System;
296using System.Collections.Generic;
297class TestClass
298{
299 static void M(string[] args)
300 {
301 var q = (from a in new XYZ() $join b in args on a equals b into g$ select g.ToUpper());
302 }
303}
304class XYZ
305{
306 public int GroupJoin(IEnumerable<string> f, Func<string, object> key1, Func<string, object> key2, Func<string, int, int> s) { return 0; }
307 public decimal GroupJoin(IEnumerable<string> f, Func<string, object> key1, Func<string, object> key2, Func<string, string, string> s) { return 0; }
308}";
309 var rr = Resolve<CSharpInvocationResolveResult>(program);
310 Assert.IsFalse(rr.IsError);
311 Assert.AreEqual("GroupJoin", rr.Member.Name);
312 Assert.AreEqual("System.Decimal", rr.Type.FullName);
313
314 rr = Resolve<CSharpInvocationResolveResult>(program.Replace("g.ToUpper()", "g.CompareTo(42)"));
315 Assert.IsFalse(rr.IsError);
316 Assert.AreEqual("GroupJoin", rr.Member.Name);
317 Assert.AreEqual("System.Int32", rr.Type.FullName);
318 }
319
320 [Test]
321 public void GroupWithQueryContinuation()
322 {
323 string program = @"using System; using System.Linq;
324class TestClass
325{
326 static void M(string[] args)
327 {
328 var query =
329 from w in ""one to three"".Split()
330 group w by w.Length into g
331 orderby g.Key descending
332 select new { g.Key, Count = g.Count(), Avg = g.Average ($w$ => w.Length) };
333 }
334}";
335 var rr = Resolve<LocalResolveResult>(program);
336 Assert.AreEqual("System.String", rr.Type.FullName);
337 }
338
339 [Test]
340 public void SelectManyInvocation()
341 {
342 string program = @"using System; using System.Linq;
343class TestClass
344{
345 static void M(string[] args)
346 {
347 var query = from w in args $from c in w$ select c - '0';
348 }
349}";
350 var rr = Resolve<CSharpInvocationResolveResult>(program);
351 Assert.IsFalse(rr.IsError);
352 Assert.AreEqual("SelectMany", rr.Member.Name);
353 Assert.AreEqual(3, rr.Member.Parameters.Count);
354 var typeArguments = ((SpecializedMethod)rr.Member).TypeArguments;
355 Assert.AreEqual(3, typeArguments.Count);
356 Assert.AreEqual("System.String", typeArguments[0].ReflectionName, "TSource");
357 Assert.AreEqual("System.Char", typeArguments[1].ReflectionName, "TCollection");
358 Assert.AreEqual("System.Int32", typeArguments[2].ReflectionName, "TResult");
359 }
360
361 [Test]
362 public void SelectManyInvocationWithTransparentIdentifier()
363 {
364 string program = @"using System; using System.Linq;
365class TestClass
366{
367 static void M(string[] args)
368 {
369 var query = from w in args $from c in w$ orderby c select c - '0';
370 }
371}";
372 var rr = Resolve<CSharpInvocationResolveResult>(program);
373 Assert.IsFalse(rr.IsError);
374 Assert.AreEqual("SelectMany", rr.Member.Name);
375 Assert.AreEqual(3, rr.Member.Parameters.Count);
376 var typeArguments = ((SpecializedMethod)rr.Member).TypeArguments;
377 Assert.AreEqual(3, typeArguments.Count);
378 Assert.AreEqual("System.String", typeArguments[0].ReflectionName, "TSource");
379 Assert.AreEqual("System.Char", typeArguments[1].ReflectionName, "TCollection");
380 Assert.AreEqual(TypeKind.Anonymous, typeArguments[2].Kind, "TResult");
381 }
382
383 [Test]
384 public void FromClauseDoesNotResolveToSourceVariable()
385 {
386 string program = @"using System; using System.Linq;
387class TestClass {
388 static void M(string[] args) {
389 var query = $from w in args$ select int.Parse(w);
390 }}";
391 var rr = Resolve<ConversionResolveResult>(program);
392 Assert.AreEqual("System.String[]", rr.Type.ReflectionName);
393 Assert.AreEqual(Conversion.IdentityConversion, rr.Conversion);
394 }
395 }
396}