From ad2f39888f34df35383c46b31478a8bc7a91b458 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Matou=C5=A1ek?= Date: Fri, 9 Jun 2017 11:43:28 -0700 Subject: [PATCH] EnC test refactoring (#20061) Refactor tests --- .../CSharpEditorServicesTest.csproj | 7 +- .../ActiveStatementTests.Methods.cs | 2 +- .../EditAndContinue/ActiveStatementTests.cs | 28 +- .../ActiveStatementTrackingServiceTests.cs | 2 +- ...RudeEditTestBase.cs => EditingTestBase.cs} | 2 +- .../EditAndContinue/LineEditTests.cs | 2 +- ...ementTests.cs => StatementEditingTests.cs} | 1448 +--------------- .../EditAndContinue/StatementMatchingTests.cs | 1500 +++++++++++++++++ ...pLevelTests.cs => TopLevelEditingTests.cs} | 2 +- 9 files changed, 1525 insertions(+), 1468 deletions(-) rename src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/{RudeEditTestBase.cs => EditingTestBase.cs} (99%) rename src/EditorFeatures/CSharpTest/EditAndContinue/{RudeEditStatementTests.cs => StatementEditingTests.cs} (76%) create mode 100644 src/EditorFeatures/CSharpTest/EditAndContinue/StatementMatchingTests.cs rename src/EditorFeatures/CSharpTest/EditAndContinue/{RudeEditTopLevelTests.cs => TopLevelEditingTests.cs} (99%) diff --git a/src/EditorFeatures/CSharpTest/CSharpEditorServicesTest.csproj b/src/EditorFeatures/CSharpTest/CSharpEditorServicesTest.csproj index 6cdee8bd666..dbb70796874 100644 --- a/src/EditorFeatures/CSharpTest/CSharpEditorServicesTest.csproj +++ b/src/EditorFeatures/CSharpTest/CSharpEditorServicesTest.csproj @@ -206,6 +206,7 @@ + @@ -359,10 +360,10 @@ - + - - + + diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.Methods.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.Methods.cs index de8f5d1dc9c..fd1498a6759 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.Methods.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.Methods.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.CSharp.EditAndContinue.UnitTests { - public class ActiveStatementTests_Methods : RudeEditTestBase + public class ActiveStatementTests_Methods : EditingTestBase { #region Methods diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.cs index a35d25546fb..ee80967d296 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTests.cs @@ -7,7 +7,7 @@ namespace Microsoft.CodeAnalysis.CSharp.EditAndContinue.UnitTests { - public class ActiveStatementTests : RudeEditTestBase + public class ActiveStatementTests : EditingTestBase { #region Update @@ -8457,7 +8457,7 @@ static void Foo() #region C# 7.0 [Fact] - public void MethodUpdate_IsPattern() + public void UpdateAroundActiveStatement_IsPattern() { string src1 = @" class C @@ -8486,7 +8486,7 @@ static void F(object x) } [Fact] - public void MethodUpdate_DeconstructionDeclarationStatement() + public void UpdateAroundActiveStatement_DeconstructionDeclarationStatement() { string src1 = @" class C @@ -8515,7 +8515,7 @@ static void F(object x) } [Fact] - public void MethodUpdate_DeconstructionForEach() + public void UpdateAroundActiveStatement_DeconstructionForEach() { string src1 = @" class C @@ -8544,7 +8544,7 @@ static void F(object o) } [Fact] - public void MethodUpdate_VarDeconstruction() + public void UpdateAroundActiveStatement_VarDeconstruction() { string src1 = @" class C @@ -8573,7 +8573,7 @@ static void F(object o1, object o2) } [Fact] - public void MethodUpdate_TypedDeconstruction() + public void UpdateAroundActiveStatement_TypedDeconstruction() { string src1 = @" class C @@ -8602,7 +8602,7 @@ static void F(object o1, object o2) } [Fact] - public void MethodUpdate_Tuple() + public void UpdateAroundActiveStatement_Tuple() { string src1 = @" class C @@ -8631,7 +8631,7 @@ static void F(object o) } [Fact] - public void MethodUpdate_LocalFunction() + public void UpdateAroundActiveStatement_LocalFunction() { string src1 = @" class C @@ -8661,7 +8661,7 @@ static void F(object o) } [Fact] - public void MethodUpdate_OutVar() + public void UpdateAroundActiveStatement_OutVar() { string src1 = @" class C @@ -8690,7 +8690,7 @@ static void F() } [Fact] - public void MethodUpdate_OutVarRemoved() + public void UpdateAroundActiveStatement_OutVarRemoved() { string src1 = @" class C @@ -8718,7 +8718,7 @@ static void F() } [Fact] - public void MethodUpdate_Ref() + public void UpdateAroundActiveStatement_Ref() { string src1 = @" class C @@ -8747,7 +8747,7 @@ static void F() } [Fact] - public void MethodUpdate_DeconstructionDeclaration() + public void UpdateAroundActiveStatement_DeconstructionDeclaration() { string src1 = @" class C @@ -8776,7 +8776,7 @@ static void F(object o1, object o2) } [Fact] - public void MethodUpdate_DeconstructionAssignment() + public void UpdateAroundActiveStatement_DeconstructionAssignment() { string src1 = @" class C @@ -8807,7 +8807,7 @@ static void F(object o1, object o2) } [Fact] - public void MethodUpdate_SwitchWithPattern() + public void UpdateAroundActiveStatement_SwitchWithPattern() { string src1 = @" class C diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTrackingServiceTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTrackingServiceTests.cs index f4f988c1ae7..db2ae98fe1d 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTrackingServiceTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/ActiveStatementTrackingServiceTests.cs @@ -5,7 +5,7 @@ namespace Microsoft.CodeAnalysis.CSharp.EditAndContinue.UnitTests { - public class ActiveStatementTrackingServiceTests : RudeEditTestBase + public class ActiveStatementTrackingServiceTests : EditingTestBase { [Fact, WorkItem(846042, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/846042")] public void MovedOutsideOfMethod1() diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/RudeEditTestBase.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditingTestBase.cs similarity index 99% rename from src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/RudeEditTestBase.cs rename to src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditingTestBase.cs index 17da36a6fd6..903ab341116 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/RudeEditTestBase.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/Helpers/EditingTestBase.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.CSharp.EditAndContinue.UnitTests { - public abstract class RudeEditTestBase : CSharpTestBase + public abstract class EditingTestBase : CSharpTestBase { internal static readonly CSharpEditAndContinueAnalyzer Analyzer = new CSharpEditAndContinueAnalyzer(); diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/LineEditTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/LineEditTests.cs index 220d96032f4..0e894cc9d3e 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/LineEditTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/LineEditTests.cs @@ -8,7 +8,7 @@ namespace Microsoft.CodeAnalysis.CSharp.EditAndContinue.UnitTests { - public class LineEditTests : RudeEditTestBase + public class LineEditTests : EditingTestBase { #region Methods diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/RudeEditStatementTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs similarity index 76% rename from src/EditorFeatures/CSharpTest/EditAndContinue/RudeEditStatementTests.cs rename to src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs index be1d05a8cd1..4abd5f9ad5d 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/RudeEditStatementTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/StatementEditingTests.cs @@ -11,1421 +11,9 @@ namespace Microsoft.CodeAnalysis.CSharp.EditAndContinue.UnitTests { - public class RudeEditStatementTests : RudeEditTestBase + public class StatementEditingTests : EditingTestBase { - #region Matching - - [Fact] - public void Match1() - { - var src1 = @" -int x = 1; -Console.WriteLine(1); -x++/*1A*/; -Console.WriteLine(2); - -while (true) -{ - x++/*2A*/; -} - -Console.WriteLine(1); -"; - var src2 = @" -int x = 1; -x++/*1B*/; -for (int i = 0; i < 10; i++) {} -y++; -if (x > 1) -{ - while (true) - { - x++/*2B*/; - } - - Console.WriteLine(1); -}"; - var match = GetMethodMatch(src1, src2); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "int x = 1;", "int x = 1;" }, - { "int x = 1", "int x = 1" }, - { "x = 1", "x = 1" }, - { "Console.WriteLine(1);", "Console.WriteLine(1);" }, - { "x++/*1A*/;", "x++/*1B*/;" }, - { "Console.WriteLine(2);", "y++;" }, - { "while (true) { x++/*2A*/; }", "while (true) { x++/*2B*/; }" }, - { "{ x++/*2A*/; }", "{ x++/*2B*/; }" }, - { "x++/*2A*/;", "x++/*2B*/;" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void KnownMatches_Root() - { - string src1 = @" -Console.WriteLine(1); -"; - - string src2 = @" -Console.WriteLine(2); -"; - - var m1 = MakeMethodBody(src1); - var m2 = MakeMethodBody(src2); - - var knownMatches = new[] { new KeyValuePair(m1, m2) }; - var match = StatementSyntaxComparer.Default.ComputeMatch(m1, m2, knownMatches); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "Console.WriteLine(1);", "Console.WriteLine(2);" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void Locals_Rename() - { - var src1 = @" -int x = 1; -"; - var src2 = @" -int y = 1; -"; - var match = GetMethodMatch(src1, src2); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "int x = 1;", "int y = 1;" }, - { "int x = 1", "int y = 1" }, - { "x = 1", "y = 1" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void Locals_TypeChange() - { - var src1 = @" -int x = 1; -"; - var src2 = @" -byte x = 1; -"; - var match = GetMethodMatch(src1, src2); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "int x = 1;", "byte x = 1;" }, - { "int x = 1", "byte x = 1" }, - { "x = 1", "x = 1" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void BlocksWithLocals1() - { - var src1 = @" -{ - int a = 1; -} -{ - int b = 2; -} -"; - var src2 = @" -{ - int a = 3; - int b = 4; -} -{ - int b = 5; -} -"; - var match = GetMethodMatch(src1, src2); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "{ int a = 1; }", "{ int a = 3; int b = 4; }" }, - { "int a = 1;", "int a = 3;" }, - { "int a = 1", "int a = 3" }, - { "a = 1", "a = 3" }, - { "{ int b = 2; }", "{ int b = 5; }" }, - { "int b = 2;", "int b = 5;" }, - { "int b = 2", "int b = 5" }, - { "b = 2", "b = 5" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void IfBlocksWithLocals1() - { - var src1 = @" -if (X) -{ - int a = 1; -} -if (Y) -{ - int b = 2; -} -"; - var src2 = @" -if (Y) -{ - int a = 3; - int b = 4; -} -if (X) -{ - int b = 5; -} -"; - var match = GetMethodMatch(src1, src2); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "if (X) { int a = 1; }", "if (Y) { int a = 3; int b = 4; }" }, - { "{ int a = 1; }", "{ int a = 3; int b = 4; }" }, - { "int a = 1;", "int a = 3;" }, - { "int a = 1", "int a = 3" }, - { "a = 1", "a = 3" }, - { "if (Y) { int b = 2; }", "if (X) { int b = 5; }" }, - { "{ int b = 2; }", "{ int b = 5; }" }, - { "int b = 2;", "int b = 5;" }, - { "int b = 2", "int b = 5" }, - { "b = 2", "b = 5" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void BlocksWithLocals2() - { - var src1 = @" -{ - int a = 1; -} -{ - { - int b = 2; - } -} -"; - var src2 = @" -{ - int b = 1; -} -{ - { - int a = 2; - } -} -"; - var match = GetMethodMatch(src1, src2); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "{ int a = 1; }", "{ int a = 2; }" }, - { "int a = 1;", "int a = 2;" }, - { "int a = 1", "int a = 2" }, - { "a = 1", "a = 2" }, - { "{ { int b = 2; } }", "{ { int a = 2; } }" }, - { "{ int b = 2; }", "{ int b = 1; }" }, - { "int b = 2;", "int b = 1;" }, - { "int b = 2", "int b = 1" }, - { "b = 2", "b = 1" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void BlocksWithLocals3() - { - var src1 = @" -{ - int a = 1, b = 2, c = 3; - Console.WriteLine(a + b + c); -} -{ - int c = 4, b = 5, a = 6; - Console.WriteLine(a + b + c); -} -{ - int a = 7, b = 8; - Console.WriteLine(a + b); -} -"; - var src2 = @" -{ - int a = 9, b = 10; - Console.WriteLine(a + b); -} -{ - int c = 11, b = 12, a = 13; - Console.WriteLine(a + b + c); -} -{ - int a = 14, b = 15, c = 16; - Console.WriteLine(a + b + c); -} -"; - var match = GetMethodMatch(src1, src2); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "{ int a = 1, b = 2, c = 3; Console.WriteLine(a + b + c); }", "{ int a = 14, b = 15, c = 16; Console.WriteLine(a + b + c); }" }, - { "int a = 1, b = 2, c = 3;", "int a = 14, b = 15, c = 16;" }, - { "int a = 1, b = 2, c = 3", "int a = 14, b = 15, c = 16" }, - { "a = 1", "a = 14" }, - { "b = 2", "b = 15" }, - { "c = 3", "c = 16" }, - { "Console.WriteLine(a + b + c);", "Console.WriteLine(a + b + c);" }, - { "{ int c = 4, b = 5, a = 6; Console.WriteLine(a + b + c); }", "{ int c = 11, b = 12, a = 13; Console.WriteLine(a + b + c); }" }, - { "int c = 4, b = 5, a = 6;", "int c = 11, b = 12, a = 13;" }, - { "int c = 4, b = 5, a = 6", "int c = 11, b = 12, a = 13" }, - { "c = 4", "c = 11" }, - { "b = 5", "b = 12" }, - { "a = 6", "a = 13" }, - { "Console.WriteLine(a + b + c);", "Console.WriteLine(a + b + c);" }, - { "{ int a = 7, b = 8; Console.WriteLine(a + b); }", "{ int a = 9, b = 10; Console.WriteLine(a + b); }" }, - { "int a = 7, b = 8;", "int a = 9, b = 10;" }, - { "int a = 7, b = 8", "int a = 9, b = 10" }, - { "a = 7", "a = 9" }, - { "b = 8", "b = 10" }, - { "Console.WriteLine(a + b);", "Console.WriteLine(a + b);" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchLambdas1() - { - var src1 = "Action x = a => a;"; - var src2 = "Action x = (a) => a;"; - - var match = GetMethodMatch(src1, src2); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "Action x = a => a;", "Action x = (a) => a;" }, - { "Action x = a => a", "Action x = (a) => a" }, - { "x = a => a", "x = (a) => a" }, - { "a => a", "(a) => a" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchLambdas2a() - { - var src1 = @" -F(x => x + 1, 1, y => y + 1, delegate(int x) { return x; }, async u => u); -"; - var src2 = @" -F(y => y + 1, G(), x => x + 1, (int x) => x, u => u, async (u, v) => u + v); -"; - - var match = GetMethodMatch(src1, src2); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "F(x => x + 1, 1, y => y + 1, delegate(int x) { return x; }, async u => u);", "F(y => y + 1, G(), x => x + 1, (int x) => x, u => u, async (u, v) => u + v);" }, - { "x => x + 1", "x => x + 1" }, - { "y => y + 1", "y => y + 1" }, - { "delegate(int x) { return x; }", "(int x) => x" }, - { "async u => u", "async (u, v) => u + v" }, - }; - - expected.AssertEqual(actual); - } - - [Fact, WorkItem(830419, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/830419")] - public void MatchLambdas2b() - { - var src1 = @" -F(delegate { return x; }); -"; - var src2 = @" -F((a) => x, () => x); -"; - - var match = GetMethodMatch(src1, src2); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "F(delegate { return x; });", "F((a) => x, () => x);" }, - { "delegate { return x; }", "() => x" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchLambdas3() - { - var src1 = @" -a += async u => u; -"; - var src2 = @" -a += u => u; -"; - - var match = GetMethodMatch(src1, src2); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "a += async u => u;", "a += u => u;" }, - { "async u => u", "u => u" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchLambdas4() - { - var src1 = @" -foreach (var a in z) -{ - var e = from q in a.Where(l => l > 10) select q + 1; -} -"; - var src2 = @" -foreach (var a in z) -{ - var e = from q in a.Where(l => l < 0) select q + 1; -} -"; - - var match = GetMethodMatch(src1, src2); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "foreach (var a in z) { var e = from q in a.Where(l => l > 10) select q + 1; }", "foreach (var a in z) { var e = from q in a.Where(l => l < 0) select q + 1; }" }, - { "{ var e = from q in a.Where(l => l > 10) select q + 1; }", "{ var e = from q in a.Where(l => l < 0) select q + 1; }" }, - { "var e = from q in a.Where(l => l > 10) select q + 1;", "var e = from q in a.Where(l => l < 0) select q + 1;" }, - { "var e = from q in a.Where(l => l > 10) select q + 1", "var e = from q in a.Where(l => l < 0) select q + 1" }, - { "e = from q in a.Where(l => l > 10) select q + 1", "e = from q in a.Where(l => l < 0) select q + 1" }, - { "from q in a.Where(l => l > 10)", "from q in a.Where(l => l < 0)" }, - { "l => l > 10", "l => l < 0" }, - { "select q + 1", "select q + 1" }, // select clause - { "select q + 1", "select q + 1" } // query body - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchLambdas5() - { - var src1 = @" -F(a => b => c => d); -"; - var src2 = @" -F(a => b => c => d); -"; - - var matches = GetMethodMatches(src1, src2); - var actual = ToMatchingPairs(matches); - - var expected = new MatchingPairs - { - { "F(a => b => c => d);", "F(a => b => c => d);" }, - { "a => b => c => d", "a => b => c => d" }, - { "b => c => d", "b => c => d" }, - { "c => d", "c => d" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchLambdas6() - { - var src1 = @" -F(a => b => c => d); -"; - var src2 = @" -F(a => G(b => H(c => I(d)))); -"; - - var matches = GetMethodMatches(src1, src2); - var actual = ToMatchingPairs(matches); - - var expected = new MatchingPairs - { - { "F(a => b => c => d);", "F(a => G(b => H(c => I(d))));" }, - { "a => b => c => d", "a => G(b => H(c => I(d)))" }, - { "b => c => d", "b => H(c => I(d))" }, - { "c => d", "c => I(d)" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchLambdas7() - { - var src1 = @" -F(a => -{ - F(c => /*1*/d); - F((u, v) => - { - F((w) => c => /*2*/d); - F(p => p); - }); -}); -"; - var src2 = @" -F(a => -{ - F(c => /*1*/d + 1); - F((u, v) => - { - F((w) => c => /*2*/d + 1); - F(p => p*2); - }); -}); -"; - - var matches = GetMethodMatches(src1, src2); - var actual = ToMatchingPairs(matches); - - var expected = new MatchingPairs - { - { "F(a => { F(c => /*1*/d); F((u, v) => { F((w) => c => /*2*/d); F(p => p); }); });", - "F(a => { F(c => /*1*/d + 1); F((u, v) => { F((w) => c => /*2*/d + 1); F(p => p*2); }); });" }, - { "a => { F(c => /*1*/d); F((u, v) => { F((w) => c => /*2*/d); F(p => p); }); }", - "a => { F(c => /*1*/d + 1); F((u, v) => { F((w) => c => /*2*/d + 1); F(p => p*2); }); }" }, - { "{ F(c => /*1*/d); F((u, v) => { F((w) => c => /*2*/d); F(p => p); }); }", - "{ F(c => /*1*/d + 1); F((u, v) => { F((w) => c => /*2*/d + 1); F(p => p*2); }); }" }, - { "F(c => /*1*/d);", "F(c => /*1*/d + 1);" }, - { "c => /*1*/d", "c => /*1*/d + 1" }, - { "F((u, v) => { F((w) => c => /*2*/d); F(p => p); });", "F((u, v) => { F((w) => c => /*2*/d + 1); F(p => p*2); });" }, - { "(u, v) => { F((w) => c => /*2*/d); F(p => p); }", "(u, v) => { F((w) => c => /*2*/d + 1); F(p => p*2); }" }, - { "{ F((w) => c => /*2*/d); F(p => p); }", "{ F((w) => c => /*2*/d + 1); F(p => p*2); }" }, - { "F((w) => c => /*2*/d);", "F((w) => c => /*2*/d + 1);" }, - { "(w) => c => /*2*/d", "(w) => c => /*2*/d + 1" }, - { "c => /*2*/d", "c => /*2*/d + 1" }, - { "F(p => p);", "F(p => p*2);" }, - { "p => p", "p => p*2" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchQueries1() - { - var src1 = @" -var q = from c in cars - from ud in users_details - from bd in bids - select 1; -"; - var src2 = @" -var q = from c in cars - from bd in bids - from ud in users_details - select 2; -"; - - var match = GetMethodMatch(src1, src2); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "var q = from c in cars from ud in users_details from bd in bids select 1;", "var q = from c in cars from bd in bids from ud in users_details select 2;" }, - { "var q = from c in cars from ud in users_details from bd in bids select 1", "var q = from c in cars from bd in bids from ud in users_details select 2" }, - { "q = from c in cars from ud in users_details from bd in bids select 1", "q = from c in cars from bd in bids from ud in users_details select 2" }, - { "from c in cars", "from c in cars" }, - { "from ud in users_details from bd in bids select 1", "from bd in bids from ud in users_details select 2" }, - { "from ud in users_details", "from ud in users_details" }, - { "from bd in bids", "from bd in bids" }, - { "select 1", "select 2" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchQueries2() - { - var src1 = @" -var q = from c in cars - from ud in users_details - from bd in bids - orderby c.listingOption descending - where a.userID == ud.userid - let images = from ai in auction_images - where ai.belongs_to == c.id - select ai - let bid = (from b in bids - orderby b.id descending - where b.carID == c.id - select b.bidamount).FirstOrDefault() - select bid; -"; - var src2 = @" -var q = from c in cars - from ud in users_details - from bd in bids - orderby c.listingOption descending - where a.userID == ud.userid - let images = from ai in auction_images - where ai.belongs_to == c.id2 - select ai + 1 - let bid = (from b in bids - orderby b.id ascending - where b.carID == c.id2 - select b.bidamount).FirstOrDefault() - select bid; -"; - - var match = GetMethodMatches(src1, src2); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "var q = from c in cars from ud in users_details from bd in bids orderby c.listingOption descending where a.userID == ud.userid let images = from ai in auction_images where ai.belongs_to == c.id select ai let bid = (from b in bids orderby b.id descending where b.carID == c.id select b.bidamount).FirstOrDefault() select bid;", - "var q = from c in cars from ud in users_details from bd in bids orderby c.listingOption descending where a.userID == ud.userid let images = from ai in auction_images where ai.belongs_to == c.id2 select ai + 1 let bid = (from b in bids orderby b.id ascending where b.carID == c.id2 select b.bidamount).FirstOrDefault() select bid;" }, - { "var q = from c in cars from ud in users_details from bd in bids orderby c.listingOption descending where a.userID == ud.userid let images = from ai in auction_images where ai.belongs_to == c.id select ai let bid = (from b in bids orderby b.id descending where b.carID == c.id select b.bidamount).FirstOrDefault() select bid", - "var q = from c in cars from ud in users_details from bd in bids orderby c.listingOption descending where a.userID == ud.userid let images = from ai in auction_images where ai.belongs_to == c.id2 select ai + 1 let bid = (from b in bids orderby b.id ascending where b.carID == c.id2 select b.bidamount).FirstOrDefault() select bid" }, - { "q = from c in cars from ud in users_details from bd in bids orderby c.listingOption descending where a.userID == ud.userid let images = from ai in auction_images where ai.belongs_to == c.id select ai let bid = (from b in bids orderby b.id descending where b.carID == c.id select b.bidamount).FirstOrDefault() select bid", - "q = from c in cars from ud in users_details from bd in bids orderby c.listingOption descending where a.userID == ud.userid let images = from ai in auction_images where ai.belongs_to == c.id2 select ai + 1 let bid = (from b in bids orderby b.id ascending where b.carID == c.id2 select b.bidamount).FirstOrDefault() select bid" }, - { "from c in cars", "from c in cars" }, - { "from ud in users_details from bd in bids orderby c.listingOption descending where a.userID == ud.userid let images = from ai in auction_images where ai.belongs_to == c.id select ai let bid = (from b in bids orderby b.id descending where b.carID == c.id select b.bidamount).FirstOrDefault() select bid", "from ud in users_details from bd in bids orderby c.listingOption descending where a.userID == ud.userid let images = from ai in auction_images where ai.belongs_to == c.id2 select ai + 1 let bid = (from b in bids orderby b.id ascending where b.carID == c.id2 select b.bidamount).FirstOrDefault() select bid" }, - { "from ud in users_details", "from ud in users_details" }, - { "from bd in bids", "from bd in bids" }, - { "orderby c.listingOption descending", "orderby c.listingOption descending" }, - { "c.listingOption descending", "c.listingOption descending" }, - { "where a.userID == ud.userid", "where a.userID == ud.userid" }, - { "let images = from ai in auction_images where ai.belongs_to == c.id select ai", - "let images = from ai in auction_images where ai.belongs_to == c.id2 select ai + 1" }, - { "from ai in auction_images", "from ai in auction_images" }, - { "where ai.belongs_to == c.id select ai", "where ai.belongs_to == c.id2 select ai + 1" }, - { "where ai.belongs_to == c.id", "where ai.belongs_to == c.id2" }, - { "select ai", "select ai + 1" }, - { "let bid = (from b in bids orderby b.id descending where b.carID == c.id select b.bidamount).FirstOrDefault()", - "let bid = (from b in bids orderby b.id ascending where b.carID == c.id2 select b.bidamount).FirstOrDefault()" }, - { "from b in bids", "from b in bids" }, - { "orderby b.id descending where b.carID == c.id select b.bidamount", "orderby b.id ascending where b.carID == c.id2 select b.bidamount" }, - { "orderby b.id descending", "orderby b.id ascending" }, - { "b.id descending", "b.id ascending" }, - { "where b.carID == c.id", "where b.carID == c.id2" }, - { "select b.bidamount", "select b.bidamount" }, - { "select bid", "select bid" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchQueries3() - { - var src1 = @" -var q = from a in await seq1 - join c in await seq2 on F(u => u) equals G(s => s) into g1 - join l in await seq3 on F(v => v) equals G(t => t) into g2 - select a; - -"; - var src2 = @" -var q = from a in await seq1 - join c in await seq2 on F(u => u + 1) equals G(s => s + 3) into g1 - join c in await seq3 on F(vv => vv + 2) equals G(tt => tt + 4) into g2 - select a + 1; -"; - - var match = GetMethodMatches(src1, src2); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "var q = from a in await seq1 join c in await seq2 on F(u => u) equals G(s => s) into g1 join l in await seq3 on F(v => v) equals G(t => t) into g2 select a;", "var q = from a in await seq1 join c in await seq2 on F(u => u + 1) equals G(s => s + 3) into g1 join c in await seq3 on F(vv => vv + 2) equals G(tt => tt + 4) into g2 select a + 1;" }, - { "var q = from a in await seq1 join c in await seq2 on F(u => u) equals G(s => s) into g1 join l in await seq3 on F(v => v) equals G(t => t) into g2 select a", "var q = from a in await seq1 join c in await seq2 on F(u => u + 1) equals G(s => s + 3) into g1 join c in await seq3 on F(vv => vv + 2) equals G(tt => tt + 4) into g2 select a + 1" }, - { "q = from a in await seq1 join c in await seq2 on F(u => u) equals G(s => s) into g1 join l in await seq3 on F(v => v) equals G(t => t) into g2 select a", "q = from a in await seq1 join c in await seq2 on F(u => u + 1) equals G(s => s + 3) into g1 join c in await seq3 on F(vv => vv + 2) equals G(tt => tt + 4) into g2 select a + 1" }, - { "from a in await seq1", "from a in await seq1" }, - { "await seq1", "await seq1" }, - { "join c in await seq2 on F(u => u) equals G(s => s) into g1 join l in await seq3 on F(v => v) equals G(t => t) into g2 select a", "join c in await seq2 on F(u => u + 1) equals G(s => s + 3) into g1 join c in await seq3 on F(vv => vv + 2) equals G(tt => tt + 4) into g2 select a + 1" }, - { "join c in await seq2 on F(u => u) equals G(s => s) into g1", "join c in await seq2 on F(u => u + 1) equals G(s => s + 3) into g1" }, - { "await seq2", "await seq2" }, - { "u => u", "u => u + 1" }, - { "s => s", "s => s + 3" }, - { "into g1", "into g1" }, - { "join l in await seq3 on F(v => v) equals G(t => t) into g2", "join c in await seq3 on F(vv => vv + 2) equals G(tt => tt + 4) into g2" }, - { "await seq3", "await seq3" }, - { "v => v", "vv => vv + 2" }, - { "t => t", "tt => tt + 4" }, - { "into g2", "into g2" }, - { "select a", "select a + 1" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchQueries4() - { - var src1 = "F(from a in await b from x in y select c);"; - var src2 = "F(from a in await c from x in y select c);"; - - var match = GetMethodMatches(src1, src2); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "F(from a in await b from x in y select c);", "F(from a in await c from x in y select c);" }, - { "from a in await b", "from a in await c" }, - { "await b", "await c" }, - { "from x in y select c", "from x in y select c" }, - { "from x in y", "from x in y" }, - { "select c", "select c" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchQueries5() - { - var src1 = "F(from a in b group a by a.x into g select g);"; - var src2 = "F(from a in b group z by z.y into h select h);"; - - var match = GetMethodMatches(src1, src2); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "F(from a in b group a by a.x into g select g);", "F(from a in b group z by z.y into h select h);" }, - { "from a in b", "from a in b" }, - { "group a by a.x into g select g", "group z by z.y into h select h" }, - { "group a by a.x", "group z by z.y" }, - { "into g select g", "into h select h" }, - { "select g", "select h" }, - { "select g", "select h" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchYields() - { - var src1 = @" -yield return /*1*/ 1; - -{ - yield return /*2*/ 2; -} - -foreach (var x in y) { yield return /*3*/ 3; } -"; - var src2 = @" -yield return /*1*/ 1; -yield return /*2*/ 3; -foreach (var x in y) { yield return /*3*/ 2; } -"; - - var match = GetMethodMatches(src1, src2, kind: MethodKind.Iterator); - var actual = ToMatchingPairs(match); - - // note that yield returns are matched in source order, regardless of the yielded expressions: - var expected = new MatchingPairs - { - { "yield return /*1*/ 1;", "yield return /*1*/ 1;" }, - { "{ yield return /*2*/ 2; }", "{ yield return /*3*/ 2; }" }, - { "yield return /*2*/ 2;", "yield return /*2*/ 3;" }, - { "foreach (var x in y) { yield return /*3*/ 3; }", "foreach (var x in y) { yield return /*3*/ 2; }" }, - { "yield return /*3*/ 3;", "yield return /*3*/ 2;" }, - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void KnownMatches() - { - string src1 = @" -Console.WriteLine(1)/*1*/; -Console.WriteLine(1)/*2*/; -"; - - string src2 = @" -Console.WriteLine(1)/*3*/; -Console.WriteLine(1)/*4*/; -"; - - var m1 = MakeMethodBody(src1); - var m2 = MakeMethodBody(src2); - - var knownMatches = new KeyValuePair[] - { - new KeyValuePair(m1.Statements[1], m2.Statements[0]) - }; - - // pre-matched: - - var match = StatementSyntaxComparer.Default.ComputeMatch(m1, m2, knownMatches); - - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "Console.WriteLine(1)/*1*/;", "Console.WriteLine(1)/*4*/;" }, - { "Console.WriteLine(1)/*2*/;", "Console.WriteLine(1)/*3*/;" } - }; - - expected.AssertEqual(actual); - - // not pre-matched: - - match = StatementSyntaxComparer.Default.ComputeMatch(m1, m2); - - actual = ToMatchingPairs(match); - - expected = new MatchingPairs - { - { "Console.WriteLine(1)/*1*/;", "Console.WriteLine(1)/*3*/;" }, - { "Console.WriteLine(1)/*2*/;", "Console.WriteLine(1)/*4*/;" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchConstructorWithInitializer1() - { - var src1 = @" -(int x = 1) : base(a => a + 1) { Console.WriteLine(1); } -"; - var src2 = @" -(int x = 1) : base(a => a + 1) { Console.WriteLine(1); } -"; - - var match = GetMethodMatches(src1, src2, kind: MethodKind.ConstructorWithParameters); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "a => a + 1", "a => a + 1" }, - { "{ Console.WriteLine(1); }", "{ Console.WriteLine(1); }" }, - { "Console.WriteLine(1);", "Console.WriteLine(1);" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchConstructorWithInitializer2() - { - var src1 = @" -() : base(a => a + 1) { Console.WriteLine(1); } -"; - var src2 = @" -() { Console.WriteLine(1); } -"; - - var match = GetMethodMatches(src1, src2, kind: MethodKind.ConstructorWithParameters); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "{ Console.WriteLine(1); }", "{ Console.WriteLine(1); }" }, - { "Console.WriteLine(1);", "Console.WriteLine(1);" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchExceptionHandlers() - { - var src1 = @" -try { throw new InvalidOperationException(1); } -catch (IOException e) when (filter(e)) { Console.WriteLine(2); } -catch (Exception e) when (filter(e)) { Console.WriteLine(3); } -"; - var src2 = @" -try { throw new InvalidOperationException(10); } -catch (IOException e) when (filter(e)) { Console.WriteLine(20); } -catch (Exception e) when (filter(e)) { Console.WriteLine(30); } -"; - - var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "try { throw new InvalidOperationException(1); } catch (IOException e) when (filter(e)) { Console.WriteLine(2); } catch (Exception e) when (filter(e)) { Console.WriteLine(3); }", "try { throw new InvalidOperationException(10); } catch (IOException e) when (filter(e)) { Console.WriteLine(20); } catch (Exception e) when (filter(e)) { Console.WriteLine(30); }" }, - { "{ throw new InvalidOperationException(1); }", "{ throw new InvalidOperationException(10); }" }, - { "throw new InvalidOperationException(1);", "throw new InvalidOperationException(10);" }, - { "catch (IOException e) when (filter(e)) { Console.WriteLine(2); }", "catch (IOException e) when (filter(e)) { Console.WriteLine(20); }" }, - { "(IOException e)", "(IOException e)" }, - { "when (filter(e))", "when (filter(e))" }, - { "{ Console.WriteLine(2); }", "{ Console.WriteLine(20); }" }, - { "Console.WriteLine(2);", "Console.WriteLine(20);" }, - { "catch (Exception e) when (filter(e)) { Console.WriteLine(3); }", "catch (Exception e) when (filter(e)) { Console.WriteLine(30); }" }, - { "(Exception e)", "(Exception e)" }, - { "when (filter(e))", "when (filter(e))" }, - { "{ Console.WriteLine(3); }", "{ Console.WriteLine(30); }" }, - { "Console.WriteLine(3);", "Console.WriteLine(30);" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchTuple() - { - var src1 = @" -return (1, 2); -return (d, 6); -return (10, e, 22); -return (2, () => { - int a = 6; - return 1; -});"; - - var src2 = @" -return (1, 2, 3); -return (d, 5); -return (10, e); -return (2, () => { - int a = 6; - return 5; -});"; - - var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "return (1, 2);", "return (1, 2, 3);" }, - { "return (d, 6);", "return (d, 5);" }, - { "return (10, e, 22);", "return (10, e);" }, - { "return (2, () => { int a = 6; return 1; });", "return (2, () => { int a = 6; return 5; });" }, - { "() => { int a = 6; return 1; }", "() => { int a = 6; return 5; }" }, - { "{ int a = 6; return 1; }", "{ int a = 6; return 5; }" }, - { "int a = 6;", "int a = 6;" }, - { "int a = 6", "int a = 6" }, - { "a = 6", "a = 6" }, - { "return 1;", "return 5;" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchLocalFunctionDefinitions() - { - var src1 = @" -(int a, string c) F1(int i) { return null; } -(int a, int b) F2(int i) { return null; } -(int a, int b, int c) F3(int i) { return null; } -"; - - var src2 = @" -(int a, int b) F1(int i) { return null; } -(int a, int b, string c) F2(int i) { return null; } -(int a, int b) F3(int i) { return null; } -"; - - var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "(int a, string c) F1(int i) { return null; }", "(int a, int b) F1(int i) { return null; }" }, - { "{ return null; }", "{ return null; }" }, - { "return null;", "return null;" }, - { "(int a, int b) F2(int i) { return null; }", "(int a, int b, string c) F2(int i) { return null; }" }, - { "{ return null; }", "{ return null; }" }, - { "return null;", "return null;" }, - { "(int a, int b, int c) F3(int i) { return null; }", "(int a, int b) F3(int i) { return null; }" }, - { "{ return null; }", "{ return null; }" }, - { "return null;", "return null;" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchVariableDesignations() - { - var src1 = @" -M(out int z); -N(out var a); -"; - - var src2 = @" -M(out var z); -N(out var b); -"; - - var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "M(out int z);", "M(out var z);" }, - { "z", "z" }, - { "N(out var a);", "N(out var b);" }, - { "a", "b" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchParenthesizedVariable_Update() - { - var src1 = @" -var (x1, (x2, x3)) = (1, (2, true)); -var (a1, a2) = (1, () => { return 7; }); -"; - - var src2 = @" -var (x1, (x3, x4)) = (1, (2, true)); -var (a1, a3) = (1, () => { return 8; }); -"; - - var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "var (x1, (x2, x3)) = (1, (2, true));", "var (x1, (x3, x4)) = (1, (2, true));" }, - { "x1", "x1" }, - { "x2", "x4" }, - { "x3", "x3" }, - { "var (a1, a2) = (1, () => { return 7; });", "var (a1, a3) = (1, () => { return 8; });" }, - { "a1", "a1" }, - { "a2", "a3" }, - { "() => { return 7; }", "() => { return 8; }" }, - { "{ return 7; }", "{ return 8; }" }, - { "return 7;", "return 8;" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchParenthesizedVariable_Insert() - { - var src1 = @"var (z1, z2) = (1, 2);"; - var src2 = @"var (z1, z2, z3) = (1, 2, 5);"; - - var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "var (z1, z2) = (1, 2);", "var (z1, z2, z3) = (1, 2, 5);" }, - { "z1", "z1" }, - { "z2", "z2" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchParenthesizedVariable_Delete() - { - var src1 = @"var (y1, y2, y3) = (1, 2, 7);"; - var src2 = @"var (y1, y2) = (1, 4);"; - - var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "var (y1, y2, y3) = (1, 2, 7);", "var (y1, y2) = (1, 4);" }, - { "y1", "y1" }, - { "y2", "y2" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchForeachVariable_Update1() - { - var src1 = @" -foreach (var (a1, a2) in e) { A1(); } -foreach ((var b1, var b2) in e) { A2(); } -"; - - var src2 = @" -foreach (var (a1, a3) in e) { A1(); } -foreach ((var b3, int b2) in e) { A2(); } -"; - - var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "foreach (var (a1, a2) in e) { A1(); }", "foreach (var (a1, a3) in e) { A1(); }" }, - { "a1", "a1" }, - { "a2", "a3" }, - { "{ A1(); }", "{ A1(); }" }, - { "A1();", "A1();" }, - { "foreach ((var b1, var b2) in e) { A2(); }", "foreach ((var b3, int b2) in e) { A2(); }" }, - { "b1", "b3" }, - { "b2", "b2" }, - { "{ A2(); }", "{ A2(); }" }, - { "A2();", "A2();" }, - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchForeachVariable_Update2() - { - var src1 = @" -foreach (_ in e2) { yield return 4; } -foreach (_ in e3) { A(); } -"; - - var src2 = @" -foreach (_ in e4) { A(); } -foreach (var b in e2) { yield return 4; } -"; - - var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "foreach (_ in e2) { yield return 4; }", "foreach (var b in e2) { yield return 4; }" }, - { "{ yield return 4; }", "{ yield return 4; }" }, - { "yield return 4;", "yield return 4;" }, - { "foreach (_ in e3) { A(); }", "foreach (_ in e4) { A(); }" }, - { "{ A(); }", "{ A(); }" }, - { "A();", "A();" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchForeachVariable_Insert() - { - var src1 = @" -foreach (var (a3, a4) in e) { } -foreach ((var b4, var b5) in e) { } -"; - - var src2 = @" -foreach (var (a3, a5, a4) in e) { } -foreach ((var b6, var b4, var b5) in e) { } -"; - - var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "foreach (var (a3, a4) in e) { }", "foreach (var (a3, a5, a4) in e) { }" }, - { "a3", "a3" }, - { "a4", "a4" }, - { "{ }", "{ }" }, - { "foreach ((var b4, var b5) in e) { }", "foreach ((var b6, var b4, var b5) in e) { }" }, - { "b4", "b4" }, - { "b5", "b5" }, - { "{ }", "{ }" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchForeachVariable_Delete() - { - var src1 = @" -foreach (var (a11, a12, a13) in e) { A1(); } -foreach ((var b7, var b8, var b9) in e) { A2(); } -"; - - var src2 = @" -foreach (var (a12, a13) in e1) { A1(); } -foreach ((var b7, var b9) in e) { A2(); } -"; - - var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "foreach (var (a11, a12, a13) in e) { A1(); }", "foreach (var (a12, a13) in e1) { A1(); }" }, - { "a12", "a12" }, - { "a13", "a13" }, - { "{ A1(); }", "{ A1(); }" }, - { "A1();", "A1();" }, - { "foreach ((var b7, var b8, var b9) in e) { A2(); }", "foreach ((var b7, var b9) in e) { A2(); }" }, - { "b7", "b7" }, - { "b9", "b9" }, - { "{ A2(); }", "{ A2(); }" }, - { "A2();", "A2();" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchConstantPattern() - { - var src1 = @" -if ((o is null) && (y == 7)) return 3; -if (a is 7) return 5; -"; - - var src2 = @" -if ((o1 is null) && (y == 7)) return 3; -if (a is 77) return 5; -"; - - var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs { - { "if ((o is null) && (y == 7)) return 3;", "if ((o1 is null) && (y == 7)) return 3;" }, - { "return 3;", "return 3;" }, - { "if (a is 7) return 5;", "if (a is 77) return 5;" }, - { "return 5;", "return 5;" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchDeclarationPattern() - { - var src1 = @" -if (!(o is int i) && (y == 7)) return; -if (!(a is string s)) return; -if (!(b is string t)) return; -if (!(c is int j)) return; -"; - - var src2 = @" -if (!(b is string t1)) return; -if (!(o1 is int i) && (y == 7)) return; -if (!(c is int)) return; -if (!(a is int s)) return; -"; - - var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs { - { "if (!(o is int i) && (y == 7)) return;", "if (!(o1 is int i) && (y == 7)) return;" }, - { "i", "i" }, - { "return;", "return;" }, - { "if (!(a is string s)) return;", "if (!(a is int s)) return;" }, - { "s", "s" }, - { "return;", "return;" }, - { "if (!(b is string t)) return;", "if (!(b is string t1)) return;" }, - { "t", "t1" }, - { "return;", "return;" }, - { "if (!(c is int j)) return;", "if (!(c is int)) return;" }, - { "return;", "return;" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchCasePattern_UpdateInsert() - { - var src1 = @" -switch(shape) -{ - case Circle c: return 1; - default: return 4; -} -"; - - var src2 = @" -switch(shape) -{ - case Circle c1: return 1; - case Point p: return 0; - default: return 4; -} -"; - - var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs { - { "switch(shape) { case Circle c: return 1; default: return 4; }", "switch(shape) { case Circle c1: return 1; case Point p: return 0; default: return 4; }" }, - { "case Circle c: return 1;", "case Circle c1: return 1;" }, - { "case Circle c:", "case Circle c1:" }, - { "c", "c1" }, - { "return 1;", "return 1;" }, - { "default: return 4;", "default: return 4;" }, - { "return 4;", "return 4;" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchWhenCondition() - { - var src1 = @" -switch(shape) -{ - case Circle c when (c < 10): return 1; - case Circle c when (c > 100): return 2; -} -"; - - var src2 = @" -switch(shape) -{ - case Circle c when (c < 5): return 1; - case Circle c2 when (c2 > 100): return 2; -} -"; - - var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "switch(shape) { case Circle c when (c < 10): return 1; case Circle c when (c > 100): return 2; }", "switch(shape) { case Circle c when (c < 5): return 1; case Circle c2 when (c2 > 100): return 2; }" }, - { "case Circle c when (c < 10): return 1;", "case Circle c when (c < 5): return 1;" }, - { "case Circle c when (c < 10):", "case Circle c when (c < 5):" }, - { "c", "c" }, - { "when (c < 10)", "when (c < 5)" }, - { "return 1;", "return 1;" }, - { "case Circle c when (c > 100): return 2;", "case Circle c2 when (c2 > 100): return 2;" }, - { "case Circle c when (c > 100):", "case Circle c2 when (c2 > 100):" }, - { "c", "c2" }, - { "when (c > 100)", "when (c2 > 100)" }, - { "return 2;", "return 2;" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchRef() - { - var src1 = @" -ref int a = ref G(new int[] { 1, 2 }); - ref int G(int[] p) - { - return ref p[1]; - } -"; - - var src2 = @" -ref int32 a = ref G1(new int[] { 1, 2 }); - ref int G1(int[] p) - { - return ref p[2]; - } -"; - - var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "ref int a = ref G(new int[] { 1, 2 });", "ref int32 a = ref G1(new int[] { 1, 2 });" }, - { "ref int a = ref G(new int[] { 1, 2 })", "ref int32 a = ref G1(new int[] { 1, 2 })" }, - { "a = ref G(new int[] { 1, 2 })", "a = ref G1(new int[] { 1, 2 })" }, - { "ref int G(int[] p) { return ref p[1]; }", "ref int G1(int[] p) { return ref p[2]; }" }, - { "{ return ref p[1]; }", "{ return ref p[2]; }" }, - { "return ref p[1];", "return ref p[2];" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchThrowException_UpdateInsert() - { - var src1 = @" -return a > 3 ? a : throw new Exception(); -return c > 7 ? c : 7; -"; - - var src2 = @" -return a > 3 ? a : throw new ArgumentException(); -return c > 7 ? c : throw new IndexOutOfRangeException(); -"; - - var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "return a > 3 ? a : throw new Exception();", "return a > 3 ? a : throw new ArgumentException();" }, - { "return c > 7 ? c : 7;", "return c > 7 ? c : throw new IndexOutOfRangeException();" } - }; - - expected.AssertEqual(actual); - } - - [Fact] - public void MatchThrowException_UpdateDelete() - { - var src1 = @" -return a > 3 ? a : throw new Exception(); -return b > 5 ? b : throw new OperationCanceledException(); -"; - - var src2 = @" -return a > 3 ? a : throw new ArgumentException(); -return b > 5 ? b : 5; -"; - - var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs - { - { "return a > 3 ? a : throw new Exception();", "return a > 3 ? a : throw new ArgumentException();" }, - { "return b > 5 ? b : throw new OperationCanceledException();", "return b > 5 ? b : 5;" } - }; - - expected.AssertEqual(actual); - } + #region Strings [Fact] public void StringLiteral_update() @@ -1483,38 +71,6 @@ public void InterpolationFormatClause_update() edits.VerifyEdits("Update [x = $\"Hello{123:N1}\"]@8 -> [x = $\"Hello{123:N2}\"]@8"); } - [Fact] - public void MatchCasePattern_UpdateDelete() - { - var src1 = @" -switch(shape) -{ - case Point p: return 0; - case Circle c: return 1; -} -"; - - var src2 = @" -switch(shape) -{ - case Circle circle: return 1; -} -"; - - var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); - var actual = ToMatchingPairs(match); - - var expected = new MatchingPairs { - { "switch(shape) { case Point p: return 0; case Circle c: return 1; }", "switch(shape) { case Circle circle: return 1; }" }, - { "case Circle c: return 1;", "case Circle circle: return 1;" }, - { "case Circle c:", "case Circle circle:" }, - { "c", "circle" }, - { "return 1;", "return 1;" } - }; - - expected.AssertEqual(actual); - } - #endregion #region Variable Declaration diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/StatementMatchingTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/StatementMatchingTests.cs new file mode 100644 index 00000000000..5be548928ec --- /dev/null +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/StatementMatchingTests.cs @@ -0,0 +1,1500 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Generic; +using Microsoft.CodeAnalysis.EditAndContinue.UnitTests; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.EditAndContinue.UnitTests +{ + public class StatementMatchingTests : EditingTestBase + { + #region Known Matches + + [Fact] + public void KnownMatches() + { + string src1 = @" +Console.WriteLine(1)/*1*/; +Console.WriteLine(1)/*2*/; +"; + + string src2 = @" +Console.WriteLine(1)/*3*/; +Console.WriteLine(1)/*4*/; +"; + + var m1 = MakeMethodBody(src1); + var m2 = MakeMethodBody(src2); + + var knownMatches = new KeyValuePair[] + { + new KeyValuePair(m1.Statements[1], m2.Statements[0]) + }; + + // pre-matched: + + var match = StatementSyntaxComparer.Default.ComputeMatch(m1, m2, knownMatches); + + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "Console.WriteLine(1)/*1*/;", "Console.WriteLine(1)/*4*/;" }, + { "Console.WriteLine(1)/*2*/;", "Console.WriteLine(1)/*3*/;" } + }; + + expected.AssertEqual(actual); + + // not pre-matched: + + match = StatementSyntaxComparer.Default.ComputeMatch(m1, m2); + + actual = ToMatchingPairs(match); + + expected = new MatchingPairs + { + { "Console.WriteLine(1)/*1*/;", "Console.WriteLine(1)/*3*/;" }, + { "Console.WriteLine(1)/*2*/;", "Console.WriteLine(1)/*4*/;" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void KnownMatches_Root() + { + string src1 = @" +Console.WriteLine(1); +"; + + string src2 = @" +Console.WriteLine(2); +"; + + var m1 = MakeMethodBody(src1); + var m2 = MakeMethodBody(src2); + + var knownMatches = new[] { new KeyValuePair(m1, m2) }; + var match = StatementSyntaxComparer.Default.ComputeMatch(m1, m2, knownMatches); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "Console.WriteLine(1);", "Console.WriteLine(2);" } + }; + + expected.AssertEqual(actual); + } + + #endregion + + #region Statements + + [Fact] + public void MiscStatements() + { + var src1 = @" +int x = 1; +Console.WriteLine(1); +x++/*1A*/; +Console.WriteLine(2); + +while (true) +{ + x++/*2A*/; +} + +Console.WriteLine(1); +"; + var src2 = @" +int x = 1; +x++/*1B*/; +for (int i = 0; i < 10; i++) {} +y++; +if (x > 1) +{ + while (true) + { + x++/*2B*/; + } + + Console.WriteLine(1); +}"; + var match = GetMethodMatch(src1, src2); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "int x = 1;", "int x = 1;" }, + { "int x = 1", "int x = 1" }, + { "x = 1", "x = 1" }, + { "Console.WriteLine(1);", "Console.WriteLine(1);" }, + { "x++/*1A*/;", "x++/*1B*/;" }, + { "Console.WriteLine(2);", "y++;" }, + { "while (true) { x++/*2A*/; }", "while (true) { x++/*2B*/; }" }, + { "{ x++/*2A*/; }", "{ x++/*2B*/; }" }, + { "x++/*2A*/;", "x++/*2B*/;" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void ThrowException_UpdateInsert() + { + var src1 = @" +return a > 3 ? a : throw new Exception(); +return c > 7 ? c : 7; +"; + + var src2 = @" +return a > 3 ? a : throw new ArgumentException(); +return c > 7 ? c : throw new IndexOutOfRangeException(); +"; + + var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "return a > 3 ? a : throw new Exception();", "return a > 3 ? a : throw new ArgumentException();" }, + { "return c > 7 ? c : 7;", "return c > 7 ? c : throw new IndexOutOfRangeException();" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void ThrowException_UpdateDelete() + { + var src1 = @" +return a > 3 ? a : throw new Exception(); +return b > 5 ? b : throw new OperationCanceledException(); +"; + + var src2 = @" +return a > 3 ? a : throw new ArgumentException(); +return b > 5 ? b : 5; +"; + + var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "return a > 3 ? a : throw new Exception();", "return a > 3 ? a : throw new ArgumentException();" }, + { "return b > 5 ? b : throw new OperationCanceledException();", "return b > 5 ? b : 5;" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void Tuple() + { + var src1 = @" +return (1, 2); +return (d, 6); +return (10, e, 22); +return (2, () => { + int a = 6; + return 1; +});"; + + var src2 = @" +return (1, 2, 3); +return (d, 5); +return (10, e); +return (2, () => { + int a = 6; + return 5; +});"; + + var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "return (1, 2);", "return (1, 2, 3);" }, + { "return (d, 6);", "return (d, 5);" }, + { "return (10, e, 22);", "return (10, e);" }, + { "return (2, () => { int a = 6; return 1; });", "return (2, () => { int a = 6; return 5; });" }, + { "() => { int a = 6; return 1; }", "() => { int a = 6; return 5; }" }, + { "{ int a = 6; return 1; }", "{ int a = 6; return 5; }" }, + { "int a = 6;", "int a = 6;" }, + { "int a = 6", "int a = 6" }, + { "a = 6", "a = 6" }, + { "return 1;", "return 5;" } + }; + + expected.AssertEqual(actual); + } + + #endregion + + #region Local Variables + + [Fact] + public void Locals_Rename() + { + var src1 = @" +int x = 1; +"; + var src2 = @" +int y = 1; +"; + var match = GetMethodMatch(src1, src2); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "int x = 1;", "int y = 1;" }, + { "int x = 1", "int y = 1" }, + { "x = 1", "y = 1" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void Locals_TypeChange() + { + var src1 = @" +int x = 1; +"; + var src2 = @" +byte x = 1; +"; + var match = GetMethodMatch(src1, src2); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "int x = 1;", "byte x = 1;" }, + { "int x = 1", "byte x = 1" }, + { "x = 1", "x = 1" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void BlocksWithLocals1() + { + var src1 = @" +{ + int a = 1; +} +{ + int b = 2; +} +"; + var src2 = @" +{ + int a = 3; + int b = 4; +} +{ + int b = 5; +} +"; + var match = GetMethodMatch(src1, src2); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "{ int a = 1; }", "{ int a = 3; int b = 4; }" }, + { "int a = 1;", "int a = 3;" }, + { "int a = 1", "int a = 3" }, + { "a = 1", "a = 3" }, + { "{ int b = 2; }", "{ int b = 5; }" }, + { "int b = 2;", "int b = 5;" }, + { "int b = 2", "int b = 5" }, + { "b = 2", "b = 5" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void IfBlocksWithLocals1() + { + var src1 = @" +if (X) +{ + int a = 1; +} +if (Y) +{ + int b = 2; +} +"; + var src2 = @" +if (Y) +{ + int a = 3; + int b = 4; +} +if (X) +{ + int b = 5; +} +"; + var match = GetMethodMatch(src1, src2); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "if (X) { int a = 1; }", "if (Y) { int a = 3; int b = 4; }" }, + { "{ int a = 1; }", "{ int a = 3; int b = 4; }" }, + { "int a = 1;", "int a = 3;" }, + { "int a = 1", "int a = 3" }, + { "a = 1", "a = 3" }, + { "if (Y) { int b = 2; }", "if (X) { int b = 5; }" }, + { "{ int b = 2; }", "{ int b = 5; }" }, + { "int b = 2;", "int b = 5;" }, + { "int b = 2", "int b = 5" }, + { "b = 2", "b = 5" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void BlocksWithLocals2() + { + var src1 = @" +{ + int a = 1; +} +{ + { + int b = 2; + } +} +"; + var src2 = @" +{ + int b = 1; +} +{ + { + int a = 2; + } +} +"; + var match = GetMethodMatch(src1, src2); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "{ int a = 1; }", "{ int a = 2; }" }, + { "int a = 1;", "int a = 2;" }, + { "int a = 1", "int a = 2" }, + { "a = 1", "a = 2" }, + { "{ { int b = 2; } }", "{ { int a = 2; } }" }, + { "{ int b = 2; }", "{ int b = 1; }" }, + { "int b = 2;", "int b = 1;" }, + { "int b = 2", "int b = 1" }, + { "b = 2", "b = 1" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void BlocksWithLocals3() + { + var src1 = @" +{ + int a = 1, b = 2, c = 3; + Console.WriteLine(a + b + c); +} +{ + int c = 4, b = 5, a = 6; + Console.WriteLine(a + b + c); +} +{ + int a = 7, b = 8; + Console.WriteLine(a + b); +} +"; + var src2 = @" +{ + int a = 9, b = 10; + Console.WriteLine(a + b); +} +{ + int c = 11, b = 12, a = 13; + Console.WriteLine(a + b + c); +} +{ + int a = 14, b = 15, c = 16; + Console.WriteLine(a + b + c); +} +"; + var match = GetMethodMatch(src1, src2); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "{ int a = 1, b = 2, c = 3; Console.WriteLine(a + b + c); }", "{ int a = 14, b = 15, c = 16; Console.WriteLine(a + b + c); }" }, + { "int a = 1, b = 2, c = 3;", "int a = 14, b = 15, c = 16;" }, + { "int a = 1, b = 2, c = 3", "int a = 14, b = 15, c = 16" }, + { "a = 1", "a = 14" }, + { "b = 2", "b = 15" }, + { "c = 3", "c = 16" }, + { "Console.WriteLine(a + b + c);", "Console.WriteLine(a + b + c);" }, + { "{ int c = 4, b = 5, a = 6; Console.WriteLine(a + b + c); }", "{ int c = 11, b = 12, a = 13; Console.WriteLine(a + b + c); }" }, + { "int c = 4, b = 5, a = 6;", "int c = 11, b = 12, a = 13;" }, + { "int c = 4, b = 5, a = 6", "int c = 11, b = 12, a = 13" }, + { "c = 4", "c = 11" }, + { "b = 5", "b = 12" }, + { "a = 6", "a = 13" }, + { "Console.WriteLine(a + b + c);", "Console.WriteLine(a + b + c);" }, + { "{ int a = 7, b = 8; Console.WriteLine(a + b); }", "{ int a = 9, b = 10; Console.WriteLine(a + b); }" }, + { "int a = 7, b = 8;", "int a = 9, b = 10;" }, + { "int a = 7, b = 8", "int a = 9, b = 10" }, + { "a = 7", "a = 9" }, + { "b = 8", "b = 10" }, + { "Console.WriteLine(a + b);", "Console.WriteLine(a + b);" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void VariableDesignations() + { + var src1 = @" +M(out int z); +N(out var a); +"; + + var src2 = @" +M(out var z); +N(out var b); +"; + + var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "M(out int z);", "M(out var z);" }, + { "z", "z" }, + { "N(out var a);", "N(out var b);" }, + { "a", "b" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void ParenthesizedVariable_Update() + { + var src1 = @" +var (x1, (x2, x3)) = (1, (2, true)); +var (a1, a2) = (1, () => { return 7; }); +"; + + var src2 = @" +var (x1, (x3, x4)) = (1, (2, true)); +var (a1, a3) = (1, () => { return 8; }); +"; + + var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "var (x1, (x2, x3)) = (1, (2, true));", "var (x1, (x3, x4)) = (1, (2, true));" }, + { "x1", "x1" }, + { "x2", "x4" }, + { "x3", "x3" }, + { "var (a1, a2) = (1, () => { return 7; });", "var (a1, a3) = (1, () => { return 8; });" }, + { "a1", "a1" }, + { "a2", "a3" }, + { "() => { return 7; }", "() => { return 8; }" }, + { "{ return 7; }", "{ return 8; }" }, + { "return 7;", "return 8;" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void ParenthesizedVariable_Insert() + { + var src1 = @"var (z1, z2) = (1, 2);"; + var src2 = @"var (z1, z2, z3) = (1, 2, 5);"; + + var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "var (z1, z2) = (1, 2);", "var (z1, z2, z3) = (1, 2, 5);" }, + { "z1", "z1" }, + { "z2", "z2" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void ParenthesizedVariable_Delete() + { + var src1 = @"var (y1, y2, y3) = (1, 2, 7);"; + var src2 = @"var (y1, y2) = (1, 4);"; + + var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "var (y1, y2, y3) = (1, 2, 7);", "var (y1, y2) = (1, 4);" }, + { "y1", "y1" }, + { "y2", "y2" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void RefVariable() + { + var src1 = @" +ref int a = ref G(new int[] { 1, 2 }); + ref int G(int[] p) + { + return ref p[1]; + } +"; + + var src2 = @" +ref int32 a = ref G1(new int[] { 1, 2 }); + ref int G1(int[] p) + { + return ref p[2]; + } +"; + + var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "ref int a = ref G(new int[] { 1, 2 });", "ref int32 a = ref G1(new int[] { 1, 2 });" }, + { "ref int a = ref G(new int[] { 1, 2 })", "ref int32 a = ref G1(new int[] { 1, 2 })" }, + { "a = ref G(new int[] { 1, 2 })", "a = ref G1(new int[] { 1, 2 })" }, + { "ref int G(int[] p) { return ref p[1]; }", "ref int G1(int[] p) { return ref p[2]; }" }, + { "{ return ref p[1]; }", "{ return ref p[2]; }" }, + { "return ref p[1];", "return ref p[2];" } + }; + + expected.AssertEqual(actual); + } + + #endregion + + #region Lambdas + + [Fact] + public void Lambdas1() + { + var src1 = "Action x = a => a;"; + var src2 = "Action x = (a) => a;"; + + var match = GetMethodMatch(src1, src2); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "Action x = a => a;", "Action x = (a) => a;" }, + { "Action x = a => a", "Action x = (a) => a" }, + { "x = a => a", "x = (a) => a" }, + { "a => a", "(a) => a" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void Lambdas2a() + { + var src1 = @" +F(x => x + 1, 1, y => y + 1, delegate(int x) { return x; }, async u => u); +"; + var src2 = @" +F(y => y + 1, G(), x => x + 1, (int x) => x, u => u, async (u, v) => u + v); +"; + + var match = GetMethodMatch(src1, src2); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "F(x => x + 1, 1, y => y + 1, delegate(int x) { return x; }, async u => u);", "F(y => y + 1, G(), x => x + 1, (int x) => x, u => u, async (u, v) => u + v);" }, + { "x => x + 1", "x => x + 1" }, + { "y => y + 1", "y => y + 1" }, + { "delegate(int x) { return x; }", "(int x) => x" }, + { "async u => u", "async (u, v) => u + v" }, + }; + + expected.AssertEqual(actual); + } + + [Fact, WorkItem(830419, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/830419")] + public void Lambdas2b() + { + var src1 = @" +F(delegate { return x; }); +"; + var src2 = @" +F((a) => x, () => x); +"; + + var match = GetMethodMatch(src1, src2); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "F(delegate { return x; });", "F((a) => x, () => x);" }, + { "delegate { return x; }", "() => x" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void Lambdas3() + { + var src1 = @" +a += async u => u; +"; + var src2 = @" +a += u => u; +"; + + var match = GetMethodMatch(src1, src2); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "a += async u => u;", "a += u => u;" }, + { "async u => u", "u => u" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void Lambdas4() + { + var src1 = @" +foreach (var a in z) +{ + var e = from q in a.Where(l => l > 10) select q + 1; +} +"; + var src2 = @" +foreach (var a in z) +{ + var e = from q in a.Where(l => l < 0) select q + 1; +} +"; + + var match = GetMethodMatch(src1, src2); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "foreach (var a in z) { var e = from q in a.Where(l => l > 10) select q + 1; }", "foreach (var a in z) { var e = from q in a.Where(l => l < 0) select q + 1; }" }, + { "{ var e = from q in a.Where(l => l > 10) select q + 1; }", "{ var e = from q in a.Where(l => l < 0) select q + 1; }" }, + { "var e = from q in a.Where(l => l > 10) select q + 1;", "var e = from q in a.Where(l => l < 0) select q + 1;" }, + { "var e = from q in a.Where(l => l > 10) select q + 1", "var e = from q in a.Where(l => l < 0) select q + 1" }, + { "e = from q in a.Where(l => l > 10) select q + 1", "e = from q in a.Where(l => l < 0) select q + 1" }, + { "from q in a.Where(l => l > 10)", "from q in a.Where(l => l < 0)" }, + { "l => l > 10", "l => l < 0" }, + { "select q + 1", "select q + 1" }, // select clause + { "select q + 1", "select q + 1" } // query body + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void Lambdas5() + { + var src1 = @" +F(a => b => c => d); +"; + var src2 = @" +F(a => b => c => d); +"; + + var matches = GetMethodMatches(src1, src2); + var actual = ToMatchingPairs(matches); + + var expected = new MatchingPairs + { + { "F(a => b => c => d);", "F(a => b => c => d);" }, + { "a => b => c => d", "a => b => c => d" }, + { "b => c => d", "b => c => d" }, + { "c => d", "c => d" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void Lambdas6() + { + var src1 = @" +F(a => b => c => d); +"; + var src2 = @" +F(a => G(b => H(c => I(d)))); +"; + + var matches = GetMethodMatches(src1, src2); + var actual = ToMatchingPairs(matches); + + var expected = new MatchingPairs + { + { "F(a => b => c => d);", "F(a => G(b => H(c => I(d))));" }, + { "a => b => c => d", "a => G(b => H(c => I(d)))" }, + { "b => c => d", "b => H(c => I(d))" }, + { "c => d", "c => I(d)" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void Lambdas7() + { + var src1 = @" +F(a => +{ + F(c => /*1*/d); + F((u, v) => + { + F((w) => c => /*2*/d); + F(p => p); + }); +}); +"; + var src2 = @" +F(a => +{ + F(c => /*1*/d + 1); + F((u, v) => + { + F((w) => c => /*2*/d + 1); + F(p => p*2); + }); +}); +"; + + var matches = GetMethodMatches(src1, src2); + var actual = ToMatchingPairs(matches); + + var expected = new MatchingPairs + { + { "F(a => { F(c => /*1*/d); F((u, v) => { F((w) => c => /*2*/d); F(p => p); }); });", + "F(a => { F(c => /*1*/d + 1); F((u, v) => { F((w) => c => /*2*/d + 1); F(p => p*2); }); });" }, + { "a => { F(c => /*1*/d); F((u, v) => { F((w) => c => /*2*/d); F(p => p); }); }", + "a => { F(c => /*1*/d + 1); F((u, v) => { F((w) => c => /*2*/d + 1); F(p => p*2); }); }" }, + { "{ F(c => /*1*/d); F((u, v) => { F((w) => c => /*2*/d); F(p => p); }); }", + "{ F(c => /*1*/d + 1); F((u, v) => { F((w) => c => /*2*/d + 1); F(p => p*2); }); }" }, + { "F(c => /*1*/d);", "F(c => /*1*/d + 1);" }, + { "c => /*1*/d", "c => /*1*/d + 1" }, + { "F((u, v) => { F((w) => c => /*2*/d); F(p => p); });", "F((u, v) => { F((w) => c => /*2*/d + 1); F(p => p*2); });" }, + { "(u, v) => { F((w) => c => /*2*/d); F(p => p); }", "(u, v) => { F((w) => c => /*2*/d + 1); F(p => p*2); }" }, + { "{ F((w) => c => /*2*/d); F(p => p); }", "{ F((w) => c => /*2*/d + 1); F(p => p*2); }" }, + { "F((w) => c => /*2*/d);", "F((w) => c => /*2*/d + 1);" }, + { "(w) => c => /*2*/d", "(w) => c => /*2*/d + 1" }, + { "c => /*2*/d", "c => /*2*/d + 1" }, + { "F(p => p);", "F(p => p*2);" }, + { "p => p", "p => p*2" } + }; + + expected.AssertEqual(actual); + } + + #endregion + + #region Local Functions + + [Fact] + public void LocalFunctionDefinitions() + { + var src1 = @" +(int a, string c) F1(int i) { return null; } +(int a, int b) F2(int i) { return null; } +(int a, int b, int c) F3(int i) { return null; } +"; + + var src2 = @" +(int a, int b) F1(int i) { return null; } +(int a, int b, string c) F2(int i) { return null; } +(int a, int b) F3(int i) { return null; } +"; + + var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "(int a, string c) F1(int i) { return null; }", "(int a, int b) F1(int i) { return null; }" }, + { "{ return null; }", "{ return null; }" }, + { "return null;", "return null;" }, + { "(int a, int b) F2(int i) { return null; }", "(int a, int b, string c) F2(int i) { return null; }" }, + { "{ return null; }", "{ return null; }" }, + { "return null;", "return null;" }, + { "(int a, int b, int c) F3(int i) { return null; }", "(int a, int b) F3(int i) { return null; }" }, + { "{ return null; }", "{ return null; }" }, + { "return null;", "return null;" } + }; + + expected.AssertEqual(actual); + } + + #endregion + + #region LINQ + + [Fact] + public void Queries1() + { + var src1 = @" +var q = from c in cars + from ud in users_details + from bd in bids + select 1; +"; + var src2 = @" +var q = from c in cars + from bd in bids + from ud in users_details + select 2; +"; + + var match = GetMethodMatch(src1, src2); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "var q = from c in cars from ud in users_details from bd in bids select 1;", "var q = from c in cars from bd in bids from ud in users_details select 2;" }, + { "var q = from c in cars from ud in users_details from bd in bids select 1", "var q = from c in cars from bd in bids from ud in users_details select 2" }, + { "q = from c in cars from ud in users_details from bd in bids select 1", "q = from c in cars from bd in bids from ud in users_details select 2" }, + { "from c in cars", "from c in cars" }, + { "from ud in users_details from bd in bids select 1", "from bd in bids from ud in users_details select 2" }, + { "from ud in users_details", "from ud in users_details" }, + { "from bd in bids", "from bd in bids" }, + { "select 1", "select 2" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void Queries2() + { + var src1 = @" +var q = from c in cars + from ud in users_details + from bd in bids + orderby c.listingOption descending + where a.userID == ud.userid + let images = from ai in auction_images + where ai.belongs_to == c.id + select ai + let bid = (from b in bids + orderby b.id descending + where b.carID == c.id + select b.bidamount).FirstOrDefault() + select bid; +"; + var src2 = @" +var q = from c in cars + from ud in users_details + from bd in bids + orderby c.listingOption descending + where a.userID == ud.userid + let images = from ai in auction_images + where ai.belongs_to == c.id2 + select ai + 1 + let bid = (from b in bids + orderby b.id ascending + where b.carID == c.id2 + select b.bidamount).FirstOrDefault() + select bid; +"; + + var match = GetMethodMatches(src1, src2); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "var q = from c in cars from ud in users_details from bd in bids orderby c.listingOption descending where a.userID == ud.userid let images = from ai in auction_images where ai.belongs_to == c.id select ai let bid = (from b in bids orderby b.id descending where b.carID == c.id select b.bidamount).FirstOrDefault() select bid;", + "var q = from c in cars from ud in users_details from bd in bids orderby c.listingOption descending where a.userID == ud.userid let images = from ai in auction_images where ai.belongs_to == c.id2 select ai + 1 let bid = (from b in bids orderby b.id ascending where b.carID == c.id2 select b.bidamount).FirstOrDefault() select bid;" }, + { "var q = from c in cars from ud in users_details from bd in bids orderby c.listingOption descending where a.userID == ud.userid let images = from ai in auction_images where ai.belongs_to == c.id select ai let bid = (from b in bids orderby b.id descending where b.carID == c.id select b.bidamount).FirstOrDefault() select bid", + "var q = from c in cars from ud in users_details from bd in bids orderby c.listingOption descending where a.userID == ud.userid let images = from ai in auction_images where ai.belongs_to == c.id2 select ai + 1 let bid = (from b in bids orderby b.id ascending where b.carID == c.id2 select b.bidamount).FirstOrDefault() select bid" }, + { "q = from c in cars from ud in users_details from bd in bids orderby c.listingOption descending where a.userID == ud.userid let images = from ai in auction_images where ai.belongs_to == c.id select ai let bid = (from b in bids orderby b.id descending where b.carID == c.id select b.bidamount).FirstOrDefault() select bid", + "q = from c in cars from ud in users_details from bd in bids orderby c.listingOption descending where a.userID == ud.userid let images = from ai in auction_images where ai.belongs_to == c.id2 select ai + 1 let bid = (from b in bids orderby b.id ascending where b.carID == c.id2 select b.bidamount).FirstOrDefault() select bid" }, + { "from c in cars", "from c in cars" }, + { "from ud in users_details from bd in bids orderby c.listingOption descending where a.userID == ud.userid let images = from ai in auction_images where ai.belongs_to == c.id select ai let bid = (from b in bids orderby b.id descending where b.carID == c.id select b.bidamount).FirstOrDefault() select bid", "from ud in users_details from bd in bids orderby c.listingOption descending where a.userID == ud.userid let images = from ai in auction_images where ai.belongs_to == c.id2 select ai + 1 let bid = (from b in bids orderby b.id ascending where b.carID == c.id2 select b.bidamount).FirstOrDefault() select bid" }, + { "from ud in users_details", "from ud in users_details" }, + { "from bd in bids", "from bd in bids" }, + { "orderby c.listingOption descending", "orderby c.listingOption descending" }, + { "c.listingOption descending", "c.listingOption descending" }, + { "where a.userID == ud.userid", "where a.userID == ud.userid" }, + { "let images = from ai in auction_images where ai.belongs_to == c.id select ai", + "let images = from ai in auction_images where ai.belongs_to == c.id2 select ai + 1" }, + { "from ai in auction_images", "from ai in auction_images" }, + { "where ai.belongs_to == c.id select ai", "where ai.belongs_to == c.id2 select ai + 1" }, + { "where ai.belongs_to == c.id", "where ai.belongs_to == c.id2" }, + { "select ai", "select ai + 1" }, + { "let bid = (from b in bids orderby b.id descending where b.carID == c.id select b.bidamount).FirstOrDefault()", + "let bid = (from b in bids orderby b.id ascending where b.carID == c.id2 select b.bidamount).FirstOrDefault()" }, + { "from b in bids", "from b in bids" }, + { "orderby b.id descending where b.carID == c.id select b.bidamount", "orderby b.id ascending where b.carID == c.id2 select b.bidamount" }, + { "orderby b.id descending", "orderby b.id ascending" }, + { "b.id descending", "b.id ascending" }, + { "where b.carID == c.id", "where b.carID == c.id2" }, + { "select b.bidamount", "select b.bidamount" }, + { "select bid", "select bid" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void Queries3() + { + var src1 = @" +var q = from a in await seq1 + join c in await seq2 on F(u => u) equals G(s => s) into g1 + join l in await seq3 on F(v => v) equals G(t => t) into g2 + select a; + +"; + var src2 = @" +var q = from a in await seq1 + join c in await seq2 on F(u => u + 1) equals G(s => s + 3) into g1 + join c in await seq3 on F(vv => vv + 2) equals G(tt => tt + 4) into g2 + select a + 1; +"; + + var match = GetMethodMatches(src1, src2); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "var q = from a in await seq1 join c in await seq2 on F(u => u) equals G(s => s) into g1 join l in await seq3 on F(v => v) equals G(t => t) into g2 select a;", "var q = from a in await seq1 join c in await seq2 on F(u => u + 1) equals G(s => s + 3) into g1 join c in await seq3 on F(vv => vv + 2) equals G(tt => tt + 4) into g2 select a + 1;" }, + { "var q = from a in await seq1 join c in await seq2 on F(u => u) equals G(s => s) into g1 join l in await seq3 on F(v => v) equals G(t => t) into g2 select a", "var q = from a in await seq1 join c in await seq2 on F(u => u + 1) equals G(s => s + 3) into g1 join c in await seq3 on F(vv => vv + 2) equals G(tt => tt + 4) into g2 select a + 1" }, + { "q = from a in await seq1 join c in await seq2 on F(u => u) equals G(s => s) into g1 join l in await seq3 on F(v => v) equals G(t => t) into g2 select a", "q = from a in await seq1 join c in await seq2 on F(u => u + 1) equals G(s => s + 3) into g1 join c in await seq3 on F(vv => vv + 2) equals G(tt => tt + 4) into g2 select a + 1" }, + { "from a in await seq1", "from a in await seq1" }, + { "await seq1", "await seq1" }, + { "join c in await seq2 on F(u => u) equals G(s => s) into g1 join l in await seq3 on F(v => v) equals G(t => t) into g2 select a", "join c in await seq2 on F(u => u + 1) equals G(s => s + 3) into g1 join c in await seq3 on F(vv => vv + 2) equals G(tt => tt + 4) into g2 select a + 1" }, + { "join c in await seq2 on F(u => u) equals G(s => s) into g1", "join c in await seq2 on F(u => u + 1) equals G(s => s + 3) into g1" }, + { "await seq2", "await seq2" }, + { "u => u", "u => u + 1" }, + { "s => s", "s => s + 3" }, + { "into g1", "into g1" }, + { "join l in await seq3 on F(v => v) equals G(t => t) into g2", "join c in await seq3 on F(vv => vv + 2) equals G(tt => tt + 4) into g2" }, + { "await seq3", "await seq3" }, + { "v => v", "vv => vv + 2" }, + { "t => t", "tt => tt + 4" }, + { "into g2", "into g2" }, + { "select a", "select a + 1" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void Queries4() + { + var src1 = "F(from a in await b from x in y select c);"; + var src2 = "F(from a in await c from x in y select c);"; + + var match = GetMethodMatches(src1, src2); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "F(from a in await b from x in y select c);", "F(from a in await c from x in y select c);" }, + { "from a in await b", "from a in await c" }, + { "await b", "await c" }, + { "from x in y select c", "from x in y select c" }, + { "from x in y", "from x in y" }, + { "select c", "select c" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void Queries5() + { + var src1 = "F(from a in b group a by a.x into g select g);"; + var src2 = "F(from a in b group z by z.y into h select h);"; + + var match = GetMethodMatches(src1, src2); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "F(from a in b group a by a.x into g select g);", "F(from a in b group z by z.y into h select h);" }, + { "from a in b", "from a in b" }, + { "group a by a.x into g select g", "group z by z.y into h select h" }, + { "group a by a.x", "group z by z.y" }, + { "into g select g", "into h select h" }, + { "select g", "select h" }, + { "select g", "select h" } + }; + + expected.AssertEqual(actual); + } + + #endregion + + #region Iterators + + [Fact] + public void Yields() + { + var src1 = @" +yield return /*1*/ 1; + +{ + yield return /*2*/ 2; +} + +foreach (var x in y) { yield return /*3*/ 3; } +"; + var src2 = @" +yield return /*1*/ 1; +yield return /*2*/ 3; +foreach (var x in y) { yield return /*3*/ 2; } +"; + + var match = GetMethodMatches(src1, src2, kind: MethodKind.Iterator); + var actual = ToMatchingPairs(match); + + // note that yield returns are matched in source order, regardless of the yielded expressions: + var expected = new MatchingPairs + { + { "yield return /*1*/ 1;", "yield return /*1*/ 1;" }, + { "{ yield return /*2*/ 2; }", "{ yield return /*3*/ 2; }" }, + { "yield return /*2*/ 2;", "yield return /*2*/ 3;" }, + { "foreach (var x in y) { yield return /*3*/ 3; }", "foreach (var x in y) { yield return /*3*/ 2; }" }, + { "yield return /*3*/ 3;", "yield return /*3*/ 2;" }, + }; + + expected.AssertEqual(actual); + } + + #endregion + + #region Constructors + + [Fact] + public void ConstructorWithInitializer1() + { + var src1 = @" +(int x = 1) : base(a => a + 1) { Console.WriteLine(1); } +"; + var src2 = @" +(int x = 1) : base(a => a + 1) { Console.WriteLine(1); } +"; + + var match = GetMethodMatches(src1, src2, kind: MethodKind.ConstructorWithParameters); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "a => a + 1", "a => a + 1" }, + { "{ Console.WriteLine(1); }", "{ Console.WriteLine(1); }" }, + { "Console.WriteLine(1);", "Console.WriteLine(1);" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void ConstructorWithInitializer2() + { + var src1 = @" +() : base(a => a + 1) { Console.WriteLine(1); } +"; + var src2 = @" +() { Console.WriteLine(1); } +"; + + var match = GetMethodMatches(src1, src2, kind: MethodKind.ConstructorWithParameters); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "{ Console.WriteLine(1); }", "{ Console.WriteLine(1); }" }, + { "Console.WriteLine(1);", "Console.WriteLine(1);" } + }; + + expected.AssertEqual(actual); + } + + #endregion + + #region Exception Handlers + + [Fact] + public void ExceptionHandlers() + { + var src1 = @" +try { throw new InvalidOperationException(1); } +catch (IOException e) when (filter(e)) { Console.WriteLine(2); } +catch (Exception e) when (filter(e)) { Console.WriteLine(3); } +"; + var src2 = @" +try { throw new InvalidOperationException(10); } +catch (IOException e) when (filter(e)) { Console.WriteLine(20); } +catch (Exception e) when (filter(e)) { Console.WriteLine(30); } +"; + + var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "try { throw new InvalidOperationException(1); } catch (IOException e) when (filter(e)) { Console.WriteLine(2); } catch (Exception e) when (filter(e)) { Console.WriteLine(3); }", "try { throw new InvalidOperationException(10); } catch (IOException e) when (filter(e)) { Console.WriteLine(20); } catch (Exception e) when (filter(e)) { Console.WriteLine(30); }" }, + { "{ throw new InvalidOperationException(1); }", "{ throw new InvalidOperationException(10); }" }, + { "throw new InvalidOperationException(1);", "throw new InvalidOperationException(10);" }, + { "catch (IOException e) when (filter(e)) { Console.WriteLine(2); }", "catch (IOException e) when (filter(e)) { Console.WriteLine(20); }" }, + { "(IOException e)", "(IOException e)" }, + { "when (filter(e))", "when (filter(e))" }, + { "{ Console.WriteLine(2); }", "{ Console.WriteLine(20); }" }, + { "Console.WriteLine(2);", "Console.WriteLine(20);" }, + { "catch (Exception e) when (filter(e)) { Console.WriteLine(3); }", "catch (Exception e) when (filter(e)) { Console.WriteLine(30); }" }, + { "(Exception e)", "(Exception e)" }, + { "when (filter(e))", "when (filter(e))" }, + { "{ Console.WriteLine(3); }", "{ Console.WriteLine(30); }" }, + { "Console.WriteLine(3);", "Console.WriteLine(30);" } + }; + + expected.AssertEqual(actual); + } + + #endregion + + #region Foreach + + [Fact] + public void ForeachVariable_Update1() + { + var src1 = @" +foreach (var (a1, a2) in e) { A1(); } +foreach ((var b1, var b2) in e) { A2(); } +"; + + var src2 = @" +foreach (var (a1, a3) in e) { A1(); } +foreach ((var b3, int b2) in e) { A2(); } +"; + + var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "foreach (var (a1, a2) in e) { A1(); }", "foreach (var (a1, a3) in e) { A1(); }" }, + { "a1", "a1" }, + { "a2", "a3" }, + { "{ A1(); }", "{ A1(); }" }, + { "A1();", "A1();" }, + { "foreach ((var b1, var b2) in e) { A2(); }", "foreach ((var b3, int b2) in e) { A2(); }" }, + { "b1", "b3" }, + { "b2", "b2" }, + { "{ A2(); }", "{ A2(); }" }, + { "A2();", "A2();" }, + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void ForeachVariable_Update2() + { + var src1 = @" +foreach (_ in e2) { yield return 4; } +foreach (_ in e3) { A(); } +"; + + var src2 = @" +foreach (_ in e4) { A(); } +foreach (var b in e2) { yield return 4; } +"; + + var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "foreach (_ in e2) { yield return 4; }", "foreach (var b in e2) { yield return 4; }" }, + { "{ yield return 4; }", "{ yield return 4; }" }, + { "yield return 4;", "yield return 4;" }, + { "foreach (_ in e3) { A(); }", "foreach (_ in e4) { A(); }" }, + { "{ A(); }", "{ A(); }" }, + { "A();", "A();" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void ForeachVariable_Insert() + { + var src1 = @" +foreach (var (a3, a4) in e) { } +foreach ((var b4, var b5) in e) { } +"; + + var src2 = @" +foreach (var (a3, a5, a4) in e) { } +foreach ((var b6, var b4, var b5) in e) { } +"; + + var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "foreach (var (a3, a4) in e) { }", "foreach (var (a3, a5, a4) in e) { }" }, + { "a3", "a3" }, + { "a4", "a4" }, + { "{ }", "{ }" }, + { "foreach ((var b4, var b5) in e) { }", "foreach ((var b6, var b4, var b5) in e) { }" }, + { "b4", "b4" }, + { "b5", "b5" }, + { "{ }", "{ }" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void ForeachVariable_Delete() + { + var src1 = @" +foreach (var (a11, a12, a13) in e) { A1(); } +foreach ((var b7, var b8, var b9) in e) { A2(); } +"; + + var src2 = @" +foreach (var (a12, a13) in e1) { A1(); } +foreach ((var b7, var b9) in e) { A2(); } +"; + + var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "foreach (var (a11, a12, a13) in e) { A1(); }", "foreach (var (a12, a13) in e1) { A1(); }" }, + { "a12", "a12" }, + { "a13", "a13" }, + { "{ A1(); }", "{ A1(); }" }, + { "A1();", "A1();" }, + { "foreach ((var b7, var b8, var b9) in e) { A2(); }", "foreach ((var b7, var b9) in e) { A2(); }" }, + { "b7", "b7" }, + { "b9", "b9" }, + { "{ A2(); }", "{ A2(); }" }, + { "A2();", "A2();" } + }; + + expected.AssertEqual(actual); + } + + #endregion + + #region Patterns + + [Fact] + public void ConstantPattern() + { + var src1 = @" +if ((o is null) && (y == 7)) return 3; +if (a is 7) return 5; +"; + + var src2 = @" +if ((o1 is null) && (y == 7)) return 3; +if (a is 77) return 5; +"; + + var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs { + { "if ((o is null) && (y == 7)) return 3;", "if ((o1 is null) && (y == 7)) return 3;" }, + { "return 3;", "return 3;" }, + { "if (a is 7) return 5;", "if (a is 77) return 5;" }, + { "return 5;", "return 5;" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void DeclarationPattern() + { + var src1 = @" +if (!(o is int i) && (y == 7)) return; +if (!(a is string s)) return; +if (!(b is string t)) return; +if (!(c is int j)) return; +"; + + var src2 = @" +if (!(b is string t1)) return; +if (!(o1 is int i) && (y == 7)) return; +if (!(c is int)) return; +if (!(a is int s)) return; +"; + + var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs { + { "if (!(o is int i) && (y == 7)) return;", "if (!(o1 is int i) && (y == 7)) return;" }, + { "i", "i" }, + { "return;", "return;" }, + { "if (!(a is string s)) return;", "if (!(a is int s)) return;" }, + { "s", "s" }, + { "return;", "return;" }, + { "if (!(b is string t)) return;", "if (!(b is string t1)) return;" }, + { "t", "t1" }, + { "return;", "return;" }, + { "if (!(c is int j)) return;", "if (!(c is int)) return;" }, + { "return;", "return;" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void CasePattern_UpdateInsert() + { + var src1 = @" +switch(shape) +{ + case Circle c: return 1; + default: return 4; +} +"; + + var src2 = @" +switch(shape) +{ + case Circle c1: return 1; + case Point p: return 0; + default: return 4; +} +"; + + var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs { + { "switch(shape) { case Circle c: return 1; default: return 4; }", "switch(shape) { case Circle c1: return 1; case Point p: return 0; default: return 4; }" }, + { "case Circle c: return 1;", "case Circle c1: return 1;" }, + { "case Circle c:", "case Circle c1:" }, + { "c", "c1" }, + { "return 1;", "return 1;" }, + { "default: return 4;", "default: return 4;" }, + { "return 4;", "return 4;" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void CasePattern_UpdateDelete() + { + var src1 = @" +switch(shape) +{ + case Point p: return 0; + case Circle c: return 1; +} +"; + + var src2 = @" +switch(shape) +{ + case Circle circle: return 1; +} +"; + + var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs { + { "switch(shape) { case Point p: return 0; case Circle c: return 1; }", "switch(shape) { case Circle circle: return 1; }" }, + { "case Circle c: return 1;", "case Circle circle: return 1;" }, + { "case Circle c:", "case Circle circle:" }, + { "c", "circle" }, + { "return 1;", "return 1;" } + }; + + expected.AssertEqual(actual); + } + + [Fact] + public void WhenCondition() + { + var src1 = @" +switch(shape) +{ + case Circle c when (c < 10): return 1; + case Circle c when (c > 100): return 2; +} +"; + + var src2 = @" +switch(shape) +{ + case Circle c when (c < 5): return 1; + case Circle c2 when (c2 > 100): return 2; +} +"; + + var match = GetMethodMatches(src1, src2, kind: MethodKind.Regular); + var actual = ToMatchingPairs(match); + + var expected = new MatchingPairs + { + { "switch(shape) { case Circle c when (c < 10): return 1; case Circle c when (c > 100): return 2; }", "switch(shape) { case Circle c when (c < 5): return 1; case Circle c2 when (c2 > 100): return 2; }" }, + { "case Circle c when (c < 10): return 1;", "case Circle c when (c < 5): return 1;" }, + { "case Circle c when (c < 10):", "case Circle c when (c < 5):" }, + { "c", "c" }, + { "when (c < 10)", "when (c < 5)" }, + { "return 1;", "return 1;" }, + { "case Circle c when (c > 100): return 2;", "case Circle c2 when (c2 > 100): return 2;" }, + { "case Circle c when (c > 100):", "case Circle c2 when (c2 > 100):" }, + { "c", "c2" }, + { "when (c > 100)", "when (c2 > 100)" }, + { "return 2;", "return 2;" } + }; + + expected.AssertEqual(actual); + } + + #endregion + } +} diff --git a/src/EditorFeatures/CSharpTest/EditAndContinue/RudeEditTopLevelTests.cs b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs similarity index 99% rename from src/EditorFeatures/CSharpTest/EditAndContinue/RudeEditTopLevelTests.cs rename to src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs index d2aa6170d44..5a291a6904c 100644 --- a/src/EditorFeatures/CSharpTest/EditAndContinue/RudeEditTopLevelTests.cs +++ b/src/EditorFeatures/CSharpTest/EditAndContinue/TopLevelEditingTests.cs @@ -12,7 +12,7 @@ namespace Microsoft.CodeAnalysis.CSharp.EditAndContinue.UnitTests { - public class RudeEditTopLevelTests : RudeEditTestBase + public class TopLevelEditingTests : EditingTestBase { #region Usings -- GitLab