﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="DisposeShould.cs" company="Epworth Consulting Ltd.">
//   © Epworth Consulting Ltd.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
namespace Atlas.ServiceBus.RabbitMQ.Tests.RabbitMQMessageListenerTests
{
   using System;

   using Atlas.Core.Logging;
   using Atlas.ServiceBus.RabbitMQ.Implementations;

   using FakeItEasy;

   using NUnit.Framework;

   using global::RabbitMQ.Client;

   public class DisposeShould
   {
      private IChannelManagerFactory channelManagerFactory;
      private IMessageHandlerTypesIndexFactory messageHandlerTypesIndexFactory;
      private IMessageHandlerInvokerFactory messageHandlerInvokerFactory;
      private IQueueNameConvention queueNameConvention;
      private IMessageEncoder messageEncoder;
      private IMessageSerialiser messageSerialiser;
      private ILogger logger;
      private IConfiguration configuration;
      private IChannelManager channelManager;
      private IModel channel;

      private RabbitMQMessageListener componentUnderTest;

      [SetUp]
      public void SetupBeforeEachTest()
      {
         this.channelManagerFactory = A.Fake<IChannelManagerFactory>();
         this.messageHandlerTypesIndexFactory = A.Fake<IMessageHandlerTypesIndexFactory>();
         this.messageHandlerInvokerFactory = A.Fake<IMessageHandlerInvokerFactory>();
         this.queueNameConvention = A.Fake<IQueueNameConvention>();
         this.messageEncoder = A.Fake<IMessageEncoder>();
         this.messageSerialiser = A.Fake<IMessageSerialiser>();
         this.logger = A.Fake<ILogger>();
         this.configuration = A.Fake<IConfiguration>();
         this.channelManager = A.Fake<IChannelManager>();
         this.channel = A.Fake<IModel>();

         A.CallTo(() => this.channelManagerFactory.Create()).Returns(this.channelManager);
         A.CallTo(() => this.channelManager.CreateChannel()).Returns(this.channel);

         this.componentUnderTest = new RabbitMQMessageListener(this.channelManagerFactory, new Type[0], this.messageHandlerTypesIndexFactory, this.messageHandlerInvokerFactory, this.queueNameConvention, this.messageEncoder, this.messageSerialiser, this.logger, this.configuration);
      }

      [Test]
      public void NotDisposeOfChannelIfListenOnceNotCalled()
      {
         this.componentUnderTest.Dispose();

         A.CallTo(() => this.channel.Dispose()).MustNotHaveHappened();
      }

      [Test]
      public void DisposeOfChannel()
      {
         // Listen will create the channel
         this.componentUnderTest.ListenOnce();

         this.componentUnderTest.Dispose();

         A.CallTo(() => this.channel.Dispose()).MustHaveHappened(Repeated.Exactly.Once);
      }

      [Test]
      public void DisposeOfChannelOnlyOnce()
      {
         // Listen will create the channel
         this.componentUnderTest.ListenOnce();

         this.componentUnderTest.Dispose();
         this.componentUnderTest.Dispose();

         A.CallTo(() => this.channel.Dispose()).MustHaveHappened(Repeated.Exactly.Once);
      }

      [Test]
      public void ShouldNotDisposeOfConnectionDuringFinalise()
      {
         // Listen will create the channel
         this.componentUnderTest.ListenOnce();

         this.componentUnderTest = null;
         GC.Collect();
         GC.WaitForPendingFinalizers();

         A.CallTo(() => this.channel.Dispose()).MustNotHaveHappened();
      }
   }
}
