<?php
/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * @category   tests   
 * @package    log4php
 * @subpackage renderers
 * @license    http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
 * @version    $Revision: 1394956 $
 * @link       http://logging.apache.org/log4php
 */

/** Renders everything as 'foo'. */
class FooRenderer implements LoggerRenderer {
	public function render($input) {
		return 'foo';
	}
}

class InvalidCostumObjectRenderer { }

class Fruit3 {
    public $test1 = 'test1';
    public $test2 = 'test2';
    public $test3 = 'test3';
}

class Fruit3Descendant extends Fruit3 {
}

class FruitRenderer3 implements LoggerRenderer {
    public function render($fruit) {
		return $fruit->test1 . ',' . $fruit->test2 . ',' . $fruit->test3;
	}
}

class SampleObject {
}

/**
 * @group renderers
 */
class LoggerRendererMapTest extends PHPUnit_Framework_TestCase {

	public function testDefaults() {
		
		$map = new LoggerRendererMap();
		$actual = $map->getByClassName('Exception');
		self::assertInstanceOf('LoggerRendererException', $actual);
		
		// Check non-configured objects return null
		self::assertNull($map->getByObject(new stdClass()));
		self::assertNull($map->getByClassName('stdClass'));
	}
	
	public function testClear() 
	{
		$map = new LoggerRendererMap();
		$map->clear(); // This should clear the map and remove default renderers
		self::assertNull($map->getByClassName('Exception'));
	}
	
	public function testFindAndRender() 
	{
		$map = new LoggerRendererMap();
		$map->addRenderer('Fruit3', 'FruitRenderer3');

		$fruit = new Fruit3();
		$descendant = new Fruit3Descendant();
		
		// Check rendering of fruit
		$actual = $map->findAndRender($fruit);
		$expected = 'test1,test2,test3';
		self::assertSame($expected, $actual);
		
		$actual = $map->getByObject($fruit);
		self::assertInstanceOf('FruitRenderer3', $actual);
		
		// Check rendering of fruit's descendant
		$actual = $map->findAndRender($descendant);
		$expected = 'test1,test2,test3';
		self::assertSame($expected, $actual);
		
		$actual = $map->getByObject($descendant);
		self::assertInstanceOf('FruitRenderer3', $actual);
		
		// Test rendering null returns null
		self::assertNull($map->findAndRender(null));
	}
	
	/**
	 * Try adding a non-existant class as renderer.
	 * @expectedException PHPUnit_Framework_Error
 	 * @expectedExceptionMessage Failed adding renderer. Rendering class [DoesNotExist] not found.
	 */
	public function testAddRendererError1() 
	{
		$map = new LoggerRendererMap();
		$map->addRenderer('Fruit3', 'DoesNotExist');
	}
	
	/**
	 * Try adding a class which does not implement LoggerRenderer as renderer.
	 * @expectedException PHPUnit_Framework_Error
 	 * @expectedExceptionMessage Failed adding renderer. Rendering class [stdClass] does not implement the LoggerRenderer interface.
	 */
	public function testAddRendererError2() 
	{
		$map = new LoggerRendererMap();
		$map->addRenderer('Fruit3', 'stdClass');
	}
	
	public function testAddRendererError3() 
	{
		$map = new LoggerRendererMap();
		@$map->addRenderer('Fruit3', 'stdClass');
		self::assertNull($map->getByClassName('Fruit3'));
		
		@$map->addRenderer('Fruit3', 'DoesNotExist');
		self::assertNull($map->getByClassName('Fruit3'));
	}
	
	/**
	 * Try setting a non-existant class as default renderer.
	 * @expectedException PHPUnit_Framework_Error
	 * @expectedExceptionMessage Failed setting default renderer. Rendering class [DoesNotExist] not found.
	 */
	public function testSetDefaultRendererError1() 
	{
		$map = new LoggerRendererMap();
		$map->setDefaultRenderer('DoesNotExist');
	}
	
	/**
	 * Try setting a class which does not implement LoggerRenderer as default renderer.
	 * @expectedException PHPUnit_Framework_Error
	 * @expectedExceptionMessage Failed setting default renderer. Rendering class [stdClass] does not implement the LoggerRenderer interface.
	 */
	public function testSetDefaultRendererError2()
	{
		$map = new LoggerRendererMap();
		$map->setDefaultRenderer('stdClass');
	}
	
	public function testSetDefaultRendererError3()
	{
		$map = new LoggerRendererMap();
		$expected =  $map->getDefaultRenderer();
		
		@$map->setDefaultRenderer('stdClass');
		$actual = $map->getDefaultRenderer();
		self::assertSame($expected, $actual);
	
		@$map->setDefaultRenderer('DoesNotExist');
		$actual = $map->getDefaultRenderer();
		self::assertSame($expected, $actual);
	}
	
	public function testFetchingRenderer() 
	{
		$map = new LoggerRendererMap();
		$map->addRenderer('Fruit3', 'FruitRenderer3');
	}
	
	public function testDefaultRenderer() 
	{
		$fruit = new Fruit3();
		
		$map = new LoggerRendererMap();
		$actual = $map->findAndRender($fruit);
		
		$defaultRenderer = new LoggerRendererDefault();
		$expected = $defaultRenderer->render($fruit);
		self::assertSame($expected, $actual);
	}
	
	public function testOverrideDefaultRenderer() 
	{
		$map = new LoggerRendererMap();
		$default = $map->getDefaultRenderer();
		
		$array = array(1, 2, 3);
		
		$actual = $map->findAndRender($array);
		$expected = print_r($array, true);
		self::assertSame($actual, $expected);
		
		// Now switch the default renderer
		$map->setDefaultRenderer('FooRenderer');
		$actual = $map->findAndRender($array);
		$expected = 'foo';
		self::assertSame($actual, $expected);
	}

	public function testGetByObjectCrap()
	{
		$map = new LoggerRendererMap();
		
		// Non object input should always return null
		self::assertNull($map->getByObject(null));
		self::assertNull($map->getByObject(array()));
		self::assertNull($map->getByObject('sdasda'));
	}
	
	public function testXMLConfig() 
	{
		$map = Logger::getHierarchy()->getRendererMap();
		Logger::resetConfiguration();
		self::assertInstanceOf('LoggerRendererDefault', $map->getDefaultRenderer());
		
		Logger::configure(PHPUNIT_CONFIG_DIR . '/renderers/config_default_renderer.xml');
		self::assertInstanceOf('FruitRenderer3', $map->getDefaultRenderer());
		
		Logger::resetConfiguration();
		self::assertInstanceOf('LoggerRendererDefault', $map->getDefaultRenderer());
	}
	
	public function testExceptionRenderer() 
	{
		$ex = new LoggerException("This is a test");
		
		$map = new LoggerRendererMap();
		$actual = $map->findAndRender($ex);
		$expected = (string) $ex;

		self::assertSame($expected, $actual);
	}
	
	
}
