|
// 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.CodeRefactorings;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.InvertLogical;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.InvertLogical;
[Trait(Traits.Feature, Traits.Features.CodeActionsInvertLogical)]
public partial class InvertLogicalTests : AbstractCSharpCodeActionTest_NoEditor
{
private static readonly ParseOptions CSharp6 = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp6);
private static readonly ParseOptions CSharp8 = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp8);
private static readonly ParseOptions CSharp9 = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp9);
protected override CodeRefactoringProvider CreateCodeRefactoringProvider(TestWorkspace workspace, TestParameters parameters)
=> new CSharpInvertLogicalCodeRefactoringProvider();
[Fact]
public async Task InvertLogical1()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, int b)
{
var c = a > 10 [||]|| b < 20;
}
}
""",
"""
class C
{
void M(bool x, int a, int b)
{
var c = !(a <= 10 && b >= 20);
}
}
""");
}
[Fact]
public async Task InvertLogical2()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, int b)
{
var c = !(a <= 10 [||]&& b >= 20);
}
}
""",
"""
class C
{
void M(bool x, int a, int b)
{
var c = a > 10 || b < 20;
}
}
""");
}
[Fact]
public async Task TestTrivia1()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, int b)
{
var c = !(a <= 10 [||]&&
b >= 20);
}
}
""",
"""
class C
{
void M(bool x, int a, int b)
{
var c = a > 10 ||
b < 20;
}
}
""");
}
[Fact]
public async Task TestTrivia2()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, int b, int c)
{
var c = !(a <= 10 [||]&&
b >= 20 &&
c == 30);
}
}
""",
"""
class C
{
void M(bool x, int a, int b, int c)
{
var c = a > 10 ||
b < 20 ||
c != 30;
}
}
""");
}
[Fact]
public async Task InvertMultiConditional1()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(int a, int b, int c)
{
var x = a > 10 [||]|| b < 20 || c == 30;
}
}
""",
"""
class C
{
void M(int a, int b, int c)
{
var x = !(a <= 10 && b >= 20 && c != 30);
}
}
""");
}
[Fact]
public async Task InvertMultiConditional2()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(int a, int b, int c)
{
var x = a > 10 || b < 20 [||]|| c == 30;
}
}
""",
"""
class C
{
void M(int a, int b, int c)
{
var x = !(a <= 10 && b >= 20 && c != 30);
}
}
""");
}
[Fact]
public async Task InvertMultiConditional3()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(int a, int b, int c)
{
var x = !(a <= 10 [||]&& b >= 20 && c != 30);
}
}
""",
"""
class C
{
void M(int a, int b, int c)
{
var x = a > 10 || b < 20 || c == 30;
}
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/35525")]
public async Task InverSelection()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(int a, int b, int c)
{
var x = !([|a <= 10 && b >= 20 && c != 30|]);
}
}
""",
"""
class C
{
void M(int a, int b, int c)
{
var x = a > 10 || b < 20 || c == 30;
}
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/35525")]
public async Task MissingInverSelection1()
{
// Can't convert selected partial subtrees
// -> see comment at AbstractInvertLogicalCodeRefactoringProvider::ComputeRefactoringsAsync
// -> "expected" result commented out & TestMissingXXX method used in the meantime
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void M(int a, int b, int c)
{
var x = !([|a <= 10 && b >= 20|] && c != 30);
}
}
"""/*
@"class C
{
void M(int a, int b, int c)
{
var x = !(!(a > 10 || b < 20) && c != 30);
}
}"*/);
}
[Fact]
public async Task InvertMultiConditional4()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(int a, int b, int c)
{
var x = !(a <= 10 && b >= 20 [||]&& c != 30);
}
}
""",
"""
class C
{
void M(int a, int b, int c)
{
var x = a > 10 || b < 20 || c == 30;
}
}
""");
}
[Fact]
public async Task TestMissingOnShortCircuitAnd()
{
await TestMissingAsync(
"""
class C
{
void M(bool x, int a, int b)
{
var c = a > 10 [||]& b < 20;
}
}
""");
}
[Fact]
public async Task TestMissingOnShortCircuitOr()
{
await TestMissingAsync(
"""
class C
{
void M(bool x, int a, int b)
{
var c = a > 10 [||]| b < 20;
}
}
""");
}
[Fact]
public async Task TestSelectedOperator()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, int b)
{
var c = a > 10 [||||] b < 20;
}
}
""",
"""
class C
{
void M(bool x, int a, int b)
{
var c = !(a <= 10 && b >= 20);
}
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/35525")]
public async Task MissingSelectedSubtree()
{
await TestMissingInRegularAndScriptAsync(
"""
class C
{
void M(int a, int b, int c)
{
var x = !(a <= 10 && [|b >= 20 && c != 30|]);
}
}
""");
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
public async Task InvertIsTypePattern1_CSharp8()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is string;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || !(b is string));
}
}
""", parseOptions: CSharp8);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
public async Task InvertIsTypePattern1_CSharp9()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is string;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || b is not string);
}
}
""", parseOptions: CSharp9);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
public async Task InvertIsNotTypePattern1_CSharp8()
{
// Note: this is not legal (since it's a 'not' pattern being used in C# 8).
// This test just makes sure we don't crash in cases like that.
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is not string;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || b is string);
}
}
""", parseOptions: CSharp8);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
public async Task InvertIsNotTypePattern1_CSharp9()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is not string;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || b is string);
}
}
""", parseOptions: CSharp9);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
public async Task InvertIsNullPattern1_CSharp8()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is null;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || !(b is null));
}
}
""", parseOptions: CSharp8);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
public async Task InvertIsNullPattern1_CSharp9()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is null;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || b is not null);
}
}
""", parseOptions: CSharp9);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
public async Task InvertIsNotNullPattern1_CSharp6()
{
// Result is illegal (uses a constant pattern in c# 6), but the original code was illegal as well.
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is not null;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || b is null);
}
}
""", parseOptions: CSharp6);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
public async Task InvertIsNotNullPattern1_CSharp8()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is not null;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || b is null);
}
}
""", parseOptions: CSharp8);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
public async Task InvertIsNotNullPattern1_CSharp9()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is not null;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || b is null);
}
}
""", parseOptions: CSharp9);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
public async Task InvertIsTruePattern1_CSharp8()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is true;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || !(b is true));
}
}
""", parseOptions: CSharp8);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
public async Task InvertBooleanIsTruePattern1_CSharp9()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& x is true;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || x is false);
}
}
""", parseOptions: CSharp9);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/64292")]
public async Task InvertNonBooleanIsTruePattern1_CSharp9()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is true;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || b is not true);
}
}
""", parseOptions: CSharp9);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
public async Task InvertIsFalsePattern1_CSharp8()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is false;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || !(b is false));
}
}
""", parseOptions: CSharp8);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
public async Task InvertBooleanIsFalsePattern1_CSharp9()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& x is false;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || x is true);
}
}
""", parseOptions: CSharp9);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/64292")]
public async Task InvertNonBooleanIsFalsePattern1_CSharp9()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is false;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || b is not false);
}
}
""", parseOptions: CSharp9);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/64558")]
public async Task InvertNumericIsGreaterThanPattern1_CSharp9()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& a is > 20;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || a is <= 20);
}
}
""", parseOptions: CSharp9);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/64558")]
public async Task InvertNullableNumericIsGreaterThanPattern1_CSharp9()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int? a, object b)
{
var c = x [||]&& a is > 20;
}
}
""",
"""
class C
{
void M(bool x, int? a, object b)
{
var c = !(!x || a is not > 20);
}
}
""", parseOptions: CSharp9);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/64558")]
public async Task InvertNonNumericIsGreaterThanPattern1_CSharp9()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is > 20;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || b is not > 20);
}
}
""", parseOptions: CSharp9);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/64558")]
public async Task InvertInvalidEqualsPattern1_CSharp9()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& a is == 20;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || a is not == 20);
}
}
""", parseOptions: CSharp9);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
public async Task InvertIsAndPattern1_CSharp8()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is string and object;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || !(b is string and object));
}
}
""", parseOptions: CSharp8);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
public async Task InvertIsAndPattern1_CSharp9()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is string and object;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || b is not string or not object);
}
}
""", parseOptions: CSharp9);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
public async Task InvertIsOrPattern1_CSharp8()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is string or object;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || !(b is string or object));
}
}
""", parseOptions: CSharp8);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
public async Task InvertIsOrPattern1_CSharp9()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is string or object;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || b is not string and not object);
}
}
""", parseOptions: CSharp9);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
public async Task InvertIsTypeWithDesignationPattern1_CSharp8()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is string s;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || !(b is string s));
}
}
""", parseOptions: CSharp8);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
public async Task InvertIsTypeWithDesignationPattern1_CSharp9()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is string s;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || b is not string s);
}
}
""", parseOptions: CSharp9);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
public async Task InvertIsVarPattern1_CSharp8()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is var s;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || !(b is var s));
}
}
""", parseOptions: CSharp8);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
public async Task InvertIsVarPattern1_CSharp9()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is var s;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || !(b is var s));
}
}
""", parseOptions: CSharp9);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
public async Task InvertIsAndWithDesignationPattern1_CSharp8()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is string s and object;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || !(b is string s and object));
}
}
""", parseOptions: CSharp8);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
public async Task InvertIsAndWithDesignationPattern1_CSharp9()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is string s and object;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || !(b is string s and object));
}
}
""", parseOptions: CSharp9);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
public async Task InvertIsAndWithDesignationPattern2_CSharp8()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is string and object s;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || !(b is string and object s));
}
}
""", parseOptions: CSharp8);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42368")]
public async Task InvertIsAndWithDesignationPattern2_CSharp9()
{
await TestInRegularAndScriptAsync(
"""
class C
{
void M(bool x, int a, object b)
{
var c = a > 10 [||]&& b is string and object s;
}
}
""",
"""
class C
{
void M(bool x, int a, object b)
{
var c = !(a <= 10 || !(b is string and object s));
}
}
""", parseOptions: CSharp9);
}
}
|