<?php

/*
 * @copyright NetMonsters <team@netmonsters.ru>
 * @link http://netmonsters.ru
 * @package Majestic
 * @subpackage UnitTests
 * @since 2011-10-11
 * 
 * Unit tests for RedisManager class
 */

require_once dirname(__FILE__) . '/../../Registry.php';
require_once dirname(__FILE__) . '/../../Config.php';
require_once dirname(__FILE__) . '/../../redis/RedisManager.php';
require_once dirname(__FILE__) . '/../../exception/GeneralException.php';

class RedisManagerTest extends PHPUnit_Framework_TestCase
{
    private $connections;

    public function run(PHPUnit_Framework_TestResult $result = NULL)
    {
        $this->setPreserveGlobalState(false);
        return parent::run($result);
    }

    public function setUp()
    {
        $this->getMock('Redis');

        $conf = Config::getInstance();
        if ($conf->offsetExists('Redis')) {
            $conf->offsetUnset('Redis');
        }

        $class = new ReflectionClass('RedisManager');
        $this->connections = $class->getProperty('connections');
        $this->connections->setAccessible(true);
        $this->connections->setValue(null, array());

        set_new_overload(array($this, 'newCallback'));
    }

    /**
     * @TODO: line 34: $config = Config::get('Redis')->$name; - check for Redis config existence. Agafonov: 'check added'
     */
    public function testConnectNoAnyConfig()
    {
        $this->setExpectedException('GeneralException', 'Redis config no existence');
        RedisManager::connect();
    }

    public function testConnectWrongPersistantConfig()
    {
        $this->setExpectedException('GeneralException', 'Connection parameters must be an array');
        Config::set('Redis', array('new' => 'some'));
        RedisManager::connect('new');
    }

    public function testConnectDefaultConfig()
    {
        $this->setExpectedException('GeneralException', 'Connection parameters must be an array');
        Config::set('Redis', array('default' => 'some'));
        RedisManager::connect();
    }

    public function testConnectFailedConnection()
    {
        $this->setExpectedException('GeneralException', 'Failed to connect to Redis server at');
        Config::set('Redis', array('new' => array('host' => 'error', 'port' => 2023, 'database' => 'some')));
        RedisManager::connect('new');
    }

    public function testConnectEstablishedConnectionNoDb()
    {
        $this->setExpectedException('GeneralException', 'Failed to select Redis database with index');
        Config::set('Redis', array('new' => array('host' => true, 'port' => 2023, 'database' => 'some')));
        RedisManager::connect('new');
    }

    public function testConnectionGood()
    {
        Config::set('Redis', array('new' => array('host' => true, 'port' => 2023, 'database' => true)));
        $redis = RedisManager::connect('new');
        $this->assertInstanceOf('RedisMock', $redis);
    }

    /**
     * @runInSeparateProcess
     */
    public function testConnectWithDebug()
    {
        if (!defined('DEBUG')) {
            define('DEBUG', true);
        }
        $this->getMock('RedisDebug');

        Config::set('Redis', array('new' => array('host' => true, 'port' => 2023, 'database' => true)));
        $redis = RedisManager::connect('new');
        $this->assertInstanceOf('RedisDebugMock', $redis);
    }

    public function testConnectWithConfigArray()
    {
        $config = array('host' => true, 'port' => 2023, 'database' => true);
        $redis = RedisManager::connect('nsew', $config);
        $this->assertInstanceOf('RedisMock', $redis);
    }

    protected function newCallback($className)
    {
        switch ($className) {
            case 'Redis':
                return 'RedisMock';
            case 'RedisDebug':
                return 'RedisDebugMock';
            default:
                return $className;
        }
    }

    public function tearDown()
    {
        unset_new_overload();
    }
}

class RedisMock
{
    public function connect($host, $port)
    {
        if ($host === true) {
            return true;
        }
        return false;
    }

    public function select($dbname)
    {
        if ($dbname === true) {
            return true;
        }
        return false;
    }
}

class RedisDebugMock extends RedisMock
{
}