﻿// 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.Editor.UnitTests.SpellCheck;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.Test.Utilities;
using Xunit;

namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.SpellCheck
{
    [UseExportProvider]
    public class SpellCheckSpanTests : AbstractSpellCheckSpanTests
    {
        protected override TestWorkspace CreateWorkspace(string content)
            => TestWorkspace.CreateCSharp(content);

        [Fact]
        public async Task TestSingleLineComment1()
        {
            await TestAsync("{|Comment:// Goo|}");
        }

        [Fact]
        public async Task TestSingleLineComment2()
        {
            await TestAsync(@"
{|Comment:// Goo|}");
        }

        [Fact]
        public async Task TestMultiLineComment1()
        {
            await TestAsync("{|Comment:/* Goo */|}");
        }

        [Fact]
        public async Task TestMultiLineComment2()
        {
            await TestAsync(@"
{|Comment:/*
   Goo
 */|}");
        }

        [Fact]
        public async Task TestMultiLineComment3()
        {
            await TestAsync(@"
{|Comment:/*
   Goo
 |}");
        }

        [Fact]
        public async Task TestMultiLineComment4()
        {
            await TestAsync(@"
{|Comment:/**/|}");
        }

        [Fact]
        public async Task TestMultiLineComment5()
        {
            await TestAsync(@"
{|Comment:/*/|}");
        }

        [Fact]
        public async Task TestDocComment1()
        {
            await TestAsync(@"
///{|Comment:goo bar baz|}
class {|Identifier:C|}
{
}");
        }

        [Fact]
        public async Task TestDocComment2()
        {
            await TestAsync(@"
///{|Comment:goo bar baz|}
///{|Comment:goo bar baz|}
class {|Identifier:C|}
{
}");
        }

        [Fact]
        public async Task TestDocComment3()
        {
            await TestAsync(@"
///{|Comment: |}<summary>{|Comment: goo bar baz |}</summary>
class {|Identifier:C|}
{
}");
        }

        [Fact]
        public async Task TestString1()
        {
            await TestAsync(@"{|String:"" goo ""|}");
        }

        [Fact]
        public async Task TestString2()
        {
            await TestAsync(@""" goo ");
        }

        [Fact]
        public async Task TestString3()
        {
            await TestAsync(@"
{|String:"" goo ""|}");
        }

        [Fact]
        public async Task TestString4()
        {
            await TestAsync(@"
"" goo ");
        }

        [Fact]
        public async Task TestString5()
        {
            await TestAsync(@"
{|String:@"" goo ""|}");
        }

        [Fact]
        public async Task TestString6()
        {
            await TestAsync(@"
@"" goo ");
        }

        [Fact]
        public async Task TestString7()
        {
            await TestAsync(@"{|String:"""""" goo """"""|}");
        }

        [Fact]
        public async Task TestString8()
        {
            await TestAsync(@""""""" goo """"");
        }

        [Fact]
        public async Task TestString9()
        {
            await TestAsync(@""""""" goo """);
        }

        [Fact]
        public async Task TestString10()
        {
            await TestAsync(@""""""" goo ");
        }

        [Fact]
        public async Task TestString11()
        {
            await TestAsync(@"{|String:""""""
    goo 
    """"""|}");
        }

        [Fact]
        public async Task TestString12()
        {
            await TestAsync(@"""""""
    goo
    """"");
        }

        [Fact]
        public async Task TestString13()
        {
            await TestAsync(@"""""""
    goo
    """);
        }

        [Fact]
        public async Task TestString14()
        {
            await TestAsync(@"""""""
    goo
    ");
        }

        [Fact]
        public async Task TestString15()
        {
            await TestAsync(@"
$""{|String: goo |}""");
        }

        [Fact]
        public async Task TestString16()
        {
            await TestAsync(@"
$""{|String: goo |}{0}{|String: bar |}""");
        }

        [Fact]
        public async Task TestString17()
        {
            await TestAsync(@"
$""""""{|String: goo |}{0}{|String: bar |}""""""");
        }

        [Fact]
        public async Task TestString18()
        {
            await TestAsync(@"
$""""""{|String: goo |}{0:abcd}{|String: bar |}""""""");
        }

        [Fact]
        public async Task TestEscapedString1()
        {
            await TestAsync(""" " {|String:goo|}\r\n{|String:bar|} " """);
        }

        [Fact]
        public async Task TestEscapedString2()
        {
            await TestAsync(""" " {|String:goo|}\r\t{|String:bar|} " """);
        }

        [Fact]
        public async Task TestEscapedString3()
        {
            await TestAsync(""" " {|String:goo|}\r\u0065bar " """);
        }

        [Fact]
        public async Task TestEscapedString4()
        {
            await TestAsync(""" " {|String:C|}:\t{|String:ests|} " """);
        }

        [Fact]
        public async Task TestEscapedString5()
        {
            await TestAsync(""" {|String:@" C:\tests "|} """);
        }

        [Fact]
        public async Task TestEscapedString6()
        {
            await TestAsync(""" " {|String:C|}:\\{|String:tests|} " """);
        }

        [Fact]
        public async Task TestEscapedString7()
        {
            await TestAsync(""" " {|String:C|}:\\{|String:tests|}\\{|String:goo|} " """);
        }

        [Fact]
        public async Task TestEscapedString8()
        {
            await TestAsync(""" {|String:@" C:\tests\goo "|} """);
        }

        [Fact]
        public async Task TestEscapedString9()
        {
            await TestAsync(""" $" {|String:C|}:\\{|String:tests|}\\{|String:goo|} {0} {|String:C|}:\\{|String:tests|}\\{|String:bar|} " """);
        }

        [Fact]
        public async Task TestEscapedString10()
        {
            await TestAsync(""" $@"{|String: C:\tests\goo |}{0}{|String: C:\tests\bar |}" """);
        }

        [Fact]
        public async Task TestIdentifier1()
        {
            await TestAsync(@"
class {|Identifier:C|}
{
}");
        }

        [Fact]
        public async Task TestIdentifier2()
        {
            await TestAsync(@"
record {|Identifier:C|}
{
}");
        }

        [Fact]
        public async Task TestIdentifier3()
        {
            await TestAsync(@"
record class {|Identifier:C|}
{
}");
        }

        [Fact]
        public async Task TestIdentifier4()
        {
            await TestAsync(@"
delegate void {|Identifier:C|}();");
        }

        [Fact]
        public async Task TestIdentifier5()
        {
            await TestAsync(@"
enum {|Identifier:C|} { }");
        }

        [Fact]
        public async Task TestIdentifier6()
        {
            await TestAsync(@"
enum {|Identifier:C|}
{
    {|Identifier:D|}
}");
        }

        [Fact]
        public async Task TestIdentifier7()
        {
            await TestAsync(@"
enum {|Identifier:C|}
{
    {|Identifier:D|}, {|Identifier:E|}
}");
        }

        [Fact]
        public async Task TestIdentifier8()
        {
            await TestAsync(@"
interface {|Identifier:C|} { }");
        }

        [Fact]
        public async Task TestIdentifier9()
        {
            await TestAsync(@"
struct {|Identifier:C|} { }");
        }

        [Fact]
        public async Task TestIdentifier10()
        {
            await TestAsync(@"
record struct {|Identifier:C|}() { }");
        }

        [Fact]
        public async Task TestIdentifier11()
        {
            await TestAsync(@"
class {|Identifier:C|}<{|Identifier:T|}> { }");
        }

        [Fact]
        public async Task TestIdentifier12()
        {
            await TestAsync(@"
class {|Identifier:C|}
{
    private int {|Identifier:X|};
}");
        }

        [Fact]
        public async Task TestIdentifier13()
        {
            await TestAsync(@"
class {|Identifier:C|}
{
    private int {|Identifier:X|}, {|Identifier:Y|};
}");
        }

        [Fact]
        public async Task TestIdentifier14()
        {
            await TestAsync(@"
class {|Identifier:C|}
{
    private const int {|Identifier:X|};
}");
        }

        [Fact]
        public async Task TestIdentifier15()
        {
            await TestAsync(@"
class {|Identifier:C|}
{
    private const int {|Identifier:X|}, {|Identifier:Y|};
}");
        }

        [Fact]
        public async Task TestIdentifier16()
        {
            await TestAsync(@"
class {|Identifier:C|}
{
    private int {|Identifier:X|} => 0;
}");
        }

        [Fact]
        public async Task TestIdentifier17()
        {
            await TestAsync(@"
class {|Identifier:C|}
{
    private event Action {|Identifier:X|};
}");
        }

        [Fact]
        public async Task TestIdentifier18()
        {
            await TestAsync(@"
class {|Identifier:C|}
{
    private event Action {|Identifier:X|}, {|Identifier:Y|};
}");
        }

        [Fact]
        public async Task TestIdentifier19()
        {
            await TestAsync(@"
class {|Identifier:C|}
{
    private event Action {|Identifier:X|} { add { } remove { } }
}");
        }

        [Fact]
        public async Task TestIdentifier20()
        {
            await TestAsync(@"
class {|Identifier:C|}
{
    void {|Identifier:D|}()
    {
        int {|Identifier:E|};
    }
}");
        }

        [Fact]
        public async Task TestIdentifier21()
        {
            await TestAsync(@"
class {|Identifier:C|}
{
    void {|Identifier:D|}()
    {
        int {|Identifier:E|}, {|Identifier:F|};
    }
}");
        }

        [Fact]
        public async Task TestIdentifier22()
        {
            await TestAsync(@"
class {|Identifier:C|}
{
    void {|Identifier:D|}()
    {
{|Identifier:E|}:
        return;
    }
}");
        }

        [Fact]
        public async Task TestIdentifier23()
        {
            await TestAsync(@"
class {|Identifier:C|}
{
    void {|Identifier:D|}(int {|Identifier:E|})
    {
    }
}");
        }

        [Fact]
        public async Task TestIdentifier24()
        {
            await TestAsync(@"
class {|Identifier:C|}
{
    void {|Identifier:D|}(int {|Identifier:E|})
    {
    }
}");
        }

        [Fact]
        public async Task TestIdentifier25()
        {
            await TestAsync(@"
class {|Identifier:C|}
{
    void {|Identifier:D|}(int {|Identifier:E|}, int {|Identifier:F|})
    {
    }
}");
        }

        [Fact]
        public async Task TestIdentifier26()
        {
            await TestAsync(@"
static class {|Identifier:C|}
{
    static void {|Identifier:D|}(this int {|Identifier:E|})
    {
    }
}");
        }

        [Fact]
        public async Task TestIdentifier27()
        {
            await TestAsync(@"
namespace {|Identifier:C|}
{
}");
        }

        [Fact]
        public async Task TestIdentifier28()
        {
            await TestAsync(@"
namespace {|Identifier:C|}.{|Identifier:D|}
{
}");
        }

        [Fact]
        public async Task TestIdentifier29()
        {
            await TestAsync(@"
class {|Identifier:C|}
{
    void {|Identifier:D|}()
    {
        for (int {|Identifier:E|} = 0; E < 10; E++)
        {
        }
    }
}");
        }

        [Fact]
        public async Task TestIdentifier30()
        {
            await TestAsync(@"
class {|Identifier:C|}
{
    void {|Identifier:D|}()
    {
        Goo(out var {|Identifier:E|});
    }
}");
        }

        [Fact]
        public async Task TestIdentifier31()
        {
            await TestAsync(@"
class {|Identifier:C|}() { }");
        }

        [Fact]
        public async Task TestIdentifier32()
        {
            await TestAsync(@"
struct {|Identifier:C|}() { }");
        }

        [Fact]
        public async Task TestIdentifier33()
        {
            await TestAsync(@"
class {|Identifier:C|};");
        }

        [Fact]
        public async Task TestIdentifier34()
        {
            await TestAsync(@"
struct {|Identifier:C|};");
        }
    }
}
