SessionTest.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. <?php
  2. /**
  3. * Tests the session class
  4. *
  5. * @group kohana
  6. * @group kohana.core
  7. * @group kohana.core.session
  8. *
  9. * @package Kohana
  10. * @category Tests
  11. * @author Kohana Team
  12. * @author Jeremy Bush <contractfrombelow@gmail.com>
  13. * @copyright (c) Kohana Team
  14. * @license https://koseven.ga/LICENSE.md
  15. */
  16. class Kohana_SessionTest extends Unittest_TestCase
  17. {
  18. /**
  19. * Gets a mock of the session class
  20. *
  21. * @return Session
  22. */
  23. // @codingStandardsIgnoreStart
  24. public function getMockSession(array $config = [])
  25. // @codingStandardsIgnoreEnd
  26. {
  27. return $this->getMockForAbstractClass('Session', [$config]);
  28. }
  29. /**
  30. * Provides test data for
  31. *
  32. * test_constructor_uses_name_from_config_and_casts()
  33. *
  34. * @return array
  35. */
  36. public function provider_constructor_uses_settings_from_config_and_casts()
  37. {
  38. return [
  39. // array(expected, input)
  40. // data set 0
  41. [
  42. [
  43. 'name' => 'awesomeness',
  44. 'lifetime' => 1231456421,
  45. 'encrypted' => FALSE
  46. ],
  47. [
  48. 'name' => 'awesomeness',
  49. 'lifetime' => '1231456421',
  50. 'encrypted' => FALSE,
  51. ],
  52. ],
  53. // data set 1
  54. [
  55. [
  56. 'name' => '123',
  57. 'encrypted' => 'default',
  58. ],
  59. [
  60. 'name' => 123,
  61. 'encrypted' => TRUE,
  62. ],
  63. ],
  64. ];
  65. }
  66. /**
  67. * The constructor should change its attributes based on config
  68. * passed as the first parameter
  69. *
  70. * @test
  71. * @dataProvider provider_constructor_uses_settings_from_config_and_casts
  72. * @covers Session::__construct
  73. */
  74. public function test_constructor_uses_settings_from_config_and_casts($expected, $config)
  75. {
  76. $session = $this->getMockForAbstractClass('Session', [$config]);
  77. foreach ($expected as $var => $value)
  78. {
  79. $this->assertAttributeSame($value, '_'.$var, $session);
  80. }
  81. }
  82. /**
  83. * Check that the constructor will load a session if it's provided
  84. * witha session id
  85. *
  86. * @test
  87. * @covers Session::__construct
  88. * @covers Session::read
  89. */
  90. public function test_constructor_loads_session_with_session_id()
  91. {
  92. $config = [];
  93. $session_id = 'lolums';
  94. // Don't auto-call constructor, we need to setup the mock first
  95. $session = $this->getMockBuilder('Session')
  96. ->disableOriginalConstructor()
  97. ->setMethods(['read'])
  98. ->getMockForAbstractClass();
  99. $session
  100. ->expects($this->once())
  101. ->method('read')
  102. ->with($session_id);
  103. $session->__construct($config, $session_id);
  104. }
  105. /**
  106. * Calling $session->bind() should allow you to bind a variable
  107. * to a session variable
  108. *
  109. * @test
  110. * @covers Session::bind
  111. * @ticket 3164
  112. */
  113. public function test_bind_actually_binds_variable()
  114. {
  115. $session = $this->getMockForAbstractClass('Session');
  116. $var = 'asd';
  117. $session->bind('our_var', $var);
  118. $var = 'foobar';
  119. $this->assertSame('foobar', $session->get('our_var'));
  120. }
  121. /**
  122. * When a session is initially created it should have no data
  123. *
  124. *
  125. * @test
  126. * @covers Session::__construct
  127. * @covers Session::set
  128. */
  129. public function test_initially_session_has_no_data()
  130. {
  131. $session = $this->getMockSession();
  132. $this->assertAttributeSame([], '_data', $session);
  133. }
  134. /**
  135. * Make sure that the default session name (the one used if the
  136. * driver does not set one) is 'session'
  137. *
  138. * @test
  139. * @covers Session::__construct
  140. */
  141. public function test_default_session_name_is_set()
  142. {
  143. $session = $this->getMockSession();
  144. $this->assertAttributeSame('session', '_name', $session);
  145. }
  146. /**
  147. * By default sessions are unencrypted
  148. *
  149. * @test
  150. * @covers Session::__construct
  151. */
  152. public function test_default_session_is_unencrypted()
  153. {
  154. $session = $this->getMockSession();
  155. $this->assertAttributeSame(FALSE, '_encrypted', $session);
  156. }
  157. /**
  158. * A new session should not be classed as destroyed
  159. *
  160. * @test
  161. * @covers Session::__construct
  162. */
  163. public function test_default_session_is_not_classed_as_destroyed()
  164. {
  165. $session = $this->getMockSession();
  166. $this->assertAttributeSame(FALSE, '_destroyed', $session);
  167. }
  168. /**
  169. * Provides test data for test_get_returns_default_if_var_dnx()
  170. *
  171. * @return array
  172. */
  173. public function provider_get_returns_default_if_var_dnx()
  174. {
  175. return [
  176. ['something_crazy', FALSE],
  177. ['a_true', TRUE],
  178. ['an_int', 158163158],
  179. ];
  180. }
  181. /**
  182. * Make sure that get() is using the default value we provide and
  183. * isn't tampering with it
  184. *
  185. * @test
  186. * @dataProvider provider_get_returns_default_if_var_dnx
  187. * @covers Session::get
  188. */
  189. public function test_get_returns_default_if_var_dnx($var, $default)
  190. {
  191. $session = $this->getMockSession();
  192. $this->assertSame($default, $session->get($var, $default));
  193. }
  194. /**
  195. * By default get() should be using null as the var DNX return value
  196. *
  197. * @test
  198. * @covers Session::get
  199. */
  200. public function test_get_uses_null_as_default_return_value()
  201. {
  202. $session = $this->getMockSession();
  203. $this->assertSame(NULL, $session->get('level_of_cool'));
  204. }
  205. /**
  206. * This test makes sure that session is using array_key_exists
  207. * as isset will return FALSE if the value is NULL
  208. *
  209. * @test
  210. * @covers Session::get
  211. */
  212. public function test_get_returns_value_if_it_equals_null()
  213. {
  214. $session = $this->getMockSession();
  215. $session->set('arkward', NULL);
  216. $this->assertSame(NULL, $session->get('arkward', 'uh oh'));
  217. }
  218. /**
  219. * as_array() should return the session data by reference.
  220. *
  221. * i.e. if we modify the returned data, the session data also changes
  222. *
  223. * @test
  224. * @covers Session::as_array
  225. */
  226. public function test_as_array_returns_data_by_ref_or_copy()
  227. {
  228. $session = $this->getMockSession();
  229. $data_ref =& $session->as_array();
  230. $data_ref['something'] = 'pie';
  231. $this->assertAttributeSame($data_ref, '_data', $session);
  232. $data_copy = $session->as_array();
  233. $data_copy['pie'] = 'awesome';
  234. $this->assertAttributeNotSame($data_copy, '_data', $session);
  235. }
  236. /**
  237. * set() should add new session data and modify existing ones
  238. *
  239. * Also makes sure that set() returns $this
  240. *
  241. * @test
  242. * @covers Session::set
  243. */
  244. public function test_set_adds_and_modifies_to_session_data()
  245. {
  246. $session = $this->getMockSession();
  247. $this->assertSame($session, $session->set('pork', 'pie'));
  248. $this->assertAttributeSame(
  249. ['pork' => 'pie'],
  250. '_data',
  251. $session
  252. );
  253. $session->set('pork', 'delicious');
  254. $this->assertAttributeSame(
  255. ['pork' => 'delicious'],
  256. '_data',
  257. $session
  258. );
  259. }
  260. /**
  261. * This tests that delete() removes specified session data
  262. *
  263. * @test
  264. * @covers Session::delete
  265. */
  266. public function test_delete_removes_select_session_data()
  267. {
  268. $session = $this->getMockSession();
  269. // Bit of a hack for mass-loading session data
  270. $data =& $session->as_array();
  271. $data += [
  272. 'a' => 'A',
  273. 'b' => 'B',
  274. 'c' => 'C',
  275. 'easy' => '123'
  276. ];
  277. // Make a copy of $data for testing purposes
  278. $copy = $data;
  279. // First we make sure we can delete one item
  280. // Also, check that delete returns $this
  281. $this->assertSame($session, $session->delete('a'));
  282. unset($copy['a']);
  283. // We could test against $data but then we'd be testing
  284. // that as_array() is returning by ref
  285. $this->assertAttributeSame($copy, '_data', $session);
  286. // Now we make sure we can delete multiple items
  287. // We're checking $this is returned just in case
  288. $this->assertSame($session, $session->delete('b', 'c'));
  289. unset($copy['b'], $copy['c']);
  290. $this->assertAttributeSame($copy, '_data', $session);
  291. }
  292. /**
  293. * Provides test data for test_read_loads_session_data()
  294. *
  295. * @return array
  296. */
  297. public function provider_read_loads_session_data()
  298. {
  299. return [
  300. // If driver returns array then just load it up
  301. [
  302. [],
  303. 'wacka_wacka',
  304. []
  305. ],
  306. [
  307. ['the it' => 'crowd'],
  308. 'the_it_crowd',
  309. ['the it' => 'crowd'],
  310. ],
  311. // If it's a string an encrpytion is disabled (by default) base64decode and unserialize
  312. [
  313. ['dead' => 'arrival'],
  314. 'lolums',
  315. 'YToxOntzOjQ6ImRlYWQiO3M6NzoiYXJyaXZhbCI7fQ=='
  316. ],
  317. ];
  318. }
  319. /**
  320. * This is one of the "big" tests for the session lib
  321. *
  322. * The test makes sure that
  323. *
  324. * 1. Session asks the driver for the data relating to $session_id
  325. * 2. That it will load the returned data into the session
  326. *
  327. * @test
  328. * @dataProvider provider_read_loads_session_data
  329. * @covers Session::read
  330. */
  331. public function test_read_loads_session_data($expected_data, $session_id, $driver_data, array $config = [])
  332. {
  333. $session = $this->getMockSession($config);
  334. $session->expects($this->once())
  335. ->method('_read')
  336. ->with($session_id)
  337. ->will($this->returnValue($driver_data));
  338. $session->read($session_id);
  339. $this->assertAttributeSame($expected_data, '_data', $session);
  340. }
  341. /**
  342. * regenerate() should tell the driver to regenerate its id
  343. *
  344. * @test
  345. * @covers Session::regenerate
  346. */
  347. public function test_regenerate_tells_driver_to_regenerate()
  348. {
  349. $session = $this->getMockSession();
  350. $new_session_id = 'asdnoawdnoainf';
  351. $session->expects($this->once())
  352. ->method('_regenerate')
  353. ->with()
  354. ->will($this->returnValue($new_session_id));
  355. $this->assertSame($new_session_id, $session->regenerate());
  356. }
  357. /**
  358. * If the driver destroys the session then all session data should be
  359. * removed
  360. *
  361. * @test
  362. * @covers Session::destroy
  363. */
  364. public function test_destroy_deletes_data_if_driver_destroys_session()
  365. {
  366. $session = $this->getMockSession();
  367. $session
  368. ->set('asd', 'dsa')
  369. ->set('dog', 'god');
  370. $session
  371. ->expects($this->once())
  372. ->method('_destroy')
  373. ->with()
  374. ->will($this->returnValue(TRUE));
  375. $this->assertTrue($session->destroy());
  376. $this->assertAttributeSame([], '_data', $session);
  377. }
  378. /**
  379. * The session data should only be deleted if the driver reports
  380. * that the session was destroyed ok
  381. *
  382. * @test
  383. * @covers Session::destroy
  384. */
  385. public function test_destroy_only_deletes_data_if_driver_destroys_session()
  386. {
  387. $session = $this->getMockSession();
  388. $session
  389. ->set('asd', 'dsa')
  390. ->set('dog', 'god');
  391. $session
  392. ->expects($this->once())
  393. ->method('_destroy')
  394. ->with()
  395. ->will($this->returnValue(FALSE));
  396. $this->assertFalse($session->destroy());
  397. $this->assertAttributeSame(
  398. ['asd' => 'dsa', 'dog' => 'god'],
  399. '_data',
  400. $session
  401. );
  402. }
  403. /**
  404. * If a session variable exists then get_once should get it then remove it.
  405. * If the variable does not exist then it should return the default
  406. *
  407. * @test
  408. * @covers Session::get_once
  409. */
  410. public function test_get_once_gets_once_or_returns_default()
  411. {
  412. $session = $this->getMockSession();
  413. $session->set('foo', 'bar');
  414. // Test that a default is returned
  415. $this->assertSame('mud', $session->get_once('fud', 'mud'));
  416. // Now test that it actually removes the value
  417. $this->assertSame('bar', $session->get_once('foo'));
  418. $this->assertAttributeSame([], '_data', $session);
  419. $this->assertSame('maybe', $session->get_once('foo', 'maybe'));
  420. }
  421. }