context: using System.Linq;
  using NUnit.Framework;
  using Rubberduck.CodeAnalysis.Inspections;
  using Rubberduck.CodeAnalysis.Inspections.Concrete;
  using Rubberduck.Parsing.VBA;
  using Rubberduck.VBEditor.SafeComWrappers;
  
  namespace RubberduckTests.Inspections
  {
      [TestFixture]
      public class AnnotationInIncompatibleComponentTypeInspectionTests : InspectionTestsBase
      {
          [Test]
          [Category("Inspections")]
          public void ModuleAttributeAnnotationInDocumentReturnsResult()
          {
              const string inputCode = @"
  '@ModuleAttribute VB_Description, ""Desc""
  
  ";
  
              var inspectionResults = InspectionResultsForModules(("TestDocument", inputCode, ComponentType.Document));
              Assert.AreEqual(1, inspectionResults.Count());
          }
  
          [Test]
          [Category("Inspections")]
          public void MemberAttributeAnnotationInDocumentReturnsResult()
          {
              const string inputCode = @"
  '@MemberAttribute VB_Description, ""Desc""
  Public Sub Foo()
  End Sub
  ";
  
              var inspectionResults = InspectionResultsForModules(("TestDocument", inputCode, ComponentType.Document));
              Assert.AreEqual(1, inspectionResults.Count());
          }
  
          [Test]
          [Category("Inspections")]
          public void InspectionName()
          {
              const string inspectionName = nameof(AnnotationInIncompatibleComponentTypeInspection);
              var inspection = InspectionUnderTest(null);
  
              Assert.AreEqual(inspectionName, inspection.Name);
          }
  
          protected override IInspection InspectionUnderTest(RubberduckParserState state) => new AnnotationInIncompatibleComponentTypeInspection(state);
      }
  
      [TestFixture]
      public class UnrecognizedAnnotationInspectionTests : InspectionTestsBase
      {
          [Test]
          [Category("Inspections")]
          public void NonExistentModuleAnnotation_OneResult()
          {
              const string inputCode = @"
  '@ThisDoesNotExist
  Option Explicit
  Option Private Module
  
  Public Sub Test1()
  End Sub
  
  Public Sub Test2()
  End Sub
  ";
  
              var inspectionResults = InspectionResultsForStandardModule(inputCode);
              Assert.AreEqual(1, inspectionResults.Count());
          }
  
          [Test]
          [Category("Inspections")]
          public void NonExistentMemberAnnotation_OneResult()
          {
              const string inputCode = @"
  Option Explicit
  Option Private Module
  
  Public Sub Test1()
  End Sub
  
  '@ThisDoesNotExist
  Public Sub Test2()
  End Sub
  ";
  
              var inspectionResults = InspectionResultsForStandardModule(inputCode);
              Assert.AreEqual(1, inspectionResults.Count());
          }
  
          [Test]
          [Category("Inspections")]
          public void InspectionName()
          {
              const string inspectionName = nameof(UnrecognizedAnnotationInspection);
              var inspection = InspectionUnderTest(null);
  
              Assert.AreEqual(inspectionName, inspection.Name);
          }
  
          protected override IInspection InspectionUnderTest(RubberduckParserState state) => new UnrecognizedAnnotationInspection(state);
      }
  
      [TestFixture]
      public class InvalidAnnotationsInspectionTests : InspectionTestsBase
      {
          [Test]
          [Category("Inspections")]
          public void NoAnnotation_NoResult()
          {
              const string inputCode =
                  @"Public Sub Foo()
      Const const1 As Integer = 9
  End Sub";
  
              var inspectionResults = InspectionResultsForStandardModule(inputCode);
              Assert.IsFalse(inspectionResults.Any());
          }
  
          [Test]
          [Category("Inspections")]
          public void AttributeAnnotationOnDeclarationNotAllowingAttributes_OneResult()
          {
              const string inputCode =
                  @"
  Private Sub Foo()
  'local variables do not allow attributes
      '@VariableDescription(""Desc"")
      Dim bar As Variant
  End Sub
  ";
  
              var inspectionResults = InspectionResultsForStandardModule(inputCode);
              Assert.AreEqual(1, inspectionResults.Count());
          }
  
          [Test]
          [Category("Inspections")]
          public void FirstMemberAnnotation_IsNotIllegal_InMultipleModules()
          {
              const string inputCode1 =
                  @"'@TestModule
  '@Folder(""Test"")
  Option Explicit
  
  '@ModuleInitialize
  Public Sub ModuleInitializeLegal()
  End Sub";
              const string inputCode2 =
                  @"'@TestModule
  '@Folder(""Test"")
  Option Explicit
  
  '@ModuleInitialize
  Public Sub ModuleInitializeAlsoLegal()
  End Sub";
  
              var inspectionResults = InspectionResultsForModules(
                  ("Module1", inputCode1, ComponentType.StandardModule), 
                  ("Module2", inputCode2, ComponentType.StandardModule));
  
              Assert.IsFalse(inspectionResults.Any());
          }
  
          [Test]
          [Category("Inspections")]
          public void GivenLegalModuleAnnotation_NoResult()
          {
              const string inputCode = @"
  Option Explicit
  '@PredeclaredId
  ";
  
              var inspectionResults = InspectionResultsForStandardModule(inputCode);
              Assert.IsFalse(inspectionResults.Any());
          }
  
          [Test]
          [Category("Inspections")]
          public void GivenOneIlegalModuleAnnotationAcrossModules_OneResult()
          {
              const string inputCode1 = @"
  Option Explicit
  '@Folder(""Legal"")
  
  Sub DoSomething()
  '@Folder(""Illegal"")
  End Sub
  ";
              const string inputCode2 = @"
  Option Explicit
  '@Folder(""Legal"")
  ";
  
              var inspectionResults = InspectionResultsForModules(
                  ("Module1", inputCode1, ComponentType.StandardModule),
                  ("Module2", inputCode2, ComponentType.StandardModule));
  
              Assert.AreEqual(1, inspectionResults.Count());
          }
  
          [Test]
          [Category("Inspections")]
          public void GivenTestModule_NoResult()
          {
              const string inputCode = @"
  Option Explicit
  
  Option Private Module
  
  '@TestModule
  '@Folder(""Tests"")
  
  Private Assert As Object
  Private Fakes As Object
  
  '@ModuleInitialize
  Public Sub ModuleInitialize()
      'this method runs once per module.
      Set Assert = CreateObject(""Rubberduck.AssertClass"")
  
gt:     Set Fakes = CreateObject(""Rubberduck.FakesProvider"")