PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/Tests/Phergie/Plugin/TestCase.php

https://github.com/pavlakis/phergie
PHP | 336 lines | 154 code | 30 blank | 152 comment | 14 complexity | 129cf234a13e2348dd73bca209da5133 MD5 | raw file
  1. <?php
  2. /**
  3. * Phergie
  4. *
  5. * PHP version 5
  6. *
  7. * LICENSE
  8. *
  9. * This source file is subject to the new BSD license that is bundled
  10. * with this package in the file LICENSE.
  11. * It is also available through the world-wide-web at this URL:
  12. * http://phergie.org/license
  13. *
  14. * @category Phergie
  15. * @package Phergie_Tests
  16. * @author Phergie Development Team <team@phergie.org>
  17. * @copyright 2008-2011 Phergie Development Team (http://phergie.org)
  18. * @license http://phergie.org/license New BSD License
  19. * @link http://pear.phergie.org/package/Phergie_Tests
  20. */
  21. /**
  22. * Unit test suite for plugin classes.
  23. *
  24. * @category Phergie
  25. * @package Phergie_Tests
  26. * @author Phergie Development Team <team@phergie.org>
  27. * @license http://phergie.org/license New BSD License
  28. * @link http://pear.phergie.org/package/Phergie_Tests
  29. */
  30. abstract class Phergie_Plugin_TestCase extends Phergie_TestCase
  31. {
  32. /**
  33. * Plugin instance being tested
  34. *
  35. * @var Phergie_Plugin_Abstract
  36. */
  37. protected $plugin;
  38. /**
  39. * Full name of the plugin class being tested, may be explicitly
  40. * specified in subclasses but is otherwise automatically derived from
  41. * the test case class name
  42. *
  43. * @var string
  44. */
  45. protected $pluginClass;
  46. /**
  47. * Plugins that should be required in this test
  48. *
  49. * @var array
  50. */
  51. private $expectedRequiredPlugins;
  52. /**
  53. * Plugins that are actually required in this test
  54. *
  55. * @var array
  56. */
  57. private $actualRequiredPlugins;
  58. /**
  59. * Plugins that should be removed in this test
  60. *
  61. * @var array
  62. */
  63. private $expectedRemovedPlugins;
  64. /**
  65. * Plugins that are actually removed in this test
  66. *
  67. * @var array
  68. */
  69. private $actualRemovedPlugins;
  70. /**
  71. * Mocks of plugin dependencies
  72. *
  73. * @var array
  74. */
  75. private $mockPlugins;
  76. /**
  77. * Initializes instance properties.
  78. *
  79. * @return void
  80. */
  81. public function setUp()
  82. {
  83. if (empty($this->pluginClass)) {
  84. $this->pluginClass = preg_replace('/Test$/', '', get_class($this));
  85. }
  86. if (empty($this->plugin)) {
  87. $this->plugin = new $this->pluginClass;
  88. }
  89. $this->plugin->setConfig($this->getMockConfig());
  90. $this->plugin->setConnection($this->getMockConnection());
  91. $this->plugin->setEventHandler($this->getMockEventHandler());
  92. $plugins = $this->getMockPluginHandler();
  93. $plugins->expects($this->any())
  94. ->method('getPlugin')
  95. ->will($this->returnCallback(array($this, 'requirePlugin')));
  96. $plugins->expects($this->any())
  97. ->method('removePlugin')
  98. ->will($this->returnCallback(array($this, 'removePlugin')));
  99. $this->plugin->setPluginHandler($plugins);
  100. $this->mockPlugins = array();
  101. $this->expectedRequiredPlugins = array();
  102. $this->actualRequiredPlugins = array();
  103. $this->expectedRemovedPlugins = array();
  104. $this->actualRemovedPlugins = array();
  105. }
  106. /**
  107. * Destroys all initialized instance properties.
  108. *
  109. * @return void
  110. */
  111. public function tearDown()
  112. {
  113. parent::tearDown();
  114. // Check required plugins
  115. if ($this->expectedRequiredPlugins) {
  116. $diff = array_diff($this->expectedRequiredPlugins, $this->actualRequiredPlugins);
  117. $this->assertSame(
  118. 0,
  119. count($diff),
  120. 'Expected and actual required plugins differ: ' . implode(', ', $diff)
  121. );
  122. }
  123. // Check removed plugins
  124. if ($this->expectedRemovedPlugins) {
  125. $diff = array_diff($this->expectedRequiredPlugins, $this->actualRequiredPlugins);
  126. $this->assertSame(
  127. 0,
  128. count($diff),
  129. 'Expected and actual removed plugins differ: ' . implode(', ', $diff)
  130. );
  131. }
  132. unset($this->plugin);
  133. }
  134. /**
  135. * Returns the absolute path to the Phergie/Plugin directory. Useful in
  136. * conjunction with getMockDatabase().
  137. *
  138. * @param string $subpath Optional path to append to the directory path
  139. *
  140. * @return string Directory path
  141. */
  142. protected function getPluginsPath($subpath = null)
  143. {
  144. $path = dirname(dirname(dirname(dirname(__FILE__)))) . '/Phergie/Plugin';
  145. if (!empty($subpath)) {
  146. $path .= '/' . ltrim($subpath, '/');
  147. }
  148. return $path;
  149. }
  150. /**
  151. * Modifies the event handler to include an expectation of an event
  152. * being added by the plugin being tested. Note that this must be called
  153. * BEFORE executing the plugin code intended to initiate the event.
  154. *
  155. * @param string $type Event type
  156. * @param array $args Optional enumerated array of event arguments
  157. *
  158. * @return void
  159. */
  160. protected function assertEmitsEvent($type, array $args = array())
  161. {
  162. $this->events
  163. ->expects($this->at(0))
  164. ->method('addEvent')
  165. ->with($this->plugin, $type, $args);
  166. }
  167. /**
  168. * Modifies the event handler to include an expectation of an event NOT
  169. * being added by the plugin being tested. Note that this must be called
  170. * BEFORE executing plugin code that may initiate the event.
  171. *
  172. * @param string $type Event type
  173. * @param array $args Optional enumerated array of event arguments
  174. *
  175. * @return void
  176. */
  177. protected function assertDoesNotEmitEvent($type, array $args = array())
  178. {
  179. // Ugly hack to get around an issue in PHPUnit
  180. // @link http://github.com/sebastianbergmann/phpunit-mock-objects/issues/issue/5#issue/5/comment/343524
  181. $callback = create_function(
  182. '$plugin, $type, $args',
  183. 'if (get_class($plugin) == "' . $this->pluginClass . '"
  184. && $type == "' . $type . '"
  185. && $args == "' . var_export($args, true) . '") {
  186. trigger_error("Instance of ' . $this->pluginClass
  187. . ' unexpectedly emitted event of type ' . $type
  188. . '", E_USER_ERROR);
  189. }'
  190. );
  191. $this->events
  192. ->expects($this->any())
  193. ->method('addEvent')
  194. ->will($this->returnCallback($callback));
  195. }
  196. /**
  197. * Records an actual plugin requirement.
  198. *
  199. * @param string $name Short name of the plugin required as a dependency
  200. *
  201. * @return Phergie_Plugin_Abstract Mock instance of the specified plugin
  202. */
  203. public function requirePlugin($name)
  204. {
  205. if (!isset($this->mockPlugins[$name])) {
  206. $this->actualRequiredPlugins[] = $name;
  207. $this->mockPlugins[$name] = $this->getMock('Phergie_Plugin_' . ucfirst($name));
  208. }
  209. return $this->mockPlugins[$name];
  210. }
  211. /**
  212. * Modifies the plugin handler to include an expectation of a plugin
  213. * being retrieved, indicating a dependency. Note that this must be
  214. * called BEFORE executing the plugin code that may load that plugin
  215. * dependency, which is usually located in onLoad().
  216. *
  217. * @param string|array $name Short name of the plugin required as a
  218. * dependency or an array containing multiple instances thereof
  219. *
  220. * @return void
  221. */
  222. public function assertRequiresPlugin($name)
  223. {
  224. if (is_array($name)) {
  225. $this->expectedRequiredPlugins = array_merge($this->expectedRequiredPlugins, $name);
  226. } else {
  227. $this->expectedRequiredPlugins[] = $name;
  228. }
  229. }
  230. /**
  231. * Records an actual plugin removal.
  232. *
  233. * @param string|Phergie_Plugin_Abstract $plugin Short name of the plugin
  234. * or the plugin instance to be removed
  235. *
  236. * @return void
  237. */
  238. public function removePlugin($plugin)
  239. {
  240. $this->actualRemovedPlugins[] = $plugin;
  241. }
  242. /**
  243. * Modifies the plugin handler to include an expectation of a plugin
  244. * being removed. Note that this must be called BEFORE executing the
  245. * plugin code that may remove that plugin.
  246. *
  247. * @param string|Phergie_Plugin_Abstract|array $plugin Short name of the
  248. * plugin or the plugin instance to be removed or an array of
  249. * multiple instances of either
  250. *
  251. * @return void
  252. */
  253. public function assertRemovesPlugin($plugin)
  254. {
  255. if (is_array($plugin)) {
  256. $this->expectedRemovedPlugins = array_merge($this->expectedRemovedPlugins, $plugin);
  257. } else {
  258. $this->expectedRemovedPlugins[] = $plugin;
  259. }
  260. }
  261. /**
  262. * Creates an in-memory copy of a specified SQLite database file and
  263. * returns a connection to it.
  264. *
  265. * @param string $path Path to the SQLite file to copy
  266. *
  267. * @return PDO Connection to the database copy
  268. */
  269. public function getMockDatabase($path)
  270. {
  271. $original = new PDO('sqlite:' . $path);
  272. $copy = new PDO('sqlite::memory:');
  273. $result = $original->query('SELECT sql FROM sqlite_master');
  274. while ($sql = $result->fetchColumn()) {
  275. $copy->exec($sql);
  276. }
  277. $tables = array();
  278. $result = $original->query(
  279. 'SELECT name FROM sqlite_master WHERE type = "table"'
  280. );
  281. while ($table = $result->fetchColumn()) {
  282. $tables[] = $table;
  283. }
  284. foreach ($tables as $table) {
  285. $result = $original->query('SELECT * FROM ' . $table);
  286. $insert = null;
  287. $copy->beginTransaction();
  288. while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
  289. $columns = array_keys($row);
  290. if (empty($insert)) {
  291. $insert = $copy->prepare(
  292. 'INSERT INTO "' . $table . '" (' .
  293. '"' . implode('", "', $columns) . '"' .
  294. ') VALUES (' .
  295. ':' . implode(', :', $columns) .
  296. ')'
  297. );
  298. }
  299. $insert->execute($row);
  300. }
  301. $copy->commit();
  302. unset($insert);
  303. }
  304. return $copy;
  305. }
  306. }