1<?php 2/* Icinga Web 2 | (c) 2013 Icinga Development Team | GPLv2+ */ 3 4namespace Tests\Icinga\Web; 5 6use Mockery; 7use Icinga\Web\Form; 8use Icinga\Web\Request; 9use Icinga\Test\BaseTestCase; 10 11class PostRequest extends Request 12{ 13 public function getMethod() 14 { 15 return 'POST'; 16 } 17} 18 19class SuccessfulForm extends Form 20{ 21 public function onSuccess() 22 { 23 return true; 24 } 25} 26 27class FormTest extends BaseTestCase 28{ 29 public function tearDown(): void 30 { 31 Mockery::close(); // Necessary as some tests are running isolated 32 } 33 34 public function testWhetherASubmitButtonIsAddedWithASubmitLabelBeingSet() 35 { 36 $form = new Form(); 37 $form->setTokenDisabled(); 38 $form->setSubmitLabel('test'); 39 $form->create(); 40 41 $this->assertInstanceOf( 42 '\Zend_Form_Element', 43 $form->getElement('btn_submit'), 44 'Form::create() does not add a submit button in case a submit label is set' 45 ); 46 } 47 48 public function testWhetherNoSubmitButtonIsAddedWithoutASubmitLabelBeingSet() 49 { 50 $form = new Form(); 51 $form->setTokenDisabled(); 52 $form->create(); 53 54 $this->assertNull( 55 $form->getElement('btn_submit'), 56 'Form::create() adds a submit button in case no submit label is set' 57 ); 58 } 59 60 /** 61 * @depends testWhetherASubmitButtonIsAddedWithASubmitLabelBeingSet 62 */ 63 public function testWhetherIsSubmittedReturnsTrueWithASubmitLabelBeingSet() 64 { 65 $form = new Form(); 66 $form->setTokenDisabled(); 67 $form->setSubmitLabel('test'); 68 $form->populate(array('btn_submit' => true)); 69 $form->setRequest(new PostRequest()); 70 71 $this->assertTrue( 72 $form->isSubmitted(), 73 'Form::isSubmitted() does not return true in case a submit label is set' 74 ); 75 } 76 77 /** 78 * @depends testWhetherNoSubmitButtonIsAddedWithoutASubmitLabelBeingSet 79 */ 80 public function testWhetherIsSubmittedReturnsFalseWithoutASubmitLabelBeingSet() 81 { 82 $form = new Form(); 83 84 $this->assertFalse( 85 $form->isSubmitted(), 86 'Form::isSubmitted() does not return false in case no submit label is set' 87 ); 88 } 89 90 public function testWhetherTheCurrentLocationIsUsedAsDefaultRedirection() 91 { 92 $this->getRequestMock()->shouldReceive('getPathInfo')->andReturn('default/route'); 93 $this->getResponseMock()->shouldReceive('redirectAndExit')->atLeast()->once() 94 ->with(Mockery::on(function ($url) { 95 return $url->getRelativeUrl() === 'default/route'; 96 })); 97 98 $form = new SuccessfulForm(); 99 $form->setTokenDisabled(); 100 $form->setUidDisabled(); 101 $form->handleRequest(); 102 } 103 104 public function testWhetherAnExplicitlySetRedirectUrlIsUsedForRedirection() 105 { 106 $this->getResponseMock()->shouldReceive('redirectAndExit')->atLeast()->once() 107 ->with(Mockery::on(function ($url) { 108 return $url->getRelativeUrl() === 'special/route'; 109 })); 110 111 $form = new SuccessfulForm(); 112 $form->setTokenDisabled(); 113 $form->setUidDisabled(); 114 $form->setRedirectUrl('special/route'); 115 $form->handleRequest(); 116 } 117 118 /** 119 * @runInSeparateProcess 120 */ 121 public function testWhetherACsrfCounterMeasureIsBeingAdded() 122 { 123 Mockery::mock('alias:Icinga\Web\Session')->shouldReceive('getSession->getId')->andReturn('1234567890'); 124 125 $form = new Form(); 126 $form->create(); 127 128 $this->assertInstanceOf( 129 '\Zend_Form_Element', 130 $form->getElement($form->getTokenElementName()), 131 'Form::create() does not add a csrf counter measure element' 132 ); 133 } 134 135 public function testWhetherACsrfCounterMeasureIsNotBeingAdded() 136 { 137 $form = new Form(); 138 $form->setTokenDisabled(); 139 $form->create(); 140 141 $this->assertNull( 142 $form->getElement($form->getTokenElementName()), 143 'Form::create() adds a csrf counter measure element in case it\'s disabled' 144 ); 145 } 146 147 public function testWhetherAUniqueFormIdIsBeingAdded() 148 { 149 $form = new Form(); 150 $form->setTokenDisabled(); 151 $form->create(); 152 153 $this->assertInstanceOf( 154 '\Zend_Form_Element', 155 $form->getElement($form->getUidElementName()), 156 'Form::create() does not add a form identification element' 157 ); 158 } 159 160 public function testWhetherAUniqueFormIdIsNotBeingAdded() 161 { 162 $form = new Form(); 163 $form->setTokenDisabled(); 164 $form->setUidDisabled(); 165 $form->create(); 166 167 $this->assertNull( 168 $form->getElement($form->getUidElementName()), 169 'Form::create() adds a form identification element in case it\'s disabled' 170 ); 171 } 172 173 /** 174 * @depends testWhetherAUniqueFormIdIsBeingAdded 175 */ 176 public function testWhetherAFormIsSentWithAUniqueFormIdBeingAdded() 177 { 178 $form = new Form(); 179 $form->setTokenDisabled(); 180 $form->create(); 181 182 $this->assertTrue( 183 $form->wasSent( 184 array( 185 $form->getUidElementName() => $form->getElement($form->getUidElementName())->getValue() 186 ) 187 ), 188 'Form::wasSent() does not return true in case a the form identification value is being sent' 189 ); 190 } 191 192 /** 193 * @depends testWhetherAUniqueFormIdIsNotBeingAdded 194 */ 195 public function testWhetherAFormIsNotSentWithoutAUniqueFormIdBeingAdded() 196 { 197 $form = new Form(); 198 $form->setTokenDisabled(); 199 $form->setUidDisabled(); 200 $form->create(); 201 202 $this->assertFalse( 203 $form->wasSent(array()), 204 'Form::wasSent() does not return false in case no form identification element was added' 205 ); 206 } 207 208 public function testWhetherADefaultActionIsBeingSetOnFormCreation() 209 { 210 $this->getRequestMock()->shouldReceive('getPathInfo')->andReturn('some/route'); 211 212 $form = new Form(); 213 $form->setTokenDisabled(); 214 $form->create(); 215 216 $this->assertEquals( 217 '/some/route', 218 $form->getAction(), 219 'Form::create() does not set a default action if none was set explicitly' 220 ); 221 } 222 223 /** 224 * @depends testWhetherAUniqueFormIdIsBeingAdded 225 * @depends testWhetherASubmitButtonIsAddedWithASubmitLabelBeingSet 226 */ 227 public function testWhetherItIsPossibleToRecreateAForm() 228 { 229 $form = new Form(); 230 $form->setTokenDisabled(); 231 $form->setSubmitLabel('test'); 232 $form->create(); // sets the flag $this->created to true 233 $form->clearElements(); // should reset the flag.. 234 $form->create(); // ..so that we can recreate the form 235 236 $this->assertCount( 237 2, 238 $form->getElements(), 239 'Form::clearElements() does not fully reset the form' 240 ); 241 } 242 243 public function testWhetherGetNameReturnsTheEscapedClassNameByDefault() 244 { 245 $form = new Form(); 246 247 $this->assertEquals( 248 $form->filterName(get_class($form)), 249 $form->getName(), 250 'Form::getName() does not return the escaped class name in case no name was explicitly set' 251 ); 252 } 253 254 public function testWhetherTheOnSuccessOptionMustBeCallable() 255 { 256 $this->expectException(\Icinga\Exception\ProgrammingError::class); 257 258 new Form(array('onSuccess' => '_invalid_')); 259 } 260 261 /** 262 * @depends testWhetherACsrfCounterMeasureIsNotBeingAdded 263 * @depends testWhetherAUniqueFormIdIsNotBeingAdded 264 * @depends testWhetherNoSubmitButtonIsAddedWithoutASubmitLabelBeingSet 265 */ 266 public function testWhetherAClosureCanBePassedAsOnSuccessCallback() 267 { 268 $request = new Request(); 269 $form = new Form(array( 270 'onSuccess' => function ($form) { 271 $form->getRequest()->setParam('test', 'tset'); 272 return false; 273 } 274 )); 275 $form->setTokenDisabled(); 276 $form->setUidDisabled(); 277 $form->handleRequest($request); 278 279 $this->assertEquals( 280 'tset', 281 $request->getParam('test'), 282 'Form does not utilize the onSuccess callback set with form options on instantiation' 283 ); 284 } 285} 286