<?php
/**
 * core.framework
 *
 * @category   Core
 * @package    Core_Form
 * @subpackage UnitTests
 * @copyright  Copyright (c) 2011. Burza d.o.o. (http://web.burza.hr/en/)
 * @license    proprietary
 */

/**
 * @category   Core
 * @package    Core_Form
 * @subpackage UnitTests
 * @copyright  Copyright (c) 2011. Burza d.o.o. (http://web.burza.hr/en/)
 * @license    proprietary
 * @group      Core_Form
 */
class Core_Form_Group_AbstractTest extends CoreTest_Container_TestCase
{
    /**
     * @var Core_Form_Group_Abstract
     */
    protected $_object;

    protected $_error;

    protected function setUp()
    {
        $this->_object = $this->getMockForAbstractClass('Core_Form_Group_Abstract');
    }
    
    /**
     * @covers Core_Form_Group_Abstract::setTranslator
     * @covers Core_Form_Group_Abstract::getTranslator
     */
    public function testSetAndGetTranslator()
    {
        $translator = $this->getMock('Zend_Translate');
        $this->_object->setTranslator($translator);

        $this->assertEquals($translator, $this->_object->getTranslator());
    }
    
    /**
     * @covers Core_Form_Group_Abstract::getTranslator
     */
    public function testIfTranslatorNotSetWillTryToFetchItFromParent()
    {
        $translator = $this->getMock('Zend_Translate');
        $parent     = $this->getMock('Core_Form', array('getTranslator'));
        $parent
            ->expects($this->once())
            ->method('getTranslator')
            ->will($this->returnValue($translator));
        $this->_object->setOwner($parent);

        $this->assertEquals($translator, $this->_object->getTranslator());
    }

    /**
     * @covers Core_Form_Group_Abstract::setPluginManager
     * @covers Core_Form_Group_Abstract::getPluginManager
     */
    public function testSetAndGetPluginManager()
    {
        $pluginManager = $this->getMock('Core_Plugin_Manager', array(), array($this->_object));
        $this->_object->setPluginManager($pluginManager);

        $this->assertEquals($pluginManager, $this->_object->getPluginManager());
    }

    /**
     * @covers Core_Form_Group_Abstract::init
     */
    public function testInitWillDoNothingByDefault()
    {
        $this->assertSame($this->_object, $this->_object->init());
    }

    /**
     * @covers Core_Form_Group_Abstract::__construct
     * @covers Core_Form_Group_Abstract::__call
     */
    public function testCanManageGroups()
    {
        $group = $this->getMockForAbstractClass('Core_Form_Group_Abstract', array(), '', true, true, true, array('getName'));
        $group
            ->expects($this->once())
            ->method('getName')
            ->will($this->returnValue('myGroup'));
        $this->_object->addGroup($group);

        $this->assertTrue($this->_object->hasGroup('MyGroup'));
    }

    /**
     * @covers Core_Form_Group_Abstract::__construct
     * @covers Core_Form_Group_Abstract::__call
     */
    public function testCanManageElements()
    {
        $element = $this->getMockForAbstractClass('Core_Form_Element_Abstract', array(), '', true, true, true, array('getName'));
        $element
            ->expects($this->once())
            ->method('getName')
            ->will($this->returnValue('myElement'));
        $this->_object->addElement($element);

        $this->assertTrue($this->_object->hasElement('MyElement'));
    }

    /**
     * @covers Core_Form_Group_Abstract::__call
     */
    public function testIfAddingAnElementWithANameAlreadyUsedByAGroupWillThrowAnInvalidArgumentException()
    {
        $this->setExpectedException('InvalidArgumentException');

        $group = $this->getMockForAbstractClass('Core_Form_Group_Abstract', array(), '', true, true, true, array('getName'));
        $group
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('sameName'));
        $this->_object->addGroup($group);

        $element = $this->getMockForAbstractClass('Core_Form_Element_Abstract', array(), '', true, true, true, array('getName'));
        $element
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('sameName'));
        $this->_object->addElement($element);
    }

    /**
     * @covers Core_Form_Group_Abstract::__call
     */
    public function testIfAddingAGroupWithANameAlreadyUsedByAnElementWillThrowAnInvalidArgumentException()
    {
        $this->setExpectedException('InvalidArgumentException');

        $element = $this->getMockForAbstractClass('Core_Form_Element_Abstract', array(), '', true, true, true, array('getName'));
        $element
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('sameName'));
        $this->_object->addElement($element);

        $group = $this->getMockForAbstractClass('Core_Form_Group_Abstract', array(), '', true, true, true, array('getName'));
        $group
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('sameName'));
        $this->_object->addGroup($group);
    }

    /**
     * @covers Core_Form_Group_Abstract::__call
     */
    public function testCallsToNonexistantMethodsNotPrefixedWithGetWillThrowABadMethodCallException()
    {
        $this->setExpectedException('BadMethodCallException');
        $this->_object->fooSomething();
    }

    /**
     * @covers Core_Form_Group_Abstract::setPrototype
     * @covers Core_Form_Group_Abstract::isPrototype
     */
    public function testCanSetAndGetPrototypeFlag()
    {
        $this->_object->setPrototype(true);
        $this->assertTrue($this->_object->isPrototype());
    }

    /**
     * @covers Core_Form_Group_Abstract::isPrototype
     */
    public function testIsNotPrototypeByDefault()
    {
        $this->assertFalse($this->_object->isPrototype());
    }

    /**
     * @covers Core_Form_Group_Abstract::setContext
     * @covers Core_Form_Group_Abstract::getContext
     */
    public function testCanSetAndGetContext()
    {
        $this->_object->setContext('fooContext');

        $this->assertEquals('fooContext', $this->_object->getContext());
    }

    /**
     * @covers Core_Form_Group_Abstract::getContext
     */
    public function testDefaultContextIsSet()
    {
        $this->assertEquals(Core_Form::CONTEXT_DEFAULT, $this->_object->getContext());
    }

    /**
     * @covers Core_Form_Group_Abstract::setName
     * @covers Core_Form_Group_Abstract::getName
     */
    public function testCanSetAndGetName()
    {
        $this->_object->setName('fooName');

        $this->assertEquals('fooName', $this->_object->getName());
    }

    /**
     * @covers Core_Form_Group_Abstract::setLabel
     * @covers Core_Form_Group_Abstract::getLabel
     * @covers Core_Form_Group_Abstract::<protected>
     */
    public function testCanSetAndGetLabel()
    {
        $this->_object->setLabel('Some label');

        $this->assertEquals('Some label', $this->_object->getLabel());
    }
    
    /**
     * @covers Core_Form_Group_Abstract::getLabel
     * @covers Core_Form_Group_Abstract::<protected>
     */
    public function testWillTranslateLabelIfTranslatorAvailable()
    {
        $translator = $this->getMock('Zend_Translate', array('translate'), array(), '', false);
        $translator
            ->expects($this->once())
            ->method('translate')
            ->with($this->equalTo('Some label'))
            ->will($this->returnValue('Neka labela'));
        
        $this->_object
            ->setTranslator($translator)
            ->setLabel('Some label');        

        $this->assertEquals('Neka labela', $this->_object->getLabel());
    }
    
    /**
     * @covers Core_Form_Group_Abstract::setDescription
     * @covers Core_Form_Group_Abstract::getDescription
     * @covers Core_Form_Group_Abstract::<protected>
     */
    public function testCanSetAndGetDescription()
    {
        $this->_object->setDescription('Some additional description');

        $this->assertEquals('Some additional description', $this->_object->getDescription());
    }
    
    /**
     * @covers Core_Form_Group_Abstract::getDescription
     * @covers Core_Form_Group_Abstract::<protected>
     */
    public function testWillTranslateDescriptionlIfTranslatorAvailable()
    {
        $translator = $this->getMock('Zend_Translate', array('translate'), array(), '', false);
        $translator
            ->expects($this->once())
            ->method('translate')
            ->with($this->equalTo('Some description'))
            ->will($this->returnValue('Neki opis'));
        
        $this->_object
            ->setTranslator($translator)
            ->setDescription('Some description');        

        $this->assertEquals('Neki opis', $this->_object->getDescription());
    }

    /**
     * @covers Core_Form_Group_Abstract::setModel
     * @covers Core_Form_Group_Abstract::getModel
     */
    public function testCanSetAndGetModel()
    {
        $this->_object->setModel('fooModel');

        $this->assertEquals('fooModel', $this->_object->getModel());
    }

    /**
     * @covers Core_Form_Group_Abstract::getName
     */
    public function testDefaultNameEqualsToModelPlusForm()
    {
        $this->_object->setModel('fooModel');

        $this->assertEquals('fooModelForm', $this->_object->getName());
    }

    /**
     * @covers Core_Form_Group_Abstract::getFullyQualifiedName
     */
    public function testFullyQualifiedNameIsNullIfNoParentGiven()
    {
        $this->_object->setName('fooName');

        $this->assertNull($this->_object->getFullyQualifiedName());
    }

    /**
     * @covers Core_Form_Group_Abstract::setId
     * @covers Core_Form_Group_Abstract::getId
     */
    public function testCanSetAndGetId()
    {
        $this->_object->setId('fooId');

        $this->assertEquals('fooId', $this->_object->getId());
    }

    /**
     * @covers Core_Form_Group_Abstract::setId
     * @covers Core_Form_Group_Abstract::getAttrib
     */
    public function testSettingIdWillUpdateAttribId()
    {
        $this->_object->setId('fooId');

        $this->assertEquals('fooId', $this->_object->getAttrib('id'));
    }

    /**
     * @covers Core_Form_Group_Abstract::getFullyQualifiedId
     */
    public function testFullyQualifiedIdIsEqualToId()
    {
        $this->_object->setId('fooId');

        $this->assertEquals('fooId', $this->_object->getFullyQualifiedId());
    }

    /**
     * @covers Core_Form_Group_Abstract::getFullyQualifiedAngularId
     */
    public function testIfGroupIsPrototypeWillUseParentFullyQualifiedAngularIdForFullyQualifiedAngularId()
    {
        $parent = $this->getMock('Core_Form', array('getFullyQualifiedAngularId'));
        $parent
            ->expects($this->once())
            ->method('getFullyQualifiedAngularId')
            ->will($this->returnValue('myFormGroup_mySubGroup'));

        $this->_object
            ->setId('ignored')
            ->setPrototype(true)
            ->setOwner($parent)
            ->init();

        $this->assertEquals('myFormGroup_mySubGroup', $this->_object->getFullyQualifiedAngularId());
    }

    /**
     * @covers Core_Form_Group_Abstract::getFullyQualifiedAngularId
     */
    public function testIfGroupIsNotPrototypeWillUseParentFullyQualifiedAngularIdWithOwnModelAsAngularId()
    {
        $parent = $this->getMock('Core_Form', array('getFullyQualifiedAngularId'));
        $parent
            ->expects($this->once())
            ->method('getFullyQualifiedAngularId')
            ->will($this->returnValue('myFormGroup_mySubGroup'));

        $this->_object
            ->setModel('my_model')
            ->setPrototype(false)
            ->setOwner($parent)
            ->init();

        $this->assertEquals('myFormGroup_mySubGroup_my_model', $this->_object->getFullyQualifiedAngularId());
    }

    /**
     * @covers Core_Form_Group_Abstract::getFullyQualifiedAngularId
     */
    public function testIfGroupIsNotPrototypeFullyQualifiedAngularIdEqualsFullyQualifiedId()
    {
        $this->_object->setModel('ignored');

        $this->assertEquals('ignored', $this->_object->getFullyQualifiedAngularId());
    }

    /**
     * @covers Core_Form_Group_Abstract::getFullyQualifiedAngularModel
     */
    public function testCanGetFullyQualifiedAngularModel()
    {
        $this->_object->setName('myLocalForm');

        $this->assertEquals('data.myLocalForm', $this->_object->getFullyQualifiedAngularModel());
    }

    /**
     * @covers Core_Form_Group_Abstract::setAttribs
     * @covers Core_Form_Group_Abstract::getAttribs
     */
    public function testCanSetAndGetAttribs()
    {
        $this->_object->setAttribs(array('id' => 'form', 'class' => 'g_h_123'));
        $this->assertEquals(array('id' => 'form', 'class' => 'g_h_123'), $this->_object->getAttribs());
    }

    /**
     * @covers Core_Form_Group_Abstract::getAttribs
     * @covers Core_Form_Group_Abstract::<protected>
     */
    public function testGetAttribsWillMergeMandatoryAttribsForRequestedContext()
    {
        $object = new Invalid_Form_Group_Invalid;
        $object
            ->setContext('randomContext')
            ->setName('abla');

        $this->assertEquals(array(
            'name'     => 'abla',
            'id'       => 'abla',
            'mojMakro' => 'nope',
        ), $object->getAttribs());
    }

    /**
     * @covers Core_Form_Group_Abstract::getAttribs
     */
    public function testGetAttribsWillChangeContext()
    {
        $this->_object->getAttribs(Core_Form::CONTEXT_ANGULAR);

        $this->assertEquals(Core_Form::CONTEXT_ANGULAR, $this->_object->getContext());
    }

    /**
     * @covers Core_Form_Group_Abstract::setAttrib
     * @covers Core_Form_Group_Abstract::getAttrib
     */
    public function testCanSetAndGetAttrib()
    {
        $this->_object->setAttrib('aBC', 'err');
        $this->assertEquals('err', $this->_object->getAttrib('Abc'));
    }

    /**
     * @covers Core_Form_Group_Abstract::getAttrib
     */
    public function testFetchingAnUnknownAttribWillReturnNull()
    {
        $this->assertNull($this->_object->getAttrib('no such attrib'));
    }

    /**
     * @covers Core_Form_Group_Abstract::setOptions
     */
    public function testCanSetOptions()
    {
        $options = array('attribs' => array('class' => 'g_h_23'));
        $this->_object->setOptions($options);

        $this->assertEquals('g_h_23', $this->_object->getAttrib('class'));
    }

    /**
     * @covers Core_Form_Group_Abstract::setConfig
     */
    public function testCanSetConfig()
    {
        $config = $this->getMock('Zend_Config', null, array(array('attribs' => array('class' => 'g_h_23'))));
        $this->_object->setConfig($config);

        $this->assertEquals('g_h_23', $this->_object->getAttrib('class'));
    }

    /**
     * @covers Core_Form_Group_Abstract::setOptions
     * @covers Core_Form_Group_Abstract::set
     */
    public function testPassingAnUnknownOptionsThrowsAnInvalidArgumentException()
    {
        $this->setExpectedException('InvalidArgumentException');
        $this->_object->setOptions(array('no-such' => 'option'));
    }

    /**
     * @covers Core_Form_Group_Abstract::__construct
     */
    public function testCanSetOptionsViaConstructor()
    {
        $object = $this->getMockForAbstractClass('Core_Form_Group_Abstract', array(array('attribs' => array('class' => 'g_h_23'))));

        $this->assertEquals('g_h_23', $object->getAttrib('class'));
    }

    /**
     * @covers Core_Form_Group_Abstract::__construct
     */
    public function testCanSetConfigViaConstructor()
    {
        $config = $this->getMock('Zend_Config', null, array(array('attribs' => array('class' => 'g_h_23'))));
        $object = $this->getMockForAbstractClass('Core_Form_Group_Abstract', array($config));

        $this->assertEquals('g_h_23', $object->getAttrib('class'));
    }

    /**
     * @covers Core_Form_Group_Abstract::setOptions
     */
    public function testCanAddGroupsViaOptions()
    {
        $group = $this->getMockForAbstractClass('Core_Form_Group_Abstract', array(), '', true, true, true, array('getName'));
        $group
            ->expects($this->once())
            ->method('getName')
            ->will($this->returnValue('myGroup'));
        $this->_object->setOptions(array('groups' => array($group)));

        $this->assertTrue($this->_object->hasGroup('MyGroup'));
    }

    /**
     * @covers Core_Form_Group_Abstract::setOptions
     */
    public function testCanAddElementsViaOptions()
    {
        $element = $this->getMockForAbstractClass('Core_Form_Element_Abstract', array(), '', true, true, true, array('getName'));
        $element
            ->expects($this->once())
            ->method('getName')
            ->will($this->returnValue('myElement'));
        $this->_object->setOptions(array('elements' => array($element)));

        $this->assertTrue($this->_object->hasElement('MyElement'));
    }

    /**
     * @covers Core_Form_Group_Abstract::setOwner
     * @covers Core_Form_Group_Abstract::getParent
     */
    public function testWillStoreParentPassedViaInit()
    {
        $parent = $this->getMock('Core_Form', array(), array(), '', false);
        $this->_object->setOwner($parent);

        $this->assertEquals($parent, $this->_object->getParent());
    }

    /**
     * @covers Core_Form_Group_Abstract::setOwner
     * @covers Core_Form_Group_Abstract::getParent
     */
    public function testParentMustBeAnInstanceOfGroup()
    {
        $this->setExpectedException('InvalidArgumentException');
        $parent = $this->getMock('Core_Plugin_Interface');

        $this->_object->setOwner($parent);
    }

    /**
     * @covers Core_Form_Group_Abstract::getRoot
     */
    public function testRootIsSelfIfNoParent()
    {
        $this->assertSame($this->_object, $this->_object->getRoot());
    }

    /**
     * @covers Core_Form_Group_Abstract::getRoot
     */
    public function testRootIsParentRootIfParentSet()
    {
        $parent = $this->getMock('Core_Form', array('getRoot'));
        $parent
            ->expects($this->once())
            ->method('getRoot')
            ->will($this->returnValue($this));
        $this->_object->setOwner($parent);

        $this->assertSame($this, $this->_object->getRoot());
    }

    /**
     * @covers Core_Form_Group_Abstract::getId
     */
    public function testDefaultIdIsEqualToName()
    {
        $this->_object->setName('fooBla');

        $this->assertEquals('fooBla', $this->_object->getId());
    }

    /**
     * @covers Core_Form_Group_Abstract::getFullyQualifiedName
     */
    public function testCanGetFullyQualifiedName()
    {
        $parent = $this->getMock('Core_Form', array('getFullyQualifiedName'));
        $parent
            ->expects($this->once())
            ->method('getFullyQualifiedName')
            ->will($this->returnValue('myFormGroup'));

        $this->_object
            ->setName('myLocalForm')
            ->setOwner($parent)
            ->init();

        $this->assertEquals('myFormGroup[myLocalForm]', $this->_object->getFullyQualifiedName());
    }

    /**
     * @covers Core_Form_Group_Abstract::getFullyQualifiedName
     */
    public function testFullyQualifiedNameIsEqualToNameIfParentFullyQualifiedNameIsNull()
    {
        $parent = $this->getMock('Core_Form', array('getFullyQualifiedName'));
        $parent
            ->expects($this->once())
            ->method('getFullyQualifiedName')
            ->will($this->returnValue(null));

        $this->_object
            ->setName('myLocalForm')
            ->setOwner($parent)
            ->init();

        $this->assertEquals('myLocalForm', $this->_object->getFullyQualifiedName());
    }

    /**
     * @covers Core_Form_Group_Abstract::getFullyQualifiedId
     */
    public function testCanGetFullyQualifiedId()
    {
        $parent = $this->getMock('Core_Form', array('getFullyQualifiedId'));
        $parent
            ->expects($this->once())
            ->method('getFullyQualifiedId')
            ->will($this->returnValue('myFormGroup'));

        $this->_object
            ->setId('myLocalForm')
            ->setOwner($parent)
            ->init();

        $this->assertEquals('myFormGroup_myLocalForm', $this->_object->getFullyQualifiedId());
    }

    /**
     * @covers Core_Form_Group_Abstract::getFullyQualifiedId
     */
    public function testDefaultFullyQualifiedIdIsEqualToId()
    {
        $this->_object->setId('fooBla');

        $this->assertEquals('fooBla', $this->_object->getFullyQualifiedId());
    }

    /**
     * @covers Core_Form_Group_Abstract::populateRaw
     * @covers Core_Form_Group_Abstract::<protected>
     */
    public function testCanPopulateRawData()
    {
        $data = array(
            'myGroup'   => array('a' => 1, 'b' => '2', 'c' => 'tri'),
            'myElement' => 'idcornholio',
        );
        $group = $this->getMockForAbstractClass('Core_Form_Group_Abstract', array(), '', true, true, true, array('getName', 'populateRaw'));
        $group
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('myGroup'));
        $group
            ->expects($this->once())
            ->method('populateRaw')
            ->with($this->equalTo(array('a' => 1, 'b' => '2', 'c' => 'tri')));
        $this->_object->addGroup($group);

        $element = $this->getMockForAbstractClass('Core_Form_Element_Abstract', array(), '', true, true, true, array('getName', 'setRawValue'));
        $element
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('myElement'));
        $element
            ->expects($this->once())
            ->method('setRawValue')
            ->with($this->equalTo('idcornholio'));
        $this->_object->addElement($element);

        $this->_object->populateRaw($data);
    }
    /**
     * @covers Core_Form_Group_Abstract::populate
     * @covers Core_Form_Group_Abstract::<protected>
     */
    public function testCanPopulateForm()
    {
        $data = array(
            'myGroup'   => array('a' => 1, 'b' => '2', 'c' => 'tri'),
            'myElement' => 'idcornholio',
        );
        $group = $this->getMockForAbstractClass('Core_Form_Group_Abstract', array(), '', true, true, true, array('getName', 'populate'));
        $group
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('myGroup'));
        $group
            ->expects($this->once())
            ->method('populate')
            ->with($this->equalTo(array('a' => 1, 'b' => '2', 'c' => 'tri')));
        $this->_object->addGroup($group);

        $element = $this->getMockForAbstractClass('Core_Form_Element_Abstract', array(), '', true, true, true, array('getName', 'setValue'));
        $element
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('myElement'));
        $element
            ->expects($this->once())
            ->method('setValue')
            ->with($this->equalTo('idcornholio'));
        $this->_object->addElement($element);

        $this->_object->populate($data);
    }

    /**
     * @covers Core_Form_Group_Abstract::getValues
     * @covers Core_Form_Group_Abstract::<protected>
     */
    public function testCanGetFormValues()
    {
        $data = array(
            'myGroup'   => array('a' => 1, 'b' => '2', 'c' => 'tri'),
            'myElement' => 'idcornholio',
        );
        $group = $this->getMockForAbstractClass('Core_Form_Group_Abstract', array(), '', true, true, true, array('getName', 'getValues'));
        $group
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('myGroup'));
        $group
            ->expects($this->once())
            ->method('getValues')
            ->will($this->returnValue(array('a' => 1, 'b' => '2', 'c' => 'tri')));
        $this->_object->addGroup($group);

        $element = $this->getMockForAbstractClass('Core_Form_Element_Abstract', array(), '', true, true, true, array('getName', 'getValue'));
        $element
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('myElement'));
        $element
            ->expects($this->once())
            ->method('getValue')
            ->will($this->returnValue('idcornholio'));
        $this->_object->addElement($element);

        $this->assertEquals($data, $this->_object->getValues());
    }

    /**
     * @covers Core_Form_Group_Abstract::getValues
     * @covers Core_Form_Group_Abstract::<protected>
     */
    public function testGetValuesWillSkipIgnoredElements()
    {
        $element1 = $this->getMockForAbstractClass('Core_Form_Element_Abstract', array(), '', true, true, true, array('getName', 'getValue'));
        $element1
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('myElement1'));
        $element1
            ->expects($this->once())
            ->method('getValue')
            ->will($this->returnValue('idcornholio'));
        $this->_object->addElement($element1);

        $element2 = $this->getMockForAbstractClass('Core_Form_Element_Abstract', array(), '', true, true, true, array('getName', 'getValue', 'isIgnored'));
        $element2
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('myElement2'));
        $element2
            ->expects($this->once())
            ->method('isIgnored')
            ->will($this->returnValue(true));
        $this->_object->addElement($element2);

        $this->assertEquals(array(
            'myElement1' => 'idcornholio'
        ), $this->_object->getValues());
    }

    /**
     * @covers Core_Form_Group_Abstract::getRawValues
     * @covers Core_Form_Group_Abstract::<protected>
     */
    public function testCanGetRawFormValues()
    {
        $data = array(
            'myGroup'   => array('a' => 1, 'b' => '2', 'c' => 'tri'),
            'myElement' => 'idcornholio',
        );
        $group = $this->getMockForAbstractClass('Core_Form_Group_Abstract', array(), '', true, true, true, array('getName', 'getRawValues'));
        $group
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('myGroup'));
        $group
            ->expects($this->once())
            ->method('getRawValues')
            ->will($this->returnValue(array('a' => 1, 'b' => '2', 'c' => 'tri')));
        $this->_object->addGroup($group);

        $element = $this->getMockForAbstractClass('Core_Form_Element_Abstract', array(), '', true, true, true, array('getName', 'getRawValue'));
        $element
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('myElement'));
        $element
            ->expects($this->once())
            ->method('getRawValue')
            ->will($this->returnValue('idcornholio'));
        $this->_object->addElement($element);

        $this->assertEquals($data, $this->_object->getRawValues());
    }


    /**
     * @covers Core_Form_Group_Abstract::getRawValues
     * @covers Core_Form_Group_Abstract::<protected>
     */
    public function testGetRawValuesWillSkipIgnoredElements()
    {
        $element1 = $this->getMockForAbstractClass('Core_Form_Element_Abstract', array(), '', true, true, true, array('getName', 'getRawValue'));
        $element1
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('myElement1'));
        $element1
            ->expects($this->once())
            ->method('getRawValue')
            ->will($this->returnValue('idcornholio'));
        $this->_object->addElement($element1);

        $element2 = $this->getMockForAbstractClass('Core_Form_Element_Abstract', array(), '', true, true, true, array('getName', 'getRawValue', 'isIgnored'));
        $element2
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('myElement2'));
        $element2
            ->expects($this->once())
            ->method('isIgnored')
            ->will($this->returnValue(true));
        $this->_object->addElement($element2);

        $this->assertEquals(array(
            'myElement1' => 'idcornholio'
        ), $this->_object->getRawValues());
    }

    /**
     * @covers Core_Form_Group_Abstract::isValid
     */
    public function testFormWithNoElementsOrGroupsIsConsideredValid()
    {
        $this->assertTrue($this->_object->isValid());
    }

    /**
     * @covers Core_Form_Group_Abstract::isValid
     */
    public function testIfAnAttachedElementIsInvalidTheFormIsInvalid()
    {
        $element = $this->getMockForAbstractClass('Core_Form_Element_Abstract', array(), '', true, true, true, array('getName', 'isValid', 'getError'));
        $element
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('myElement'));
        $element
            ->expects($this->once())
            ->method('isValid')
            ->will($this->returnValue(false));
        $element
            ->expects($this->once())
            ->method('getError')
            ->will($this->returnValue('Error'));
        $this->_object->addElement($element);

        $this->assertFalse($this->_object->isValid());
    }

    /**
     * @covers Core_Form_Group_Abstract::isValid
     */
    public function testWillValidateAllElementsEvenIfFirstOneInvalid()
    {
        $element1 = $this->getMockForAbstractClass('Core_Form_Element_Abstract', array(), '', true, true, true, array('getName', 'isValid'));
        $element1
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('myElement1'));
        $element1
            ->expects($this->once())
            ->method('isValid')
            ->will($this->returnValue(false));
        $this->_object->addElement($element1);

        $element2 = $this->getMockForAbstractClass('Core_Form_Element_Abstract', array(), '', true, true, true, array('getName', 'isValid'));
        $element2
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('myElement2'));
        $element2
            ->expects($this->once())
            ->method('isValid')
            ->will($this->returnValue(true));
        $this->_object->addElement($element2);

        $this->assertFalse($this->_object->isValid());
    }

    /**
     * @covers Core_Form_Group_Abstract::isValid
     */
    public function testIfAnAttachedGroupIsInvalidTheFormIsInvalid()
    {
        $group = $this->getMockForAbstractClass('Core_Form_Group_Abstract', array(), '', true, true, true, array('getName', 'isValid', 'getErrors'));
        $group
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('myGroup'));
        $group
            ->expects($this->once())
            ->method('isValid')
            ->will($this->returnValue(false));
        $group
            ->expects($this->once())
            ->method('getErrors')
            ->will($this->returnValue(array('a' => 'b', 'b' => 'c')));
        $this->_object->addGroup($group);

        $this->assertFalse($this->_object->isValid());
    }

    /**
     * @covers Core_Form_Group_Abstract::isValid
     * @covers Core_Form_Group_Abstract::<protected>
     */
    public function testWillValidateAllGroupsEvenIfFirstOneInvalid()
    {
        $group1 = $this->getMockForAbstractClass('Core_Form_Group_Abstract', array(), '', true, true, true, array('getName', 'isValid'));
        $group1
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('myGroup1'));
        $group1
            ->expects($this->once())
            ->method('isValid')
            ->will($this->returnValue(false));
        $this->_object->addGroup($group1);

        $group2 = $this->getMockForAbstractClass('Core_Form_Group_Abstract', array(), '', true, true, true, array('getName', 'isValid'));
        $group2
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('myGroup2'));
        $group2
            ->expects($this->once())
            ->method('isValid')
            ->will($this->returnValue(true));
        $this->_object->addGroup($group2);

        $this->assertFalse($this->_object->isValid());
    }

    /**
     * @covers Core_Form_Group_Abstract::isValid
     */
    public function testWillMergeErrorsFromGroupsMarkedWithEscalateErrors()
    {
        $group1 = $this->getMockForAbstractClass('Core_Form_Group_Abstract', array(), '', true, true, true, array('getName', 'isValid', 'getErrors', 'isEscalateErrors'));
        $group1
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('myGroup1'));
        $group1
            ->expects($this->once())
            ->method('isValid')
            ->will($this->returnValue(false));
        $group1
            ->expects($this->once())
            ->method('isEscalateErrors')
            ->will($this->returnValue(true));
        $group1
            ->expects($this->once())
            ->method('getErrors')
            ->will($this->returnValue(array('error1' => 'one', 'error2' => 'two')));
        $this->_object->addGroup($group1);

        $this->assertFalse($this->_object->isValid());
        $this->assertEquals(array('error1' => 'one', 'error2' => 'two'), $this->_object->getErrors());
    }

    /**
     * @covers Core_Form_Group_Abstract::getErrors
     * @covers Core_Form_Group_Abstract::<protected>
     */
    public function testCanGetErrors()
    {
        $group = $this->getMockForAbstractClass('Core_Form_Group_Abstract', array(), '', true, true, true, array('getName', 'isValid', 'getErrors'));
        $group
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('myGroup'));
        $group
            ->expects($this->once())
            ->method('isValid')
            ->will($this->returnValue(false));
        $group
            ->expects($this->once())
            ->method('getErrors')
            ->will($this->returnValue(array('myElement2' => 'Some other major error')));
        $this->_object->addGroup($group);

        $element = $this->getMockForAbstractClass('Core_Form_Element_Abstract', array(), '', true, true, true, array('getName', 'isValid', 'getError'));
        $element
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('myElement1'));
        $element
            ->expects($this->once())
            ->method('isValid')
            ->will($this->returnValue(false));
        $element
            ->expects($this->once())
            ->method('getError')
            ->will($this->returnValue('Some major error'));
        $this->_object->addElement($element);

        $errors = array(
            'myGroup' => array(
                'myElement2' => 'Some other major error',
            ),
            'myElement1' => 'Some major error',
        );

        $this->_object->isValid();

        $this->assertEquals($errors, $this->_object->getErrors());
    }

    /**
     * @covers Core_Form_Group_Abstract::setErrors
     * @covers Core_Form_Group_Abstract::hasErrors
     */
    public function testCanTestIfHasErrors()
    {
        $this->_object->setErrors(array('a'));

        $this->assertTrue($this->_object->hasErrors());
    }

    /**
     * @covers Core_Form_Group_Abstract::__clone
     */
    public function testWillClonePluginManagerWhileCloning()
    {
        $object = clone $this->_object;

        $this->assertNotSame($object->getPluginManager(), $this->_object->getPluginManager());
    }

    /**
     * @covers Core_Form_Group_Abstract::__clone
     */
    public function testWillResetPrototypeFlagWhenCloning()
    {
        $this->_object->setPrototype(true);
        $object = clone $this->_object;

        $this->assertFalse($object->isPrototype());
    }

    /**
     * @covers Core_Form_Group_Abstract::setView
     * @covers Core_Form_Group_Abstract::getView
     */
    public function testCanSetAndGetView()
    {
        $view = $this->getMock('Twig_Environment');
        $this->_object->setView($view);

        $this->assertEquals($view, $this->_object->getView());
    }

    /**
     * @covers Core_Form_Group_Abstract::getView
     */
    public function testIfViewNotSetItWillFetchItFromApplicationAsView()
    {
        $view       = $this->getMock('Twig_Environment');
        $container  = $this->_mockContainer('View', $view);
        Core_Application::getInstance()->setContainer($container);

        $this->assertEquals($view, $this->_object->getView());
    }

    /**
     * @covers Core_Form_Group_Abstract::setMacro
     * @covers Core_Form_Group_Abstract::getMacro
     */
    public function testCanSetAndGetMacro()
    {
        $this->_object->setMacro('macro_custom');

        $this->assertEquals('macro_custom', $this->_object->getMacro());
    }

    /**
     * @covers Core_Form_Group_Abstract::set
     * @covers Core_Form_Group_Abstract::get
     */
    public function testCanGetAndSetProperty()
    {
        $this->_object->set('name', 'foo');

        $this->assertEquals('foo', $this->_object->get('name'));
    }

    /**
     * @covers Core_Form_Group_Abstract::get
     */
    public function testGettingAnUnknownPropertyWillThrowAnInvalidArgumentException()
    {
        $this->setExpectedException('InvalidArgumentException');

        $this->_object->get('no-such');
    }

    /**
     * @covers Core_Form_Group_Abstract::get
     */
    public function testCanGetChildGroupViaGet()
    {
        $group = $this->getMockForAbstractClass('Core_Form_Group_Abstract', array(), '', true, true, true, array('getName'));
        $group
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('myGroup'));;
        $this->_object->addGroup($group);

        $this->assertEquals($group, $this->_object->get('myGroup'));
    }

    /**
     * @covers Core_Form_Group_Abstract::get
     */
    public function testCanGetChildElementViaGet()
    {
        $element = $this->getMockForAbstractClass('Core_Form_Element_Abstract', array(), '', true, true, true, array('getName'));
        $element
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('myElement'));
        $this->_object->addElement($element);

        $this->assertEquals($element, $this->_object->get('myElement'));
    }

    /**
     * @covers Core_Form_Group_Abstract::get
     */
    public function testCanGetRootViaGet()
    {
        $parent = $this->getMock('Core_Form', array('getRoot'));
        $parent
            ->expects($this->once())
            ->method('getRoot')
            ->will($this->returnValue($this));
        $this->_object->setOwner($parent);

        $this->assertEquals($this, $this->_object->get('/'));
    }

    /**
     * @covers Core_Form_Group_Abstract::get
     */
    public function testCanMakeAbsoluteGetRequest()
    {
        $root   = $this->getMock('Core_Form', array(), array(), '', false);
        $root
            ->expects($this->once())
            ->method('get')
            ->with($this->equalTo('foo/bar'))
            ->will($this->returnValue('barValue'));

        $parent = $this->getMock('Core_Form', array('getRoot'));
        $parent
            ->expects($this->once())
            ->method('getRoot')
            ->will($this->returnValue($root));
        $this->_object->setOwner($parent);

        $this->assertEquals('barValue', $this->_object->get('/foo/bar'));
    }

    /**
     * @covers Core_Form_Group_Abstract::get
     */
    public function testCanMakeRelativeGetRequest()
    {
        $element = $this->getMockForAbstractClass('Core_Form_Element_Abstract', array(), '', true, true, true, array('getName', 'get'));
        $element
            ->expects($this->any())
            ->method('getName')
            ->will($this->returnValue('myElement'));
        $element
            ->expects($this->once())
            ->method('get')
            ->with($this->equalTo('foo/bar'))
            ->will($this->returnValue('barValue'));
        $this->_object->addElement($element);

        $this->assertEquals('barValue', $this->_object->get('myElement/foo/bar'));
    }

    /**
     * @covers Core_Form_Group_Abstract::__set
     * @covers Core_Form_Group_Abstract::__get
     */
    public function testCanGetAndSetPropertyViaMagicMethods()
    {
        $this->_object->name = 'foo';

        $this->assertEquals('foo', $this->_object->name);
    }

    /**
     * @covers Core_Form_Group_Abstract::setTemplate
     * @covers Core_Form_Group_Abstract::getTemplate
     */
    public function testSettingTemplateWillWrapItInTwigTemplateStatement()
    {
        $this->_object
            ->setMacro('foo')
            ->setTemplate('my.tpl');
        $wrapper = '{% import "my.tpl" as macro_form %} {{ macro_form.foo(this, context) }}';
        $this->assertEquals($wrapper, $this->_object->getTemplate());
    }

    /**
     * @covers Core_Form_Group_Abstract::getTemplate
     */
    public function testWillExtractMacroParamsWhenCallingMacro()
    {
        $this->_object
            ->setMacro('foo("foo", "bar")')
            ->setTemplate('my.tpl');
        $wrapper = '{% import "my.tpl" as macro_form %} {{ macro_form.foo(this, context, "foo", "bar") }}';
        $this->assertEquals($wrapper, $this->_object->getTemplate());
    }

    /**
     * @covers Core_Form_Group_Abstract::getTemplate
     */
    public function testDefaultTemplateForDefaultContextIsSet()
    {
        $this->_object
            ->setContext(Core_Form::CONTEXT_DEFAULT)
            ->setMacro('macro');
        $wrapper = '{% import "Core/Macro/Form.tpl" as macro_form %} {{ macro_form.macro(this, context) }}';
        $this->assertEquals($wrapper, $this->_object->getTemplate());
    }


    /**
     * @covers Core_Form_Group_Abstract::render
     */
    public function testCanRender()
    {
        $wrapper = '{% import "Core/Macro/Form.tpl" as macro_form %} {{ macro_form.foo(this, context) }}';
        $view    = $this->getMockForAbstractClass('Twig_Environment', array(), '', true, true, true, array('render'));
        $view
            ->expects($this->once())
            ->method('render')
            ->with($this->equalTo($wrapper), $this->equalTo(array('this' => $this->_object, 'context' => Core_Form::CONTEXT_DEFAULT)))
            ->will($this->returnValue('<rendered/>'));
        $this->_object
            ->setMacro('foo')
            ->setView($view);

        $this->assertEquals('<rendered/>', $this->_object->render(Core_Form::CONTEXT_DEFAULT));
    }

    /**
     * @covers Core_Form_Group_Abstract::__toString
     */
    public function testCastingAnObjectToStringWillRender()
    {
        $wrapper = '{% import "Core/Macro/Form.tpl" as macro_form %} {{ macro_form.foo(this, context) }}';

        $view = $this->getMock('Twig_Environment', array('render'));
        $view
            ->expects($this->once())
            ->method('render')
            ->with($this->equalTo($wrapper), $this->equalTo(array('this' => $this->_object, 'context' => Core_Form::CONTEXT_DEFAULT)))
            ->will($this->returnValue('<rendered/>'));
        $this->_object
            ->setMacro('foo')
            ->setView($view);

        $this->assertEquals('<rendered/>', (string) $this->_object);
    }

    /**
     * @covers Core_Form_Group_Abstract::__toString
     */
    public function testAnyExceptionRaisedDuringRenderingWillBeThrownAsAnUserError()
    {
        $view = $this->getMock('Twig_Environment', array('render'));
        $view
            ->expects($this->once())
            ->method('render')
            ->will($this->throwException(new Exception));
        $this->_object->setView($view);

        set_error_handler(array($this, 'handleErrors'));
        $rendered = (string) $this->_object;
        restore_error_handler();

        $this->assertEmpty($rendered);
        $this->assertEquals(0, strpos($this->_error, 'Exception "Exception" while rendering form group'));
    }

    public function handleErrors($errno, $errstr)
    {
        if ($errno !== E_USER_ERROR) {
            throw new Exception($errstr);
        } else {
            $this->_error = $errstr;
        }
    }
    
    /**
     * @covers Core_Form_Group_Abstract::setIgnored
     * @covers Core_Form_Group_Abstract::isIgnored
     */
    public function testCanSetAndGetIgnored()
    {
        $this->_object->setIgnored(true);

        $this->assertTrue($this->_object->isIgnored());
    }

    /**
     * @covers Core_Form_Group_Abstract::isIgnored
     */
    public function testIsNotIgnoredByDefault()
    {
        $this->assertFalse($this->_object->isIgnored());
    }
    
    /**
     * @covers Core_Form_Group_Abstract::setEscalateErrors
     * @covers Core_Form_Group_Abstract::isEscalateErrors
     */
    public function testCanSetAndGetEscalateErrors()
    {
        $this->_object->setEscalateErrors(true);

        $this->assertTrue($this->_object->isEscalateErrors());
    }

    /**
     * @covers Core_Form_Group_Abstract::isIgnored
     */
    public function testErrorsAreNotEscalatedByDefault()
    {
        $this->assertFalse($this->_object->isEscalateErrors());
    }
}

class Invalid_Form_Group_Invalid extends Core_Form_Group_Abstract
{
    protected $_macro = 'nope';

    protected $_defaultAttribs = array(
        'randomContext' => array(),
    );

    protected $_mandatoryAttribs = array(
        'randomContext' => array('name', 'id' => 'fullyQualifiedId', 'mojMakro' => 'macro'),
    );
}