Yaffs site version 1.1
[yaffs-website] / vendor / gabordemooij / redbean / testing / RedUNIT / Base / Fuse.php
1 <?php
2
3 namespace RedUNIT\Base;
4
5 use RedUNIT\Base as Base;
6 use RedBeanPHP\Facade as R;
7 use RedBeanPHP\ModelHelper as ModelHelper;
8 use RedBeanPHP\RedException as RedException;
9 use RedBeanPHP\OODBBean as OODBBean;
10 use RedBeanPHP\OODB as OODB;
11 use RedBeanPHP\ToolBox as ToolBox;
12 use RedBeanPHP\QueryWriter as QueryWriter;
13 use RedBeanPHP\Adapter as Adapter;
14 use RedBeanPHP\BeanHelper\SimpleFacadeBeanHelper as SimpleFacadeBeanHelper;
15
16 /**
17  * FUSE
18  *
19  * Tests whether we can associate model logic on-the-fly
20  * by defining models extending from SimpleModel. Tests
21  * whether the calls to facade trigger the corresponding
22  * methods on the model.
23  *
24  * @file    RedUNIT/Base/Fuse.php
25  * @desc    Tests Fuse feature; coupling beans to models.
26  * @author  Gabor de Mooij and the RedBeanPHP Community
27  * @license New BSD/GPLv2
28  *
29  * (c) G.J.G.T. (Gabor) de Mooij and the RedBeanPHP Community.
30  * This source file is subject to the New BSD/GPLv2 License that is bundled
31  * with this source code in the file license.txt.
32  */
33 class Fuse extends Base
34 {
35         /**
36          * Test whether we can override the getModelForBean() method
37          * of the BeanHelper and use a custom BeanHelper to attach a model
38          * based on type.
39          *
40          * @return void
41          */
42         public function testCustomBeanHelper()
43         {
44                 $customBeanHelper = new \SoupBeanHelper( R::getToolbox() );
45                 $oldBeanHelper = R::getRedBean()->getBeanHelper();
46                 asrt( ( $oldBeanHelper instanceof SimpleFacadeBeanHelper ), TRUE );
47                 R::getRedBean()->setBeanHelper( $customBeanHelper );
48                 $meal = R::dispense( 'meal' );
49                 asrt( ( $meal->box() instanceof \Model_Soup ), TRUE );
50                 $cake = R::dispense( 'cake' );
51                 asrt( is_null( $cake->box() ), TRUE );
52                 $bean = R::dispense( 'coffee' );
53                 asrt( ( $bean->box() instanceof \Model_Coffee ), TRUE );
54                 $meal->setFlavour( 'tomato' );
55                 asrt( $meal->getFlavour(), 'tomato' );
56                 $meal->rating = 5;
57                 R::store( $meal );
58                 asrt( $meal->getFlavour(), 'tomato' );
59                 $meal = $meal->unbox();
60                 asrt( $meal->getFlavour(), 'tomato' );
61                 $meal = R::findOne( 'meal' );
62                 asrt( ( $meal->box() instanceof \Model_Soup ), TRUE );
63                 asrt( $meal->getFlavour(), '' );
64                 $meal->setFlavour( 'tomato' );
65                 asrt( $meal->getFlavour(), 'tomato' );
66                 $meal = $meal->unbox();
67                 asrt( $meal->getFlavour(), 'tomato' );
68                 R::getRedBean()->setBeanHelper( $oldBeanHelper );
69         }
70
71         /**
72          * Test FUSE hooks (i.e. open, update, update_after etc..)
73          *
74          * @return void
75          */
76         public function testHooks()
77         {
78                 R::nuke();
79                 $probe = R::dispense( 'probe' );
80                 $probe->name = 'test';
81                 asrt( $probe->getLogActionCount(), 1 );
82                 asrt( $probe->getLogActionCount( 'dispense' ), 1 );
83                 asrt( $probe->getLogActionCount( 'open' ), 0 );
84                 asrt( $probe->getLogActionCount( 'update' ), 0 );
85                 asrt( $probe->getLogActionCount( 'after_update' ), 0 );
86                 asrt( $probe->getLogActionCount( 'delete' ), 0 );
87                 asrt( $probe->getLogActionCount( 'after_delete' ), 0 );
88                 asrt( ( $probe->getDataFromLog( 0, 'bean' ) === $probe ), TRUE );
89                 R::store( $probe );
90                 asrt( $probe->getLogActionCount(), 3 );
91                 asrt( $probe->getLogActionCount( 'dispense' ), 1 );
92                 asrt( $probe->getLogActionCount( 'open' ), 0 );
93                 asrt( $probe->getLogActionCount( 'update' ), 1 );
94                 asrt( $probe->getLogActionCount( 'after_update' ), 1 );
95                 asrt( $probe->getLogActionCount( 'delete' ), 0 );
96                 asrt( $probe->getLogActionCount( 'after_delete' ), 0 );
97                 asrt( ( $probe->getDataFromLog( 2, 'bean' ) === $probe ), TRUE );
98                 $probe = R::load( 'probe', $probe->id );
99                 asrt( $probe->getLogActionCount(), 2 );
100                 asrt( $probe->getLogActionCount( 'dispense' ), 1 );
101                 asrt( $probe->getLogActionCount( 'open' ), 1 );
102                 asrt( $probe->getLogActionCount( 'update' ), 0 );
103                 asrt( $probe->getLogActionCount( 'after_update' ), 0 );
104                 asrt( $probe->getLogActionCount( 'delete' ), 0 );
105                 asrt( $probe->getLogActionCount( 'after_delete' ), 0 );
106                 asrt( ( $probe->getDataFromLog( 0, 'bean' ) === $probe ), TRUE );
107                 asrt( ( $probe->getDataFromLog( 1, 'id' ) === $probe->id ), TRUE );
108                 $probe->clearLog();
109                 R::trash( $probe );
110                 asrt( $probe->getLogActionCount(), 2 );
111                 asrt( $probe->getLogActionCount( 'dispense' ), 0 );
112                 asrt( $probe->getLogActionCount( 'open' ), 0 );
113                 asrt( $probe->getLogActionCount( 'update' ), 0 );
114                 asrt( $probe->getLogActionCount( 'after_update' ), 0 );
115                 asrt( $probe->getLogActionCount( 'delete' ), 1 );
116                 asrt( $probe->getLogActionCount( 'after_delete' ), 1 );
117                 asrt( ( $probe->getDataFromLog( 0, 'bean' ) === $probe ), TRUE );
118                 asrt( ( $probe->getDataFromLog( 1, 'bean' ) === $probe ), TRUE );
119                 //less 'normal scenarios'
120                 $probe = R::dispense( 'probe' );
121                 $probe->name = 'test';
122                 asrt( $probe->getLogActionCount(), 1 );
123                 asrt( $probe->getLogActionCount( 'dispense' ), 1 );
124                 asrt( $probe->getLogActionCount( 'open' ), 0 );
125                 asrt( $probe->getLogActionCount( 'update' ), 0 );
126                 asrt( $probe->getLogActionCount( 'after_update' ), 0 );
127                 asrt( $probe->getLogActionCount( 'delete' ), 0 );
128                 asrt( $probe->getLogActionCount( 'after_delete' ), 0 );
129                 asrt( ( $probe->getDataFromLog( 0, 'bean' ) === $probe ), TRUE );
130                 R::store( $probe );
131                 asrt( $probe->getLogActionCount(), 3 );
132                 asrt( $probe->getLogActionCount( 'dispense' ), 1 );
133                 asrt( $probe->getLogActionCount( 'open' ), 0 );
134                 asrt( $probe->getLogActionCount( 'update' ), 1 );
135                 asrt( $probe->getLogActionCount( 'after_update' ), 1 );
136                 asrt( $probe->getLogActionCount( 'delete' ), 0 );
137                 asrt( $probe->getLogActionCount( 'after_delete' ), 0 );
138                 asrt( ( $probe->getDataFromLog( 2, 'bean' ) === $probe ), TRUE );
139                 asrt( $probe->getMeta( 'tainted' ), FALSE );
140                 asrt( $probe->getMeta( 'changed' ), FALSE );
141                 R::store( $probe ); //not tainted, no FUSE save!
142                 asrt( $probe->getLogActionCount(), 3 );
143                 asrt( $probe->getLogActionCount( 'dispense' ), 1 );
144                 asrt( $probe->getLogActionCount( 'open' ), 0 );
145                 asrt( $probe->getLogActionCount( 'update' ), 1 );
146                 asrt( $probe->getLogActionCount( 'after_update' ), 1 );
147                 asrt( $probe->getLogActionCount( 'delete' ), 0 );
148                 asrt( $probe->getLogActionCount( 'after_delete' ), 0 );
149                 asrt( ( $probe->getDataFromLog( 2, 'bean' ) === $probe ), TRUE );
150                 $probe->xownProbeList[] = R::dispense( 'probe' );
151                 //tainted, not changed, triggers FUSE
152                 asrt( $probe->getMeta( 'tainted' ), TRUE );
153                 asrt( $probe->getMeta( 'changed' ), FALSE );
154                 R::store( $probe );
155                 asrt( $probe->getMeta( 'tainted' ), FALSE );
156                 asrt( $probe->getMeta( 'changed' ), FALSE );
157                 asrt( $probe->getLogActionCount(), 5 );
158                 asrt( $probe->getLogActionCount( 'dispense' ), 1 );
159                 asrt( $probe->getLogActionCount( 'open' ), 0 );
160                 asrt( $probe->getLogActionCount( 'update' ), 2 );
161                 asrt( $probe->getLogActionCount( 'after_update' ), 2 );
162                 asrt( $probe->getLogActionCount( 'delete' ), 0 );
163                 asrt( $probe->getLogActionCount( 'after_delete' ), 0 );
164                 asrt( ( $probe->getDataFromLog( 2, 'bean' ) === $probe ), TRUE );
165         }
166
167         /**
168          * Tests the SimpleFacadeBeanHelper factory setter.
169          *
170          * @return void
171          */
172         public function testFactory()
173         {
174                 SimpleFacadeBeanHelper::setFactoryFunction( function( $name ) {
175                         $model = new $name();
176                         $model->setNote( 'injected', 'dependency' );
177                         return $model;
178                 } );
179
180                 $bean = R::dispense( 'band' )->box();
181
182                 asrt( ( $bean instanceof \Model_Band ), TRUE );
183                 asrt( ( $bean->getNote('injected') ), 'dependency' );
184
185                 SimpleFacadeBeanHelper::setFactoryFunction( NULL );
186         }
187
188         /**
189          * Make sure that beans of type book_page can be fused with
190          * models like BookPage (beautified) as well as Book_Page (non-beautified).
191          */
192         public function testBeutificationOfLinkModel()
193         {
194                 $page = R::dispense( 'page' );
195                 $widget = R::dispense( 'widget' );
196                 $page->sharedWidgetList[] = $widget;
197                 R::store( $page );
198                 $testReport = \Model_PageWidget::getTestReport();
199                 asrt( $testReport, 'didSave' );
200
201                 $page = R::dispense( 'page' );
202                 $gadget = R::dispense( 'gadget' );
203                 $page->sharedGadgetList[] = $gadget;
204                 R::store( $page );
205                 $testReport = \Model_Gadget_Page::getTestReport();
206                 asrt( $testReport, 'didSave' );
207         }
208
209         /**
210          * Only theoretical.
211          *
212          * @return void
213          */
214         public function testTheoreticalBeautifications()
215         {
216                 $bean = R::dispense('bean');
217                 $bean->setMeta('type', 'a_b_c');
218                 R::store($bean);
219                 $testReport = \Model_A_B_C::getTestReport();
220                 asrt( $testReport, 'didSave' );
221         }
222
223         /**
224          * Test extraction of toolbox.
225          *
226          * @return void
227          */
228         public function testGetExtractedToolBox()
229         {
230                 $helper = new SimpleFacadeBeanHelper;
231
232                 list( $redbean, $database, $writer, $toolbox ) = $helper->getExtractedToolbox();
233
234                 asrt( ( $redbean  instanceof OODB        ), TRUE );
235                 asrt( ( $database instanceof Adapter     ), TRUE );
236                 asrt( ( $writer   instanceof QueryWriter ), TRUE );
237                 asrt( ( $toolbox  instanceof ToolBox     ), TRUE );
238         }
239
240         /**
241          * Test FUSE and model formatting.
242          *
243          * @todo move tagging tests to tag tester.
244          *
245          * @return void
246          */
247         public function testFUSE()
248         {
249                 $toolbox = R::getToolBox();
250                 $adapter = $toolbox->getDatabaseAdapter();
251                 $blog = R::dispense( 'blog' );
252                 $blog->title = 'testing';
253                 $blog->blog  = 'tesing';
254                 R::store( $blog );
255                 $blogpost = R::load( "blog", 1 );
256                 $post = R::dispense( "post" );
257                 $post->message = "hello";
258                 $blog->sharedPost[] = $post;
259                 R::store($blog);
260                 $a = R::getAll( "select * from blog " );
261                 R::tag( $post, "lousy,smart" );
262                 asrt( implode( ',', R::tag( $post ) ), "lousy,smart" );
263                 R::tag( $post, "clever,smart" );
264                 $tagz = implode( ',', R::tag( $post ) );
265                 asrt( ( $tagz == "smart,clever" || $tagz == "clever,smart" ), TRUE );
266                 R::tag( $blog, array( "smart", "interesting" ) );
267                 asrt( implode( ',', R::tag( $blog ) ), "smart,interesting" );
268                 try {
269                         R::tag( $blog, array( "smart", "interesting", "lousy!" ) );
270                         pass();
271                 } catch ( RedException $e ) {
272                         fail();
273                 }
274                 asrt( implode( ',', R::tag( $blog ) ), "smart,interesting,lousy!" );
275                 asrt( implode( ",", R::tag( $blog ) ), "smart,interesting,lousy!" );
276                 R::untag( $blog, array( "smart", "interesting" ) );
277                 asrt( implode( ",", R::tag( $blog ) ), "lousy!" );
278                 asrt( R::hasTag( $blog, array( "lousy!" ) ), TRUE );
279                 asrt( R::hasTag( $blog, array( "lousy!", "smart" ) ), TRUE );
280                 asrt( R::hasTag( $blog, array( "lousy!", "smart" ), TRUE ), FALSE );
281                 R::tag( $blog, FALSE );
282                 asrt( count( R::tag( $blog ) ), 0 );
283                 R::tag( $blog, array( "funny", "comic" ) );
284                 asrt( count( R::tag( $blog ) ), 2 );
285                 R::addTags( $blog, array( "halloween" ) );
286                 asrt( count( R::tag( $blog ) ), 3 );
287                 asrt( R::hasTag( $blog, array( "funny", "commic", "halloween" ), TRUE ), FALSE );
288                 R::unTag( $blog, array( "funny" ) );
289                 R::addTags( $blog, "horror" );
290                 asrt( count( R::tag( $blog ) ), 3 );
291                 asrt( R::hasTag( $blog, array( "horror", "commic", "halloween" ), TRUE ), FALSE );
292                 // No double tags
293                 R::addTags( $blog, "horror" );
294                 asrt( R::hasTag( $blog, array( "horror", "commic", "halloween" ), TRUE ), FALSE );
295                 asrt( count( R::tag( $blog ) ), 3 );
296         }
297
298         /**
299          * Test error handling options FUSE.
300          */
301         public function testModelErrorHandling()
302         {
303                 $test = R::dispense( 'feed' );
304                 $test->nonExistantMethod();
305                 pass();
306                 $old = R::setErrorHandlingFUSE( OODBBean::C_ERR_LOG );
307                 asrt( is_array( $old ), TRUE );
308                 asrt( count( $old ), 2 );
309                 asrt( $old[0], FALSE );
310                 asrt( $old[1], NULL);
311                 $test->nonExistantMethod(); //we cant really test this... :(
312                 pass();
313                 $old = R::setErrorHandlingFUSE( OODBBean::C_ERR_NOTICE );
314                 asrt( is_array( $old ), TRUE );
315                 asrt( count( $old ), 2 );
316                 asrt( $old[0], OODBBean::C_ERR_LOG );
317                 asrt( $old[1], NULL);
318                 set_error_handler(function($error, $str) {
319                         asrt( $str, 'FUSE: method does not exist in model: nonExistantMethod' );
320                 }, E_USER_NOTICE);
321                 $test->nonExistantMethod();
322                 restore_error_handler();
323                 $old = OODBBean::setErrorHandlingFUSE( OODBBean::C_ERR_WARN );
324                 asrt( is_array( $old ), TRUE );
325                 asrt( count( $old ), 2 );
326                 asrt( $old[0], OODBBean::C_ERR_NOTICE );
327                 asrt( $old[1], NULL);
328                 set_error_handler(function($error, $str) {
329                         asrt( $str, 'FUSE: method does not exist in model: nonExistantMethod' );
330                 }, E_USER_WARNING);
331                 $test->nonExistantMethod();
332                 restore_error_handler();
333                 $old = OODBBean::setErrorHandlingFUSE( OODBBean::C_ERR_FATAL );
334                 asrt( is_array( $old ), TRUE );
335                 asrt( count( $old ), 2 );
336                 asrt( $old[0], OODBBean::C_ERR_WARN );
337                 asrt( $old[1], NULL);
338                 set_error_handler(function($error, $str) {
339                         asrt( $str, 'FUSE: method does not exist in model: nonExistantMethod' );
340                 }, E_USER_ERROR);
341                 $test->nonExistantMethod();
342                 restore_error_handler();
343                 $old = OODBBean::setErrorHandlingFUSE( OODBBean::C_ERR_EXCEPTION );
344                 asrt( is_array( $old ), TRUE );
345                 asrt( count( $old ), 2 );
346                 asrt( $old[0], OODBBean::C_ERR_FATAL );
347                 asrt( $old[1], NULL);
348                 try {
349                         $test->nonExistantMethod();
350                         fail();
351                 } catch (\Exception $e) {
352                         pass();
353                 }
354                 global $test_bean;
355                 $test_bean = $test;
356                 global $has_executed_error_func_fuse;
357                 $has_executed_error_func_fuse = FALSE;
358                 $old = OODBBean::setErrorHandlingFUSE( OODBBean::C_ERR_FUNC, function( $info ){
359                         global $has_executed_error_func_fuse;
360                         global $test_bean;
361                         $has_executed_error_func_fuse = TRUE;
362                         asrt( is_array( $info ), TRUE );
363                         asrt( $info['method'], 'nonExistantMethod' );
364                         asrt( json_encode( $info['bean']->export() ), json_encode( $test_bean->export() ) );
365                         asrt( $info['message'], 'FUSE: method does not exist in model: nonExistantMethod' );
366                 } );
367                 asrt( is_array( $old ), TRUE );
368                 asrt( count( $old ), 2 );
369                 asrt( $old[0], OODBBean::C_ERR_EXCEPTION );
370                 asrt( $old[1], NULL);
371                 $test->nonExistantMethod();
372                 asrt( $has_executed_error_func_fuse, TRUE );
373                 $old = OODBBean::setErrorHandlingFUSE( OODBBean::C_ERR_IGNORE );
374                 asrt( is_array( $old ), TRUE );
375                 asrt( count( $old ), 2 );
376                 asrt( $old[0], OODBBean::C_ERR_FUNC );
377                 asrt( is_callable( $old[1] ), TRUE );
378                 $old = OODBBean::setErrorHandlingFUSE( OODBBean::C_ERR_IGNORE );
379                 asrt( is_array( $old ), TRUE );
380                 asrt( count( $old ), 2 );
381                 asrt( $old[0], OODBBean::C_ERR_IGNORE );
382                 asrt( $old[1], NULL);
383                 try {
384                         OODBBean::setErrorHandlingFUSE( 900 );
385                         fail();
386                 } catch (\Exception $e) {
387                         pass();
388                         asrt( $e->getMessage(), 'Invalid error mode selected' );
389                 }
390                 try {
391                         OODBBean::setErrorHandlingFUSE( OODBBean::C_ERR_FUNC, 'hello' );
392                         fail();
393                 } catch (\Exception $e) {
394                         pass();
395                         asrt( $e->getMessage(), 'Invalid error handler' );
396                 }
397                 OODBBean::setErrorHandlingFUSE( OODBBean::C_ERR_EXCEPTION );
398                 //make sure ignore FUSE events
399                 $test = R::dispense('feed');
400                 R::store( $test );
401                 $test = $test->fresh();
402                 R::trash( $test );
403                 pass();
404                 OODBBean::setErrorHandlingFUSE( OODBBean::C_ERR_IGNORE );
405         }
406 }