<?php

require_once 'Swift/Tests/SwiftUnitTestCase.php';
require_once 'Swift/Plugins/LoggerPlugin.php';
require_once 'Swift/Plugins/Logger.php';
require_once 'Swift/Events/CommandEvent.php';
require_once 'Swift/Events/ResponseEvent.php';
require_once 'Swift/Events/TransportChangeEvent.php';
require_once 'Swift/Events/TransportExceptionEvent.php';
require_once 'Swift/Transport.php';
require_once 'Swift/TransportException.php';

class Swift_Plugins_LoggerPluginTest extends Swift_Tests_SwiftUnitTestCase
{

  public function testLoggerDelegatesAddingEntries()
  {
    $logger = $this->_createLogger();
    $this->_checking(Expectations::create()
      -> one($logger)->add('foo')
      );
    
    $plugin = $this->_createPlugin($logger);
    $plugin->add('foo');
  }
  
  public function testLoggerDelegatesDumpingEntries()
  {
    $logger = $this->_createLogger();
    $this->_checking(Expectations::create()
      -> one($logger)->dump() -> returns('foobar')
      );
    
    $plugin = $this->_createPlugin($logger);
    $this->assertEqual('foobar', $plugin->dump());
  }
  
  public function testLoggerDelegatesClearingEntries()
  {
    $logger = $this->_createLogger();
    $this->_checking(Expectations::create()
      -> one($logger)->clear()
      );
    
    $plugin = $this->_createPlugin($logger);
    $plugin->clear();
  }
  
  public function testCommandIsSentToLogger()
  {
    $evt = $this->_createCommandEvent("foo\r\n");
    $logger = $this->_createLogger();
    $this->_checking(Expectations::create()
      -> one($logger)->add(pattern('~foo\r\n~'))
      );
    
    $plugin = $this->_createPlugin($logger);
    $plugin->commandSent($evt);
  }
  
  public function testResponseIsSentToLogger()
  {
    $evt = $this->_createResponseEvent("354 Go ahead\r\n");
    $logger = $this->_createLogger();
    $this->_checking(Expectations::create()
      -> one($logger)->add(pattern('~354 Go ahead\r\n~'))
      );
    
    $plugin = $this->_createPlugin($logger);
    $plugin->responseReceived($evt);
  }
  
  public function testTransportBeforeStartChangeIsSentToLogger()
  {
    $evt = $this->_createTransportChangeEvent();
    $logger = $this->_createLogger();
    $this->_checking(Expectations::create()
      -> one($logger)->add(any())
      );
    
    $plugin = $this->_createPlugin($logger);
    $plugin->beforeTransportStarted($evt);
  }
  
  public function testTransportStartChangeIsSentToLogger()
  {
    $evt = $this->_createTransportChangeEvent();
    $logger = $this->_createLogger();
    $this->_checking(Expectations::create()
      -> one($logger)->add(any())
      );
    
    $plugin = $this->_createPlugin($logger);
    $plugin->transportStarted($evt);
  }
  
  public function testTransportStopChangeIsSentToLogger()
  {
    $evt = $this->_createTransportChangeEvent();
    $logger = $this->_createLogger();
    $this->_checking(Expectations::create()
      -> one($logger)->add(any())
      );
    
    $plugin = $this->_createPlugin($logger);
    $plugin->transportStopped($evt);
  }
  
  public function testTransportBeforeStopChangeIsSentToLogger()
  {
    $evt = $this->_createTransportChangeEvent();
    $logger = $this->_createLogger();
    $this->_checking(Expectations::create()
      -> one($logger)->add(any())
      );
    
    $plugin = $this->_createPlugin($logger);
    $plugin->beforeTransportStopped($evt);
  }
  
  public function testExceptionsArePassedToDelegateAndLeftToBubbleUp()
  {
    $transport = $this->_createTransport();
    $evt = $this->_createTransportExceptionEvent();
    $logger = $this->_createLogger();
    $this->_checking(Expectations::create()
      -> one($logger)->add(any())
      -> allowing($logger)
      );
    
    $plugin = $this->_createPlugin($logger);
    try
    {
      $plugin->exceptionThrown($evt);
      $this->fail('Exception should bubble up.');
    }
    catch (Swift_TransportException $ex)
    {
    }
  }
  
  // -- Creation Methods
  
  private function _createLogger()
  {
    return $this->_mock('Swift_Plugins_Logger');
  }
  
  private function _createPlugin($logger)
  {
    return new Swift_Plugins_LoggerPlugin($logger);
  }
  
  private function _createCommandEvent($command)
  {
    $evt = $this->_mock('Swift_Events_CommandEvent');
    $this->_checking(Expectations::create()
      -> ignoring($evt)->getCommand() -> returns($command)
      -> ignoring($evt)
      );
    return $evt;
  }
  
  private function _createResponseEvent($response)
  {
    $evt = $this->_mock('Swift_Events_ResponseEvent');
    $this->_checking(Expectations::create()
      -> ignoring($evt)->getResponse() -> returns($response)
      -> ignoring($evt)
      );
    return $evt;
  }
  
  private function _createTransport()
  {
    return $this->_mock('Swift_Transport');
  }
  
  private function _createTransportChangeEvent()
  {
    $evt = $this->_mock('Swift_Events_TransportChangeEvent');
    $this->_checking(Expectations::create()
      -> ignoring($evt)->getSource() -> returns($this->_createTransport())
      -> ignoring($evt)
      );
    return $evt;
  }
  
  private function _createTransportExceptionEvent()
  {
    $evt = $this->_mock('Swift_Events_TransportExceptionEvent');
    $this->_checking(Expectations::create()
      -> ignoring($evt)->getException() -> returns(new Swift_TransportException(''))
      -> ignoring($evt)
      );
    return $evt;
  }
  
}