// 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.

#nullable disable

using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.ChangeNamespace;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeCleanup;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.MoveToNamespace;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities.MoveToNamespace;
using Roslyn.Test.Utilities;
using Xunit;

namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.MoveToNamespace
{
    [UseExportProvider]
    [Trait(Traits.Feature, Traits.Features.MoveToNamespace)]
    public class MoveToNamespaceTests : AbstractMoveToNamespaceTests
    {
        private static readonly TestComposition s_compositionWithoutOptions = FeaturesTestCompositions.Features
            .AddExcludedPartTypes(typeof(IDiagnosticUpdateSourceRegistrationService))
            .AddParts(
                typeof(MockDiagnosticUpdateSourceRegistrationService),
                typeof(TestSymbolRenamedCodeActionOperationFactoryWorkspaceService));

        private static readonly TestComposition s_composition = s_compositionWithoutOptions.AddParts(
            typeof(TestMoveToNamespaceOptionsService));

        protected override TestComposition GetComposition() => s_composition;

        protected override ParseOptions GetScriptOptions() => Options.Script;

        protected internal override string GetLanguage() => LanguageNames.CSharp;

        public static IEnumerable<object[]> SupportedKeywords => new[]
        {
            new[] { "class" },
            new[] { "enum" },
            new[] { "interface"}
        };

        [Fact]
        public Task MoveToNamespace_MoveItems_CaretAboveNamespace()
            => TestMoveToNamespaceAsync(
                """
                using System;
                [||]
                namespace A
                {
                    class MyClass
                    {
                    }
                }
                """,
expectedSuccess: false);

        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/59716")]
        public Task MoveToNamespace_MoveItems_CaretAboveNamespace_FileScopedNamespace()
            => TestMoveToNamespaceAsync(
                """
                using System;
                [||]
                namespace A;

                class MyClass
                {
                }
                """,
expectedSuccess: false);

        [Fact]
        public Task MoveToNamespace_MoveItems_CaretAboveNamespace2()
            => TestMoveToNamespaceAsync(
                """
                using System;[||]

                namespace A
                {
                    class MyClass
                    {
                    }
                }
                """,
expectedSuccess: false);

        [Fact]
        public Task MoveToNamespace_MoveItems_WeirdNamespace()
            => TestMoveToNamespaceAsync(
                """
                namespace A  [||].    B   .   C
                {
                    class MyClass
                    {
                    }
                }
                """,
expectedMarkup: """
                namespace {|Warning:A|}
                {
                    class MyClass
                    {
                    }
                }
                """,
targetNamespace: "A",
expectedSymbolChanges: new Dictionary<string, string>()
{
    {"A.B.C.MyClass", "A.MyClass" }
});

        [Fact]
        public Task MoveToNamespace_MoveItems_CaretOnNamespaceName()
            => TestMoveToNamespaceAsync(
                """
                namespace A[||] 
                {
                    class MyClass
                    {
                        void Method() { }
                    }
                }
                """,
expectedMarkup: """
                namespace {|Warning:B|}
                {
                    class MyClass
                    {
                        void Method() { }
                    }
                }
                """,
targetNamespace: "B",
expectedSymbolChanges: new Dictionary<string, string>()
{
    {"A.MyClass", "B.MyClass" }
});

        [Fact]
        public Task MoveToNamespace_MoveItems_CaretOnNamespaceName2()
            => TestMoveToNamespaceAsync(
                """
                namespace A[||].B.C
                {
                    class MyClass
                    {
                        void Method() { }
                    }
                }
                """,
expectedMarkup: """
                namespace {|Warning:B|}
                {
                    class MyClass
                    {
                        void Method() { }
                    }
                }
                """,
targetNamespace: "B",
expectedSymbolChanges: new Dictionary<string, string>()
{
    {"A.B.C.MyClass", "B.MyClass" }
});

        [Fact]
        public Task MoveToNamespace_MoveItems_CaretOnNamespaceKeyword()
        => TestMoveToNamespaceAsync(
            """
            namespace[||] A
            {
                class MyClass
                {
                    void Method() { }
                }
            }
            """,
expectedMarkup: """
            namespace {|Warning:B|}
            {
                class MyClass
                {
                    void Method() { }
                }
            }
            """,
targetNamespace: "B",
expectedSymbolChanges: new Dictionary<string, string>()
    {
        {"A.MyClass", "B.MyClass"}
    }
);

        [Fact]
        public Task MoveToNamespace_MoveItems_CaretOnNamespaceKeyword2()
        => TestMoveToNamespaceAsync(
            """
            [||]namespace A
            {
                class MyClass
                {
                    void Method() { }
                }
            }
            """,
expectedMarkup: """
            namespace {|Warning:B|}
            {
                class MyClass
                {
                    void Method() { }
                }
            }
            """,
targetNamespace: "B",
expectedSymbolChanges: new Dictionary<string, string>()
    {
        {"A.MyClass", "B.MyClass"}
    });

        [Fact]
        public Task MoveToNamespace_MoveItems_CaretOnNamespaceBrace()
        => TestMoveToNamespaceAsync(
            """
            namespace A
            [||]{
                class MyClass
                {
                    void Method() { }
                }
            }
            """,
expectedSuccess: false);

        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/59716")]
        public Task MoveToNamespace_MoveItems_CaretAfterFileScopedNamespaceSemicolon()
        => TestMoveToNamespaceAsync(
            """
            namespace A;  [||]

            class MyClass
            {
                void Method() { }
            }
            """,
expectedSuccess: false);

        [Fact]
        public Task MoveToNamespace_MoveItems_CaretOnNamespaceBrace2()
        => TestMoveToNamespaceAsync(
            """
            namespace A
            {[||]
                class MyClass
                {
                    void Method() { }
                }
            }
            """,
expectedSuccess: false);

        [Fact]
        public Task MoveToNamespace_MoveItems_MultipleDeclarations()
            => TestMoveToNamespaceAsync(
                """
                namespace A[||] 
                {
                    class MyClass
                    {
                        void Method() { }
                    }

                    class MyOtherClass
                    {
                        void Method() { }
                    }
                }
                """,
expectedMarkup: """
                namespace {|Warning:B|}
                {
                    class MyClass
                    {
                        void Method() { }
                    }

                    class MyOtherClass
                    {
                        void Method() { }
                    }
                }
                """,
targetNamespace: "B",
expectedSymbolChanges: new Dictionary<string, string>()
{
    {"A.MyClass", "B.MyClass" },
    {"A.MyOtherClass", "B.MyOtherClass" }
});

        [Fact]
        public Task MoveToNamespace_MoveItems_WithVariousSymbols()
        => TestMoveToNamespaceAsync(
            """
            namespace A[||] 
            {
                public delegate void MyDelegate();

                public enum MyEnum
                {
                    One,
                    Two,
                    Three
                }

                public struct MyStruct
                { }

                public interface MyInterface
                { }

                class MyClass
                {
                    void Method() { }
                }

                class MyOtherClass
                {
                    void Method() { }
                }
            }
            """,
expectedMarkup: """
            namespace {|Warning:B|}
            {
                public delegate void MyDelegate();

                public enum MyEnum
                {
                    One,
                    Two,
                    Three
                }

                public struct MyStruct
                { }

                public interface MyInterface
                { }

                class MyClass
                {
                    void Method() { }
                }

                class MyOtherClass
                {
                    void Method() { }
                }
            }
            """,
targetNamespace: "B",
expectedSymbolChanges: new Dictionary<string, string>()
{
    {"A.MyDelegate", "B.MyDelegate" },
    {"A.MyEnum", "B.MyEnum" },
    {"A.MyStruct", "B.MyStruct" },
    {"A.MyInterface", "B.MyInterface" },
    {"A.MyClass", "B.MyClass" },
    {"A.MyOtherClass", "B.MyOtherClass" }
});

        [Fact]
        public Task MoveToNamespace_MoveItems_NestedNamespace()
        => TestMoveToNamespaceAsync(
            """
            namespace A[||]
            {
                namespace C 
                {
                    class MyClass
                    {
                        void Method() { }
                    }
                }
            }
            """,
expectedSuccess: false);

        [Fact]
        public Task MoveToNamespace_MoveItems_NestedNamespace2()
        => TestMoveToNamespaceAsync(
            """
            namespace A
            {
                namespace C[||]
                {
                    class MyClass
                    {
                        void Method() { }
                    }
                }
            }
            """,
expectedSuccess: false);

        [Theory]
        [MemberData(nameof(SupportedKeywords))]
        public Task MoveToNamespace_MoveType_Nested(string typeKeyword)
        => TestMoveToNamespaceAsync(
@$"namespace A
{{
    class MyClass
    {{
        {typeKeyword} NestedType[||]
        {{
        }}
    }}
}}",
expectedSuccess: false);

        [Theory]
        [MemberData(nameof(SupportedKeywords))]
        public Task MoveToNamespace_MoveType_Single(string typeKeyword)
        => TestMoveToNamespaceAsync(
@$"namespace A
{{
    {typeKeyword} MyType[||]
    {{
    }}
}}",
expectedMarkup: @$"namespace {{|Warning:B|}}
{{
    {typeKeyword} MyType
    {{
    }}
}}",
targetNamespace: "B",
expectedSymbolChanges: new Dictionary<string, string>()
{
    {"A.MyType", "B.MyType" }
});

        [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/59716")]
        [MemberData(nameof(SupportedKeywords))]
        public Task MoveToNamespace_MoveType_Single_FileScopedNamespace(string typeKeyword)
        => TestMoveToNamespaceAsync(
@$"namespace A;

{typeKeyword} MyType[||]
{{
}}
",
expectedMarkup: @$"namespace {{|Warning:B|}};

{typeKeyword} MyType
{{
}}
",
targetNamespace: "B",
expectedSymbolChanges: new Dictionary<string, string>()
{
    {"A.MyType", "B.MyType" }
});

        [Theory]
        [MemberData(nameof(SupportedKeywords))]
        public Task MoveToNamespace_MoveType_SingleTop(string typeKeyword)
        => TestMoveToNamespaceAsync(
@$"namespace A
{{
    {typeKeyword} MyType[||]
    {{
    }}

    {typeKeyword} MyType2
    {{
    }}
}}",
expectedMarkup: @$"namespace {{|Warning:B|}}
{{
    {typeKeyword} MyType
    {{
    }}
}}

namespace A
{{
    {typeKeyword} MyType2
    {{
    }}
}}",
targetNamespace: "B",
expectedSymbolChanges: new Dictionary<string, string>()
{
    {"A.MyType", "B.MyType" }
});

        [Fact]
        public Task MoveToNamespace_MoveType_TopWithReference()
        => TestMoveToNamespaceAsync(
            """
            namespace A
            {
                class MyClass[||] : IMyClass
                {
                }

                interface IMyClass
                {
                }
            }
            """,
expectedMarkup: """
            using A;

            namespace {|Warning:B|}
            {
                class MyClass : IMyClass
                {
                }
            }

            namespace A
            {
                interface IMyClass
                {
                }
            }
            """,
targetNamespace: "B",
expectedSymbolChanges: new Dictionary<string, string>()
{
    {"A.MyClass", "B.MyClass" }
});

        [Theory]
        [MemberData(nameof(SupportedKeywords))]
        public Task MoveToNamespace_MoveType_Bottom(string typeKeyword)
        => TestMoveToNamespaceAsync(
@$"namespace A
{{
    {typeKeyword} MyType
    {{
    }}

    {typeKeyword} MyType2[||]
    {{
    }}
}}",
expectedMarkup: @$"namespace A
{{
    {typeKeyword} MyType
    {{
    }}
}}

namespace {{|Warning:B|}}
{{
    {typeKeyword} MyType2
    {{
    }}
}}",
targetNamespace: "B",
expectedSymbolChanges: new Dictionary<string, string>()
{
    {"A.MyType2", "B.MyType2" }
});

        [Fact]
        public Task MoveToNamespace_MoveType_BottomReference()
        => TestMoveToNamespaceAsync(
            """
            namespace A
            {
                class MyClass : IMyClass
                {
                }

                interface IMyClass[||]
                {
                }
            }
            """,
expectedMarkup: """
            using B;

            namespace A
            {
                class MyClass : IMyClass
                {
                }
            }

            namespace {|Warning:B|}
            {
                interface IMyClass
                {
                }
            }
            """,
targetNamespace: "B",
expectedSymbolChanges: new Dictionary<string, string>()
{
    {"A.IMyClass", "B.IMyClass" }
});

        [Theory]
        [MemberData(nameof(SupportedKeywords))]
        public Task MoveToNamespace_MoveType_Middle(string typeKeyword)
        => TestMoveToNamespaceAsync(
@$"namespace A
{{
    {typeKeyword} MyType
    {{
    }}

    {typeKeyword} MyType2[||]
    {{
    }}

    {typeKeyword} MyType3
    {{
    }}
}}",
expectedMarkup: @$"namespace A
{{
    {typeKeyword} MyType
    {{
    }}
}}

namespace {{|Warning:B|}}
{{
    {typeKeyword} MyType2
    {{
    }}
}}

namespace A
{{
    {typeKeyword} MyType3
    {{
    }}
}}",
targetNamespace: "B",
expectedSymbolChanges: new Dictionary<string, string>()
{
    {"A.MyType2", "B.MyType2" }
});

        [Theory]
        [MemberData(nameof(SupportedKeywords))]
        public Task MoveToNamespace_MoveType_Middle_CaretBeforeKeyword(string typeKeyword)
        => TestMoveToNamespaceAsync(
@$"namespace A
{{
    {typeKeyword} MyType
    {{
    }}

    [||]{typeKeyword} MyType2
    {{
    }}

    {typeKeyword} MyType3
    {{
    }}
}}",
expectedMarkup: @$"namespace A
{{
    {typeKeyword} MyType
    {{
    }}
}}

namespace {{|Warning:B|}}
{{
    {typeKeyword} MyType2
    {{
    }}
}}

namespace A
{{
    {typeKeyword} MyType3
    {{
    }}
}}",
targetNamespace: "B",
expectedSymbolChanges: new Dictionary<string, string>()
{
    {"A.MyType2", "B.MyType2" }
});

        [Theory]
        [MemberData(nameof(SupportedKeywords))]
        public Task MoveToNamespace_MoveType_Middle_CaretAfterTypeKeyword(string typeKeyword)
        => TestMoveToNamespaceAsync(
@$"namespace A
{{
    {typeKeyword} MyType
    {{
    }}

    {typeKeyword}[||] MyType2
    {{
    }}

    {typeKeyword} MyType3
    {{
    }}
}}",
expectedMarkup: @$"namespace A
{{
    {typeKeyword} MyType
    {{
    }}
}}

namespace {{|Warning:B|}}
{{
    {typeKeyword} MyType2
    {{
    }}
}}

namespace A
{{
    {typeKeyword} MyType3
    {{
    }}
}}",
targetNamespace: "B",
expectedSymbolChanges: new Dictionary<string, string>()
{
    {"A.MyType2", "B.MyType2" }
});

        [Theory]
        [MemberData(nameof(SupportedKeywords))]
        public Task MoveToNamespace_MoveType_Middle_CaretBeforeTypeName(string typeKeyword)
        => TestMoveToNamespaceAsync(
@$"namespace A
{{
    {typeKeyword} MyType
    {{
    }}

    {typeKeyword} [||]MyType2
    {{
    }}

    {typeKeyword} MyType3
    {{
    }}
}}",
expectedMarkup: @$"namespace A
{{
    {typeKeyword} MyType
    {{
    }}
}}

namespace {{|Warning:B|}}
{{
    {typeKeyword} MyType2
    {{
    }}
}}

namespace A
{{
    {typeKeyword} MyType3
    {{
    }}
}}",
targetNamespace: "B",
expectedSymbolChanges: new Dictionary<string, string>()
{
    {"A.MyType2", "B.MyType2" }
});

        [Fact]
        public Task MoveToNamespace_MoveType_CaretInMethod()
        => TestMoveToNamespaceAsync(
            """
            namespace A
            {
                class MyClass
                {
                    public string [||]MyMethod
                    {
                        return ";
                    }
                }

            }
            """,
expectedSuccess: false);

        [Fact]
        public Task MoveToNamespace_MoveType_MiddleReference()
        => TestMoveToNamespaceAsync(
            """
            namespace A
            {
                class MyClass : IMyClass
                {
                }

                interface IMyClass[||]
                {
                }

                class MyClass3 : IMyClass
                {
                }
            }
            """,
expectedMarkup: """
            using B;

            namespace A
            {
                class MyClass : IMyClass
                {
                }
            }

            namespace {|Warning:B|}
            {
                interface IMyClass
                {
                }
            }

            namespace A
            {
                class MyClass3 : IMyClass
                {
                }
            }
            """,
targetNamespace: "B",
expectedSymbolChanges: new Dictionary<string, string>()
{
    {"A.IMyClass", "B.IMyClass" }
});

        [Fact]
        public Task MoveToNamespace_MoveType_MiddleReference2()
        => TestMoveToNamespaceAsync(
            """
            namespace A
            {
                class MyClass : IMyClass
                {
                }

                interface IMyClass
                {
                }

                class [||]MyClass3 : IMyClass
                {
                }

                class MyClass4
                {
                }
            }
            """,
expectedMarkup: """
            using A;

            namespace A
            {
                class MyClass : IMyClass
                {
                }

                interface IMyClass
                {
                }
            }

            namespace {|Warning:B|}
            {
                class MyClass3 : IMyClass
                {
                }
            }

            namespace A
            {
                class MyClass4
                {
                }
            }
            """,
targetNamespace: "B",
expectedSymbolChanges: new Dictionary<string, string>()
{
    {"A.MyClass3", "B.MyClass3" }
});

        [Fact]
        public Task MoveToNamespace_MoveType_NestedInNamespace()
        => TestMoveToNamespaceAsync(
            """
            namespace A
            {
                class MyClass
                {
                }

                namespace B
                {
                    interface [||]IMyClass
                    {
                    }
                }

                class MyClass2 : B.IMyClass
                {
                }
            }
            """,
expectedSuccess: false);

        [Fact]
        public Task MoveToNamespace_MoveType_Cancelled()
            => TestCancelledOption(
                """
                namespace A
                {
                    class MyClass
                    {
                    }

                    interface [||]IMyClass
                    {
                    }

                    class MyClass2 : B.IMyClass
                    {
                    }
                }
                """);

        [Fact]
        public Task MoveToNamespace_MoveItems_Cancelled()
            => TestCancelledOption(
                """
                namespace A[||]
                {
                    class MyClass
                    {
                    }

                    interface IMyClass
                    {
                    }

                    class MyClass2 : B.IMyClass
                    {
                    }
                }
                """);

        [Fact]
        public Task MoveToNamespace_MoveType_MiddleReference_ComplexName()
        => TestMoveToNamespaceAsync(
            """
            namespace A.B.C
            {
                class MyClass : IMyClass
                {
                }

                interface IMyClass
                {
                }

                class [||]MyClass3 : IMyClass
                {
                }

                class MyClass4
                {
                }
            }
            """,
expectedMarkup: """
            using A.B.C;

            namespace A.B.C
            {
                class MyClass : IMyClass
                {
                }

                interface IMyClass
                {
                }
            }

            namespace {|Warning:My.New.Namespace|}
            {
                class MyClass3 : IMyClass
                {
                }
            }

            namespace A.B.C
            {
                class MyClass4
                {
                }
            }
            """,
targetNamespace: "My.New.Namespace",
expectedSymbolChanges: new Dictionary<string, string>()
{
    {"A.B.C.MyClass3", "My.New.Namespace.MyClass3" }
});

        [Fact]
        public Task MoveToNamespace_MoveType_MiddleReference_ComplexName2()
       => TestMoveToNamespaceAsync(
           """
           namespace A
           {
               class MyClass : IMyClass
               {
               }

               interface IMyClass
               {
               }

               class [||]MyClass3 : IMyClass
               {
               }

               class MyClass4
               {
               }
           }
           """,
expectedMarkup: """
           using A;

           namespace A
           {
               class MyClass : IMyClass
               {
               }

               interface IMyClass
               {
               }
           }

           namespace {|Warning:My.New.Namespace|}
           {
               class MyClass3 : IMyClass
               {
               }
           }

           namespace A
           {
               class MyClass4
               {
               }
           }
           """,
targetNamespace: "My.New.Namespace",
expectedSymbolChanges: new Dictionary<string, string>()
{
    {"A.MyClass3", "My.New.Namespace.MyClass3" }
});

        [Fact]
        public Task MoveToNamespace_MoveType_MiddleReference_ComplexName3()
       => TestMoveToNamespaceAsync(
           """
           namespace A.B.C
           {
               class MyClass : IMyClass
               {
               }

               interface IMyClass
               {
               }

               class [||]MyClass3 : IMyClass
               {
               }

               class MyClass4
               {
               }
           }
           """,
expectedMarkup: """
           using A.B.C;

           namespace A.B.C
           {
               class MyClass : IMyClass
               {
               }

               interface IMyClass
               {
               }
           }

           namespace {|Warning:B|}
           {
               class MyClass3 : IMyClass
               {
               }
           }

           namespace A.B.C
           {
               class MyClass4
               {
               }
           }
           """,
targetNamespace: "B",
expectedSymbolChanges: new Dictionary<string, string>()
{
    {"A.B.C.MyClass3", "B.MyClass3" }
});

        [Fact]
        public Task MoveToNamespace_Analysis_MoveItems_ComplexNamespace()
           => TestMoveToNamespaceAnalysisAsync(
               """
               namespace [||]A.Complex.Namespace
               {
                   class MyClass
                   {
                   }
               }
               """,
expectedNamespaceName: "A.Complex.Namespace");

        [Fact]
        public Task MoveToNamespace_Analysis_MoveType_ComplexNamespace()
           => TestMoveToNamespaceAnalysisAsync(
               """
               namespace A.Complex.Namespace
               {
                   class [||]MyClass
                   {
                   }
               }
               """,
expectedNamespaceName: "A.Complex.Namespace");

        [Fact]
        public Task MoveToNamespace_Analysis_MoveItems_WeirdNamespace()
           => TestMoveToNamespaceAnalysisAsync(
               """
               namespace A  [||].    B   .   C
               {
                   class MyClass
                   {
                   }
               }
               """,
expectedNamespaceName: "A  .    B   .   C");

        [Fact]
        public Task MoveToNamespace_Analysis_MoveType_WeirdNamespace()
           => TestMoveToNamespaceAnalysisAsync(
               """
               namespace A  .    B   .   C
               {
                   class MyClass[||]
                   {
                   }
               }
               """,
expectedNamespaceName: "A  .    B   .   C");

        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/34736")]
        public Task MoveToNamespace_MoveType_Usings()
            => TestMoveToNamespaceAsync(
                """
                namespace One
                {
                    using Two;
                    class C1
                    {
                        private C2 c2;
                    }
                }

                namespace [||]Two
                {
                    class C2
                    {

                    }
                }
                """,
expectedMarkup: """
                namespace One
                {
                    using Three;
                    class C1
                    {
                        private C2 c2;
                    }
                }

                namespace {|Warning:Three|}
                {
                    class C2
                    {

                    }
                }
                """,
targetNamespace: "Three",
expectedSymbolChanges: new Dictionary<string, string>()
{
    {"Two.C2", "Three.C2" }
});

        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/35577")]
        public async Task MoveToNamespace_WithoutOptionsService()
        {
            var code = """
                namespace A[||]
                {
                class MyClass
                {
                    void Method() { }
                }
                }
                """;

            using var workspace = TestWorkspace.CreateCSharp(code, composition: s_compositionWithoutOptions);
            using var testState = new TestState(workspace);
            Assert.Null(testState.TestMoveToNamespaceOptionsService);

            var actions = await testState.MoveToNamespaceService.GetCodeActionsAsync(
                testState.InvocationDocument,
                testState.TestInvocationDocument.SelectedSpans.Single(),
                CodeActionOptions.DefaultProvider,
                CancellationToken.None);

            Assert.Empty(actions);
        }

        [Theory, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/980758")]
        [MemberData(nameof(SupportedKeywords))]
        public Task MoveToNamespace_MoveOnlyTypeInGlobalNamespace(string typeKeyword)
        => TestMoveToNamespaceAsync(
@$"{typeKeyword} MyType[||]
{{
}}",
expectedMarkup: @$"namespace {{|Warning:A|}}
{{
    {typeKeyword} MyType
    {{
    }}
}}",
targetNamespace: "A",
expectedSymbolChanges: new Dictionary<string, string>()
{
    {"MyType", "A.MyType" }
});

        [Theory, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/980758")]
        [MemberData(nameof(SupportedKeywords))]
        public async Task MoveToNamespace_MoveOnlyTypeToGlobalNamespace(string typeKeyword)
        {
            // We will not get "" as target namespace in VS, but the refactoring should be able
            // to handle it w/o crashing.
            await TestMoveToNamespaceAsync(
 @$"namespace A
{{
    {typeKeyword} MyType[||]
    {{
    }}
}}",
  expectedMarkup: @$"namespace A
{{
    {typeKeyword} MyType
    {{
    }}
}}",
      targetNamespace: "");
        }

        [Theory, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/980758")]
        [MemberData(nameof(SupportedKeywords))]
        public Task MoveToNamespace_MoveOneTypeInGlobalNamespace(string typeKeyword)
            => TestMoveToNamespaceAsync(
@$"{typeKeyword} MyType1[||]
{{
}}

{typeKeyword} MyType2
{{
}}",
    expectedSuccess: false);

        [Fact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/980758")]
        public Task MoveToNamespace_PartialTypesInNamesapce_SelectType()
            => TestMoveToNamespaceAsync(
                """
                namespace NS
                {
                    partial class MyClass[||]
                    {
                    }

                    partial class MyClass
                    {
                    }
                }
                """,
    expectedSuccess: false);

        [Fact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/980758")]
        public Task MoveToNamespace_PartialTypesInNamesapce_SelectNamespace()
            => TestMoveToNamespaceAsync(
                """
                namespace NS[||]
                {
                    partial class MyClass
                    {
                    }

                    partial class MyClass
                    {
                    }
                }
                """,
    expectedSuccess: false);

        [Fact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/980758")]
        public Task MoveToNamespace_PartialTypesInGlobalNamesapce()
            => TestMoveToNamespaceAsync(
                """
                partial class MyClass[||]
                {
                }
                partial class MyClass
                {
                }
                """,
    expectedSuccess: false);

        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/39234")]
        public async Task TestMultiTargetingProject()
        {
            // Create two projects with same project file path and single linked document to simulate a multi-targeting project.
            var input = """
                <Workspace>
                    <Project Language="C#" CommonReferences="true" AssemblyName="Proj1" FilePath="SharedProj.csproj">
                        <Document FilePath="CurrentDocument.cs">
                namespace A
                {
                    public class Class1
                    {
                    }

                    public class Class2[||]
                    {
                    }
                }
                        </Document>
                    </Project>
                    <Project Language="C#" CommonReferences="true" AssemblyName="Proj2" FilePath="SharedProj.csproj">
                        <Document IsLinkFile="true" LinkAssemblyName="Proj1" LinkFilePath="CurrentDocument.cs"/>
                    </Project>
                </Workspace>
                """;

            var expected =
                """
                namespace A
                {
                    public class Class1
                    {
                    }
                }

                namespace B
                {
                    public class Class2
                    {
                    }
                }
                """;
            using var workspace = TestWorkspace.Create(System.Xml.Linq.XElement.Parse(input), composition: s_composition, openDocuments: false);

            // Set the target namespace to "B"
            var testDocument = workspace.Projects.Single(p => p.Name == "Proj1").Documents.Single();
            var document = workspace.CurrentSolution.GetDocument(testDocument.Id);
            var movenamespaceService = document.GetLanguageService<IMoveToNamespaceService>();
            var moveToNamespaceOptions = new MoveToNamespaceOptionsResult("B");
            ((TestMoveToNamespaceOptionsService)movenamespaceService.OptionsService).SetOptions(moveToNamespaceOptions);

            var (_, action) = await GetCodeActionsAsync(workspace);
            var operations = await VerifyActionAndGetOperationsAsync(workspace, action);
            var result = await ApplyOperationsAndGetSolutionAsync(workspace, operations);

            // Make sure both linked documents are changed.
            foreach (var id in workspace.Documents.Select(d => d.Id))
            {
                var changedDocument = result.Item2.GetDocument(id);
                var changedRoot = await changedDocument.GetSyntaxRootAsync();
                var actualText = changedRoot.ToFullString();
                Assert.Equal(expected, actualText);
            }
        }

        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/35507")]
        public Task MoveToNamespace_MoveTypeFromSystemNamespace()
            => TestMoveToNamespaceAsync(
                """
                namespace System
                {
                    [||]class A
                    {

                    }
                }
                """,
expectedMarkup: """
                namespace {|Warning:Test|}
                {
                    [||]class A
                    {

                    }
                }
                """,
targetNamespace: "Test",
expectedSymbolChanges: new Dictionary<string, string>()
{
    {"System.A", "Test.A" }
});
    }
}
