/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Features/CSharpTest/UseRecursivePatterns/UseRecursivePatternsRefactoringTests.cs
260 строк
13 KB
Cyrus Najmabadi
Use raw strings in tests
09 июл 2025, 08:52
09 июл 2025, 08:52
f265dce
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.CodeRefactorings.UseRecursivePatterns; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Testing; using Xunit; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings.UseRecursivePatterns; using VerifyCS = CSharpCodeRefactoringVerifier<UseRecursivePatternsCodeRefactoringProvider>; [UseExportProvider] [Trait(Traits.Feature, Traits.Features.CodeActionsUseRecursivePatterns)] public sealed class UseRecursivePatternsRefactoringTests { private static Task VerifyAsync( string initialMarkup, string expectedMarkup, bool skipCodeActionValidation = false, LanguageVersion languageVersion = LanguageVersion.CSharp9) { return new VerifyCS.Test { LanguageVersion = languageVersion, TestCode = initialMarkup, FixedCode = expectedMarkup, CodeActionValidationMode = skipCodeActionValidation ? CodeActionValidationMode.None : CodeActionValidationMode.SemanticStructure, }.RunAsync(); } private static Task VerifyMissingAsync(string initialMarkup) { return VerifyAsync(initialMarkup, initialMarkup); } [Theory] [InlineData("a.b.c.d && a.b.c.a", "a.b.c is { d: n, a: n }")] [InlineData("a?.b.c.d && a.b.c.a", "a?.b.c is { d: n, a: n }")] [InlineData("a.b?.c.d && a.b.c.a", "a.b?.c is { d: n, a: n }")] [InlineData("a.b.c?.d && a.b.c.a", "a.b.c is { d: n, a: n }")] [InlineData("a.b?.c?.d && a.b.c.a", "a.b?.c is { d: n, a: n }")] [InlineData("a?.b.c?.d && a.b.c.a", "a?.b.c is { d: n, a: n }")] [InlineData("a?.b?.c.d && a.b.c.a", "a?.b?.c is { d: n, a: n }")] [InlineData("a?.b?.c?.d && a.b.c.a", "a?.b?.c is { d: n, a: n }")] [InlineData("a.b.c.d && a.b.a", "a.b is { c: { d: n }, a: n }")] [InlineData("a?.b.c.d && a.b.a", "a?.b is { c: { d: n }, a: n }")] [InlineData("a.b?.c.d && a.b.a", "a.b is { c: { d: n }, a: n }")] [InlineData("a.b.c?.d && a.b.a", "a.b is { c: { d: n }, a: n }")] [InlineData("a.b?.c?.d && a.b.a", "a.b is { c: { d: n }, a: n }")] [InlineData("a?.b.c?.d && a.b.a", "a?.b is { c: { d: n }, a: n }")] [InlineData("a?.b?.c.d && a.b.a", "a?.b is { c: { d: n }, a: n }")] [InlineData("a?.b?.c?.d && a.b.a", "a?.b is { c: { d: n }, a: n }")] [InlineData("a.b.c.d && a.a", "a is { b: { c: { d: n } }, a: n }")] [InlineData("a?.b.c.d && a.a", "a is { b: { c: { d: n } }, a: n }")] [InlineData("a.b?.c.d && a.a", "a is { b: { c: { d: n } }, a: n }")] [InlineData("a.b.c?.d && a.a", "a is { b: { c: { d: n } }, a: n }")] [InlineData("a.b?.c?.d && a.a", "a is { b: { c: { d: n } }, a: n }")] [InlineData("a?.b.c?.d && a.a", "a is { b: { c: { d: n } }, a: n }")] [InlineData("a?.b?.c.d && a.a", "a is { b: { c: { d: n } }, a: n }")] [InlineData("a?.b?.c?.d && a.a", "a is { b: { c: { d: n } }, a: n }")] [InlineData("a.b.c.d && b", "this is { a: { b: { c: { d: n } } }, b: n }")] [InlineData("a?.b.c.d && b", "this is { a: { b: { c: { d: n } } }, b: n }")] [InlineData("a.b?.c.d && b", "this is { a: { b: { c: { d: n } } }, b: n }")] [InlineData("a.b.c?.d && b", "this is { a: { b: { c: { d: n } } }, b: n }")] [InlineData("a.b?.c?.d && b", "this is { a: { b: { c: { d: n } } }, b: n }")] [InlineData("a?.b.c?.d && b", "this is { a: { b: { c: { d: n } } }, b: n }")] [InlineData("a?.b?.c.d && b", "this is { a: { b: { c: { d: n } } }, b: n }")] [InlineData("a?.b?.c?.d && b", "this is { a: { b: { c: { d: n } } }, b: n }")] [InlineData("a.b.c.d && b", "this is { a.b.c.d: n, b: n }", LanguageVersion.CSharp10)] [InlineData("a?.b.c.d && b", "this is { a.b.c.d: n, b: n }", LanguageVersion.CSharp10)] [InlineData("a.b?.c.d && b", "this is { a.b.c.d: n, b: n }", LanguageVersion.CSharp10)] [InlineData("a.b.c?.d && b", "this is { a.b.c.d: n, b: n }", LanguageVersion.CSharp10)] [InlineData("a.b?.c?.d && b", "this is { a.b.c.d: n, b: n }", LanguageVersion.CSharp10)] [InlineData("a?.b.c?.d && b", "this is { a.b.c.d: n, b: n }", LanguageVersion.CSharp10)] [InlineData("a?.b?.c.d && b", "this is { a.b.c.d: n, b: n }", LanguageVersion.CSharp10)] [InlineData("a?.b?.c?.d && b", "this is { a.b.c.d: n, b: n }", LanguageVersion.CSharp10)] [InlineData("a.b.m().d && a.b.m().a", "a.b.m() is { d: n, a: n }")] [InlineData("a.m().c.d && a.m().a", "a.m() is { c: { d: n }, a: n }")] [InlineData("a?.m().c.d && a?.m().a", "a?.m() is { c: { d: n }, a: n }")] [InlineData("a.m()?.c.d && a.m().a", "a.m() is { c: { d: n }, a: n }")] [InlineData("a.m().c?.d && a.m().a", "a.m() is { c: { d: n }, a: n }")] [InlineData("a.m()?.c?.d && a.m().a", "a.m() is { c: { d: n }, a: n }")] [InlineData("a?.m().c?.d && a?.m().a", "a?.m() is { c: { d: n }, a: n }")] [InlineData("a?.m()?.c.d && a?.m().a", "a?.m() is { c: { d: n }, a: n }")] [InlineData("a?.m()?.c?.d && a?.m().a", "a?.m() is { c: { d: n }, a: n }")] public Task TestLogicalAndExpression_Receiver(string actual, string expected, LanguageVersion languageVersion = LanguageVersion.CSharp9) => VerifyAsync(WrapInIfStatement("n == " + actual + " == n", "&&"), WrapInIfStatement(expected), languageVersion: languageVersion); [Theory] [InlineData("this.P1 < 1 && 2 >= this.P2", "this is { P1: < 1, P2: <= 2 }")] [InlineData("this.P1 > 1 && 2 <= this.P2", "this is { P1: > 1, P2: >= 2 }")] [InlineData("this.P1 <= 1 && 2 > this.P2", "this is { P1: <= 1, P2: < 2 }")] [InlineData("this.P1 >= 1 && 2 < this.P2", "this is { P1: >= 1, P2: > 2 }")] // Nested [InlineData("this.CP1?.P1 < 1 && 2 >= this.CP2.P2", "this is { CP1: { P1: < 1 }, CP2: { P2: <= 2 } }")] [InlineData("this.CP1?.P1 > 1 && 2 <= this.CP2.P2", "this is { CP1: { P1: > 1 }, CP2: { P2: >= 2 } }")] [InlineData("this.CP1.P1 <= 1 && 2 > this.CP2?.P2", "this is { CP1: { P1: <= 1 }, CP2: { P2: < 2 } }")] [InlineData("this.CP1.P1 >= 1 && 2 < this.CP2?.P2", "this is { CP1: { P1: >= 1 }, CP2: { P2: > 2 } }")] public Task TestLogicalAndExpression_Relational(string actual, string expected) => VerifyAsync(WrapInIfStatement(actual, "&&"), WrapInIfStatement(expected)); [Theory] [InlineData("!B1 && B2", "this is { B1: false, B2: true }")] [InlineData("CP1.B1 && !CP2.B2", "this is { CP1: { B1: true }, CP2: { B2: false } }")] public Task TestLogicalAndExpression_Boolean(string actual, string expected) => VerifyAsync(WrapInIfStatement(actual, "&&"), WrapInIfStatement(expected, "&&")); [Theory] [InlineData("this.P1 == 1 && 2 == this.P2", "this is { P1: 1, P2: 2 }")] [InlineData("this.cf != null && this.cf.C != 0", "this.cf is { C: not 0 }")] [InlineData("cf != null && cf.C != 0", "cf is { C: not 0 }")] [InlineData("this.P1 != 1 && 2 != this.P2", "this is { P1: not 1, P2: not 2 }")] [InlineData("this.CP1.P1 == 1 && 2 == this.CP2.P2", "this is { CP1: { P1: 1 }, CP2: { P2: 2 } }")] [InlineData("this.CP1.P1 != 1 && 2 != this.CP2.P2", "this is { CP1: { P1: not 1 }, CP2: { P2: not 2 } }")] public Task TestLogicalAndExpression_Equality(string actual, string expected) => VerifyAsync(WrapInIfStatement(actual, "&&"), WrapInIfStatement(expected, "&&")); [Theory] [InlineData("NS.C.SCP1.P1 == 1 && NS.C.SCP1.P2 == 2", "NS.C.SCP1 is { P1: 1, P2: 2 }")] [InlineData("NS.C.SCP1.CP1.P1 == 1 && NS.C.SCP1.CP2.P2 == 2", "NS.C.SCP1 is { CP1: { P1: 1 }, CP2: { P2: 2 } }")] public Task TestLogicalAndExpression_StaticMembers(string actual, string expected) => VerifyAsync(WrapInIfStatement(actual, "&&"), WrapInIfStatement(expected, "&&")); [Theory] [InlineData("this.B1 && this.CP1.P1 == 1 [||]&& this.CP1.CP2.P3 == 3 && B2", "this.B1 && this.CP1 is { P1: 1, CP2: { P3: 3 } } && B2")] [InlineData("this.B1 || this.CP1.P1 == 1 [||]&& this.CP1.CP2.P3 == 3 || B2", "this.B1 || this.CP1 is { P1: 1, CP2: { P3: 3 } } || B2")] public Task TestLogicalAndExpression_Chain(string actual, string expected) => VerifyAsync(WrapInIfStatement(actual, entry: null), WrapInIfStatement(expected, entry: null)); [Theory] [InlineData("NS.C.SCP1 == null && NS.C.SCP2 == null")] [InlineData("NS.C.SCP1.P1 == 1 && NS.C.SCP2.P1 == 2")] [InlineData("base.P1 == 1 && base.P2 == 2")] [InlineData("base.B1 && base.B2")] public Task TestLogicalAndExpression_Invalid(string actual) => VerifyMissingAsync(WrapInIfStatement(actual, "&&")); [Theory] [InlineData("{ a: var x }", "x is { b: n }", "{ a: { b: n } x }")] [InlineData("{ a: C x }", "x is { b: n }", "{ a: C { b: n } x }")] [InlineData("{ a: { b: n } x }", "x is C", "{ a: C { b: n } x }")] [InlineData("{ a: { b: n } x }", "x is { a: n }", "{ a: { b: n, a: n } x }")] [InlineData("{ a: var x }", "x.c is { b: n }", "{ a: { c: { b: n } } x }")] [InlineData("{ a: C x }", "x.c is { b: n }", "{ a: C { c: { b: n } } x }")] [InlineData("{ a: { b: n } x }", "x.c is C", "{ a: { b: n, c: C } x }", true)] [InlineData("{ a: { b: n } x }", "x.c is { a: n }", "{ a: { b: n, c: { a: n } } x }")] [InlineData("{ a: var x }", "x == null", "{ a: var x and null }")] public async Task TestVariableDesignation(string pattern, string expression, string expected, bool skipCodeActionValidation = false) { await ValidateAsync(WrapInSwitchArm($"{pattern} when {expression}", "when"), WrapInSwitchArm($"{expected}")); await ValidateAsync(WrapInSwitchArm($"{pattern} when {expression}", "=>"), WrapInSwitchArm($"{expected}")); await ValidateAsync(WrapInSwitchLabel($"{pattern} when {expression}", "when"), WrapInSwitchLabel($"{expected}")); await ValidateAsync(WrapInSwitchLabel($"{pattern} when {expression}", "case"), WrapInSwitchLabel($"{expected}")); await ValidateAsync(WrapInIfStatement($"this is {pattern} && {expression}", "&&"), WrapInIfStatement($"this is {expected}")); await ValidateAsync(WrapInSwitchArm($"{pattern} when {expression} && B1 && B2", "when"), WrapInSwitchArm($"{expected} when B1 && B2")); await ValidateAsync(WrapInSwitchArm($"{pattern} when {expression} && B1 && B2", "=>"), WrapInSwitchArm($"{expected} when B1 && B2")); await ValidateAsync(WrapInSwitchLabel($"{pattern} when {expression} && B1 && B2", "when"), WrapInSwitchLabel($"{expected} when B1 && B2")); await ValidateAsync(WrapInSwitchLabel($"{pattern} when {expression} && B1 && B2", "case"), WrapInSwitchLabel($"{expected} when B1 && B2")); await ValidateAsync(WrapInIfStatement($"B1 && this is {pattern} [||]&& {expression} && B2"), WrapInIfStatement($"B1 && this is {expected} && B2")); Task ValidateAsync(string initialMarkup, string expectedMarkup) => VerifyAsync(initialMarkup, expectedMarkup, skipCodeActionValidation); } private static string WrapInIfStatement(string actual, string? entry = null) { var markup = """ if ( """ + actual + """ ) {} """; return CreateMarkup(markup, entry); } private static string WrapInSwitchArm(string actual, string? entry = null) { var markup = """ _ = this switch { """ + actual + """ => 0 }; """; return CreateMarkup(markup, entry); } private static string WrapInSwitchLabel(string actual, string? entry = null) { var markup = """ switch (this) { case """ + actual + """ : break; }; """; return CreateMarkup(markup, entry); } private static string CreateMarkup(string actual, string? entry = null) { var markup = """ namespace NS { class C : B { void Test() { """ + actual + """ } } class B { public const C n = null; public C a, b, c, d; public int P1, P2, P3; public bool B1, B2; public C CP1, CP2; public static C SCP1, SCP2; public static int SP1, SP2; public C m() { return null; } public D cf = null; } class D { public int C = 0; } } """; return entry is null ? markup : markup.Replace(entry, "[||]" + entry); } }