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