context: using System.Linq;
  using NUnit.Framework;
  using Rubberduck.CodeAnalysis.Inspections;
  using Rubberduck.CodeAnalysis.Inspections.Concrete;
  using Rubberduck.Parsing.VBA;
  using Rubberduck.VBEditor.SafeComWrappers;
  using RubberduckTests.Mocks;
  
  namespace RubberduckTests.Inspections
  {
      [TestFixture]
      public class MemberNotOnInterfaceInspectionTests : InspectionTestsBase
      {
          private int ArrangeParserAndGetResultCount(string inputCode, ReferenceLibrary library = ReferenceLibrary.Scripting)
              => InspectionResultsForModules(("Codez", inputCode, ComponentType.StandardModule), library).Count();
  
          [Test]
          [Category("Inspections")]
          public void MemberNotOnInterface_ReturnsResult_UnDeclaredMember()
          {
              const string inputCode =
                  @"Sub Foo()
      Dim dict As Dictionary
      Set dict = New Dictionary
      dict.NonMember
  End Sub";
              Assert.AreEqual(1, ArrangeParserAndGetResultCount(inputCode));
          }
  
          [Test]
          [Category("Inspections")]
          public void MemberNotOnInterface_ReturnsResult_UnDeclaredInterfaceMember()
          {
              const string inputCode =
                  @"Sub Foo()
      Dim dict As Dictionary
      Set dict = New Dictionary
      dict.NonMember
  End Sub";
              Assert.AreEqual(1, ArrangeParserAndGetResultCount(inputCode));
          }
  
          [Test]
          [Category("Inspections")]
          public void MemberNotOnInterface_ReturnsResult_ApplicationObject()
          {
              const string inputCode =
                  @"Sub Foo()
      Application.NonMember
  End Sub";
              Assert.AreEqual(1, ArrangeParserAndGetResultCount(inputCode, ReferenceLibrary.Excel));
          }
  
          [Test]
          [Category("Inspections")]
          public void MemberNotOnInterface_ReturnsResult_UnDeclaredMemberOnParameter()
          {
              const string inputCode =
                  @"Sub Foo(dict As Dictionary)
      dict.NonMember
  End Sub";
              Assert.AreEqual(1, ArrangeParserAndGetResultCount(inputCode));
          }
  
          [Test]
          [Category("Inspections")]
          public void MemberNotOnInterface_DoesNotReturnResult_DeclaredMember()
          {
              const string inputCode =
                  @"Sub Foo()
      Dim dict As Dictionary
      Set dict = New Dictionary
      Debug.Print dict.Count
  End Sub";
              Assert.AreEqual(0, ArrangeParserAndGetResultCount(inputCode));
          }
  
          [Test]
          [Category("Inspections")]
          public void MemberNotOnInterface_DoesNotReturnResult_NonExtensible()
          {
              const string inputCode =
                  @"Sub Foo()
      Dim x As File
      Debug.Print x.NonMember
  End Sub";
              Assert.AreEqual(0, ArrangeParserAndGetResultCount(inputCode));
          }
  
          [Test]
          [Category("Inspections")]
          public void MemberNotOnInterface_ReturnsResult_WithBlock()
          {
              const string inputCode =
                  @"Sub Foo()
      Dim dict As New Dictionary
      With dict
          .NonMember
      End With
  End Sub";
              Assert.AreEqual(1, ArrangeParserAndGetResultCount(inputCode));
          }
  
          [Test]
          [Category("Inspections")]
          public void MemberNotOnInterface_DoesNotReturnResult_BangNotation()
          {
              const string inputCode =
                  @"Sub Foo()
      Dim dict As Dictionary
      Set dict = New Dictionary
      dict!SomeIdentifier = 42
  End Sub";
              Assert.AreEqual(0, ArrangeParserAndGetResultCount(inputCode));
          }
  
          [Test]
          [Category("Inspections")]
          public void MemberNotOnInterface_DoesNotReturnResult_WithBlockBangNotation()
          {
              const string inputCode =
                  @"Sub Foo()
      Dim dict As New Dictionary
      With dict
          !SomeIdentifier = 42
      End With
  End Sub";
              Assert.AreEqual(0, ArrangeParserAndGetResultCount(inputCode));
          }
  
          [Test]
          [Category("Inspections")]
          public void MemberNotOnInterface_DoesNotReturnResult_ProjectReference()
          {
              const string inputCode =
                  @"Sub Foo()
      Dim dict As Scripting.Dictionary
  End Sub";
              Assert.AreEqual(0, ArrangeParserAndGetResultCount(inputCode));
          }
  
          [Test]
          [Category("Inspections")]
          public void MemberNotOnInterface_Ignored_DoesNotReturnResult()
          {
              const string inputCode =
                  @"Sub Foo(dict As Dictionary)
      Dim dict As Dictionary
      Set dict = New Dictionary
      '@Ignore MemberNotOnInterface
      dict.NonMember
  End Sub";
              Assert.AreEqual(0, ArrangeParserAndGetResultCount(inputCode));
          }
  
          [Test]
          [Category("Inspections")]
          public void MemberNotOnInterface_WithNewReturnsResult()
          {
              const string inputCode =
                  @"Sub Foo()
      With New Dictionary
          .FooBar
      End With
  End Sub";
              Assert.AreEqual(1, ArrangeParserAndGetResultCount(inputCode));
          }
  
          [Test]
          [Category("Inspections")]
          //See https://github.com/rubberduck-vba/Rubberduck/issues/4308 
          public void MemberNotOnInterface_ProcedureArgument()
          {
              const string inputCode =
                  @"Sub Foo()
      Dim fooBaz As Dictionary
      Set fooBaz = New Dictionary 
      Bar fooBaz.FooBar
  End Sub
  
  Private Sub Bar(baz As Long)
  End Sub";
              Assert.AreEqual(1, ArrangeParserAndGetResultCount(inputCode));
          }
  
          [Test]
          [Category("Inspections")]
          public void MemberNotOnInterface_FunctionArgument()
          {
              const string inputCode =
                  @"Sub Foo()
      Dim fooBaz As Dictionary
      Dim fooBar As Variant 
      Set fooBaz = New Dictionary 
      fooBar = Bar(fooBaz.FooBar)
  End Sub
  
  Private Function Bar(baz As Long) As Variant
  End Function";
              Assert.AreEqual(1, ArrangeParserAndGetResultCount(inputCode));
          }
  
          [Test]
          [Category("Inspections")]
          public void MemberNotOnInterface_Expression()
          {
              const string inputCode =
                  @"Sub Foo()
      Dim fooBaz As Dictionary
      Dim fooBar As Variant 
      Set fooBaz = New Dictionary 
      fooBar = 1 + fooBaz.FooBar
  End Sub
  
  Private Function Bar(baz As Long) As Variant
  End Function";
              Assert.AreEqual(1, ArrangeParserAndGetResultCount(inputCode));
          }
  
          [Test]
          [Category("Inspections")]
          public void MemberNotOnInterface_Expression_BothSides()
          {
              const string inputCode =
                  @"Sub Foo()
      Dim fooBaz As Dictionary
      Dim fooBar As Variant 
      Set fooBaz = New Dictionary 
      fooBar = fooBaz.NotThere + fooBaz.FooBar
  End Sub
  
  Private Function Bar(baz As Long) As Variant
  End Function";
              Assert.AreEqual(2, ArrangeParserAndGetResultCount(inputCode));
          }
  
          [Test]
          [Category("Inspections")]
          public void MemberNotOnInterface_DeepExpression()
          {
              const string inputCode =
                  @"Sub Foo()
      Dim fooBaz As Dictionary
      Dim fooBar As Variant 
      Set fooBaz = New Dictionary 
      fooBar = 1 + (1 + (1 + (1 + fooBaz.FooBar)))
  End Sub
  
  Private Function Bar(baz As Long) As Variant
  End Function";
              Assert.AreEqual(1, ArrangeParserAndGetResultCount(inputCode));
          }
  
          [Test]
          [Category("Inspections")]
          public void MemberNotOnInterface_ExpressionInFunctionArgument()
          {
              const string inputCode =
                  @"Sub Foo()
      Dim fooBaz As Dictionary
      Dim fooBar As Variant 
      Set fooBaz = New Dictionary 
      fooBar = Bar(1 + fooBaz.FooBar)
  End Sub
  
  Private Function Bar(baz As Long) As Variant
  End Function";
              Assert.AreEqual(1, ArrangeParserAndGetResultCount(inputCode));
          }
  
          [Test]
          [Category("Inspections")]
          public void MemberNotOnInterface_FunctionArgumentInFunctionArgument()
          {
              const string inputCode =
                  @"Sub Foo()
      Dim fooBaz As Dictionary
      Dim fooBar As Variant 
      Set fooBaz = New Dictionary 
      fooBar = Bar(Bar(fooBaz.FooBar))
  End Sub
  
  Private Function Bar(baz As Long) As Variant
  End Function";
              Assert.AreEqual(1, ArrangeParserAndGetResultCount(inputCode));
          }
  
          [Test]
          [Category("Inspections")]
          public void MemberNotOnInterface_FunctionArgumentInExpressionInFunctionArgument()
          {
              const string inputCode =
                  @"Sub Foo()
      Dim fooBaz As Dictionary
      Dim fooBar As Variant 
      Set fooBaz = New Dictionary 
      fooBar = Bar(1 + Bar(fooBaz.FooBar))
  End Sub
  
  Private Function Bar(baz As Long) As Variant
  End Function";
              Assert.AreEqual(1, ArrangeParserAndGetResultCount(inputCode));
          }
  
          [Test]
          [Category("Inspections")]
          public void MemberNotOnInterface_FunctionArgumentInExpressionInProcedureArgument()
          {
              const string inputCode =
                  @"Sub Foo()
      Dim fooBaz As Dictionary
      Dim fooBar As Variant 
      Set fooBaz = New Dictionary 
      Barr 1 + Bar(fooBaz.FooBar)
  End Sub
  
  Private Function Bar(baz As Long) As Variant
  End Function
  
  Private Sub Barr(baz As Long)
  End Sub";
              Assert.AreEqual(1, ArrangeParserAndGetResultCount(inputCode));
          }
  
          [Test]
          [Category("Inspections")]
          public void MemberNotOnInterface_FunctionArgumentInExpressionInProcedureArgument_ExplicitCall()
          {
              const string inputCode =
                  @"Sub Foo()
      Dim fooBaz As Dictionary
      Dim fooBar As Variant 
      Set fooBaz = New Dictionary 
  
gt:     Call Barr(1 + Bar(fooBaz.FooBar))