ConfigTest.php 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. <?php
  2. /**
  3. * Tests the Config lib that's shipped with ko7
  4. *
  5. * @group ko7
  6. * @group ko7.core
  7. * @group ko7.core.config
  8. *
  9. * @package KO7
  10. * @category Tests
  11. *
  12. * @author Jeremy Bush <contractfrombelow@gmail.com>
  13. * @author Matt Button <matthew@sigswitch.com>
  14. * @copyright (c) 2007-2016 Kohana Team
  15. * @copyright (c) since 2016 Koseven Team
  16. * @license https://koseven.dev/LICENSE
  17. */
  18. class KO7_ConfigTest extends Unittest_TestCase
  19. {
  20. /**
  21. * When a config object is initially created there should be
  22. * no readers attached
  23. *
  24. * @covers Config
  25. */
  26. public function test_initially_there_are_no_sources()
  27. {
  28. $this->expectException(KO7_Exception::class);
  29. $this->expectExceptionMessage('No configuration sources attached');
  30. $config = new Config;
  31. $config->load('invalid');
  32. }
  33. /**
  34. * Test that calling attach() on a ko7 config object
  35. * adds the specified reader to the config object
  36. *
  37. * @covers Config::attach
  38. */
  39. public function test_attach_adds_reader_and_returns_this()
  40. {
  41. $config = new Config;
  42. $reader = $this->createMock('KO7_Config_Reader');
  43. $this->assertSame($config, $config->attach($reader));
  44. $this->expectException(KO7_Exception::class);
  45. $this->expectExceptionMessage('Need to specify a config group');
  46. $config->load(NULL);
  47. }
  48. /**
  49. * Calling detach() on a config object should remove it from the queue of readers
  50. *
  51. * @test
  52. * @covers Config::detach
  53. */
  54. public function test_detach_removes_reader_and_returns_this()
  55. {
  56. $config = new Config;
  57. // Due to the way phpunit mock generator works if you try and mock a class
  58. // that has already been used then it just re-uses the first's name
  59. // To get around this we have to specify a totally random name for the second mock object
  60. $reader1 = $this->createMock('KO7_Config_Reader');
  61. $reader2 = $this->createMock('KO7_Config_Reader', [], [], 'MY_AWESOME_READER');
  62. $config->attach($reader1);
  63. $config->attach($reader2);
  64. $this->assertSame($config, $config->detach($reader2));
  65. $this->assertSame($config, $config->detach($reader1));
  66. $this->expectException(KO7_Exception::class);
  67. $this->expectExceptionMessage('No configuration sources attached');
  68. $config->load('invalid');
  69. }
  70. /**
  71. * detach() should return $this even if the specified reader does not exist
  72. *
  73. * @test
  74. * @covers Config::detach
  75. */
  76. public function test_detach_returns_this_even_when_reader_dnx()
  77. {
  78. $config = new Config;
  79. $reader = $this->createMock('KO7_Config_Reader');
  80. $this->assertSame($config, $config->detach($reader));
  81. }
  82. /**
  83. * If we request a config variable with a dot path then
  84. * Config::load() should load the group and return the requested variable
  85. *
  86. * @test
  87. * @covers Config::load
  88. */
  89. public function test_load_can_get_var_from_dot_path()
  90. {
  91. $config = new Config;
  92. $reader = $this->createMock('KO7_Config_Reader', ['load']);
  93. $reader
  94. ->expects($this->once())
  95. ->method('load')
  96. ->with('beer')
  97. ->will($this->returnValue(['stout' => 'Guinness']));
  98. $config->attach($reader);
  99. $this->assertSame('Guinness', $config->load('beer.stout'));
  100. }
  101. /**
  102. * If we've already loaded a config group then the correct variable
  103. * should be returned if we use the dot path notation to to request
  104. * a var
  105. *
  106. * @test
  107. * @covers Config::load
  108. */
  109. public function test_load_can_get_var_from_dot_path_for_loaded_group()
  110. {
  111. $config = new Config;
  112. $reader = $this->createMock('KO7_Config_Reader', ['load']);
  113. $reader
  114. ->expects($this->once())
  115. ->method('load')
  116. ->with('beer')
  117. ->will($this->returnValue(['stout' => 'Guinness']));
  118. $config->attach($reader);
  119. $config->load('beer');
  120. $this->assertSame('Guinness', $config->load('beer.stout'));
  121. }
  122. /**
  123. * If load() is called and there are no readers present then it should throw
  124. * a ko7 exception
  125. *
  126. * @covers Config::load
  127. */
  128. public function test_load_throws_exception_if_there_are_no_sources()
  129. {
  130. $this->expectException(KO7_Exception::class);
  131. // The following code should throw an exception and phpunit will catch / handle it
  132. $config = new KO7_config;
  133. $config->load('random');
  134. }
  135. /**
  136. * Provides test data for test_load_throws_exception_if_no_group_is_given()
  137. *
  138. * @return array
  139. */
  140. public function provider_load_throws_exception_if_no_group_is_given()
  141. {
  142. return [
  143. [NULL],
  144. [''],
  145. [[]],
  146. [['foo' => 'bar']],
  147. [new StdClass],
  148. ];
  149. }
  150. /**
  151. * If an invalid group name is specified then an exception should be thrown.
  152. *
  153. * Invalid means it's either a non-string value, or empty
  154. *
  155. * @dataProvider provider_load_throws_exception_if_no_group_is_given
  156. * @covers Config::load
  157. */
  158. public function test_load_throws_exception_if_invalid_group($value)
  159. {
  160. $this->expectException(KO7_Exception::class);
  161. $config = new KO7_Config;
  162. $reader = $this->createMock('KO7_Config_Reader');
  163. $config->attach($reader);
  164. $config->load($value);
  165. }
  166. /**
  167. * Make sure that _write_config() passes the changed configuration to all
  168. * writers in the queue
  169. *
  170. * @test
  171. * @covers KO7_Config
  172. */
  173. public function test_write_config_passes_changed_config_to_all_writers()
  174. {
  175. $config = new KO7_Config;
  176. $reader1 = $this->createMock('KO7_Config_Reader');
  177. $writer1 = $this->createMock('KO7_Config_Writer', ['write']);
  178. $writer2 = $this->createMock('KO7_Config_Writer', ['write']);
  179. $writer1
  180. ->expects($this->once())
  181. ->method('write')
  182. ->with('some_group', 'key', 'value');
  183. $writer2
  184. ->expects($this->once())
  185. ->method('write')
  186. ->with('some_group', 'key', 'value');
  187. $config->attach($reader1)->attach($writer1)->attach($writer2);
  188. $config->_write_config('some_group', 'key', 'value');
  189. }
  190. /**
  191. * Config sources are stored in a stack, make sure that config at the bottom
  192. * of the stack is overriden by config at the top
  193. *
  194. * @test
  195. * @covers Config::load
  196. */
  197. public function test_config_is_loaded_from_top_to_bottom_of_stack()
  198. {
  199. $group_name = 'lolumns';
  200. $reader1 = $this->createMock('KO7_Config_Reader', ['load'], [], 'Unittest_Config_Reader_1');
  201. $reader2 = $this->createMock('KO7_Config_Reader', ['load'], [], 'Unittest_Config_Reader_2');
  202. $reader1
  203. ->expects($this->once())
  204. ->method('load')
  205. ->with($group_name)
  206. ->will($this->returnValue(['foo' => 'bar', 'ko7' => 'awesome', 'life' => ['normal', 'fated']]));
  207. $reader2
  208. ->expects($this->once())
  209. ->method('load')
  210. ->with($group_name)
  211. ->will($this->returnValue(['ko7' => 'sweet', 'music' => 'tasteful', 'life' => ['extraordinary', 'destined']]));
  212. $config = new KO7_Config;
  213. // Attach $reader1 at the "top" and reader2 at the "bottom"
  214. $config->attach($reader1)->attach($reader2, FALSE);
  215. $this->assertSame(
  216. [
  217. 'ko7' => 'awesome',
  218. 'music' => 'tasteful',
  219. 'life' => [
  220. 'extraordinary',
  221. 'destined',
  222. 'normal',
  223. 'fated',
  224. ],
  225. 'foo' => 'bar',
  226. ],
  227. $config->load($group_name)->as_array()
  228. );
  229. }
  230. /**
  231. * load() should keep a record of what config groups have been requested and if
  232. * a group is requested more than once the first instance should be returned
  233. *
  234. * @test
  235. * @covers Config::load
  236. */
  237. public function test_load_reuses_config_groups()
  238. {
  239. $reader = $this->createMock('KO7_Config_Reader', ['load']);
  240. $reader
  241. ->expects($this->once())
  242. ->method('load')
  243. ->with('something')
  244. ->will($this->returnValue([]));
  245. $config = new KO7_Config;
  246. $config->attach($reader);
  247. $group = $config->load('something');
  248. $this->assertSame($group, $config->load('something'));
  249. }
  250. /**
  251. * When we call copy() we expect it to copy the merged config to all writers
  252. *
  253. * @TODO This test sucks due to limitations in the phpunit mock generator. MAKE THIS AWESOME AGAIN!
  254. * @test
  255. * @covers KO7_Config::copy
  256. */
  257. public function test_copy_copies_merged_config_to_all_writers()
  258. {
  259. $config = new KO7_Config;
  260. $reader1 = $this->createMock('KO7_Config_Reader', ['load']);
  261. $reader2 = $this->createMock('KO7_Config_Reader', ['load']);
  262. $reader1
  263. ->expects($this->once())
  264. ->method('load')
  265. ->with('something')
  266. ->will($this->returnValue(['pie' => 'good', 'ko7' => 'awesome']));
  267. $reader2
  268. ->expects($this->once())
  269. ->method('load')
  270. ->with('something')
  271. ->will($this->returnValue(['ko7' => 'good']));
  272. $writer1 = $this->createMock('KO7_Config_Writer', ['write']);
  273. $writer2 = $this->createMock('KO7_Config_Writer', ['write']);
  274. // Due to crazy limitations in phpunit's mocking engine we have to be fairly
  275. // liberal here as to what order we receive the config items
  276. // Good news is that order shouldn't matter *yay*
  277. //
  278. // Now save your eyes and skip the next... 13 lines!
  279. $key = $this->logicalOr('pie', 'ko7');
  280. $val = $this->logicalOr('good', 'awesome');
  281. $writer1
  282. ->expects($this->exactly(2))
  283. ->method('write')
  284. ->with('something', clone $key, clone $val);
  285. $writer2
  286. ->expects($this->exactly(2))
  287. ->method('write')
  288. ->with('something', clone $key, clone $val);
  289. $config
  290. ->attach($reader1)->attach($reader2, FALSE)
  291. ->attach($writer1)->attach($writer2);
  292. // Now let's get this thing going!
  293. $config->copy('something');
  294. }
  295. }