Yaffs site version 1.1
[yaffs-website] / vendor / gabordemooij / redbean / testing / RedUNIT / Base / Dup.php
1 <?php
2
3 namespace RedUNIT\Base;
4
5 use RedUNIT\Base as Base;
6 use RedBeanPHP\Facade as R;
7 use RedBeanPHP\DuplicationManager as DuplicationManager;
8 use RedBeanPHP\OODBBean as OODBBean;
9 use RedBeanPHP\RedException as RedException;
10
11 /**
12  * Dup
13  *
14  * Tests duplication. Like the 'copy' test suite but
15  * focuses on more complex scenarios.
16  *
17  * @file    RedUNIT/Base/Dup.php
18  * @desc    Intensive test for dup()
19  * @author  Gabor de Mooij and the RedBeanPHP Community
20  * @license New BSD/GPLv2
21  *
22  * (c) G.J.G.T. (Gabor) de Mooij and the RedBeanPHP Community.
23  * This source file is subject to the New BSD/GPLv2 License that is bundled
24  * with this source code in the file license.txt.
25  */
26 class Dup extends Base
27 {
28         /**
29          * Tests whether the original ID is stored
30          * in meta data (quite handy for ID mappings).
31          */
32         public function testKeepOldID()
33         {
34                 R::nuke();
35                 $book = R::dispense( 'book' );
36                 $book->xownPageList[] = R::dispense( 'page' );
37                 R::store( $book );
38                 $bookID = $book->id;
39                 $page = reset( $book->xownPageList );
40                 $pageID = $page->id;
41                 $book = $book->fresh();
42                 $copy = R::duplicate( $book );
43                 asrt( $copy->getMeta( 'sys.dup-from-id' ), $bookID );
44                 $copyPage = reset( $copy->xownPageList );
45                 asrt( $copyPage->getMeta( 'sys.dup-from-id' ), $pageID );
46         }
47
48         /**
49          * Test export camelCase.
50          *
51          * @return void
52          */
53         public function testExportCamelCase()
54         {
55                 R::nuke();
56                 $book = R::dispense( 'book' );
57                 $book->isCheap = true;
58                 $book->hasISBNCode = false;
59                 $page = R::dispense('page');
60                 $page->isWrittenWell = true;
61                 $page->containsInterestingText = true;
62                 $book->ownPageList[] = $page;
63                 R::store( $book );
64                 $book = $book->fresh();
65                 $export = R::exportAll( $book );
66
67                 asrt( isset( $export[0]['id'] ), true );
68                 asrt( isset( $export[0]['is_cheap'] ), true );
69                 asrt( isset( $export[0]['has_isbn_code'] ), true );
70                 asrt( isset( $export[0]['ownPage']['0']['id'] ), true );
71                 asrt( isset( $export[0]['ownPage']['0']['is_written_well'] ), true );
72                 asrt( isset( $export[0]['ownPage']['0']['contains_interesting_text'] ), true );
73                 asrt( isset( $export[0]['ownPage']['0']['book_id'] ), true );
74
75                 R::useExportCase( 'camel' );
76                 $export = R::exportAll( $book );
77                 asrt( isset( $export[0]['id'] ), true );
78                 asrt( isset( $export[0]['isCheap'] ), true );
79                 asrt( isset( $export[0]['hasIsbnCode'] ), true );
80                 asrt( isset( $export[0]['ownPage']['0']['id'] ), true );
81                 asrt( isset( $export[0]['ownPage']['0']['isWrittenWell'] ), true );
82                 asrt( isset( $export[0]['ownPage']['0']['containsInterestingText'] ), true );
83                 asrt( isset( $export[0]['ownPage']['0']['bookId'] ), true );
84
85                 R::useExportCase( 'dolphin' );
86                 $export = R::exportAll( $book );
87                 asrt( isset( $export[0]['id'] ), true );
88                 asrt( isset( $export[0]['isCheap'] ), true );
89                 asrt( isset( $export[0]['hasIsbnCode'] ), true );
90                 asrt( isset( $export[0]['ownPage']['0']['id'] ), true );
91                 asrt( isset( $export[0]['ownPage']['0']['isWrittenWell'] ), true );
92                 asrt( isset( $export[0]['ownPage']['0']['containsInterestingText'] ), true );
93                 asrt( isset( $export[0]['ownPage']['0']['bookID'] ), true );
94
95                 R::useExportCase( 'default' );
96                 $export = R::exportAll( $book );
97                 asrt( isset( $export[0]['id'] ), true );
98                 asrt( isset( $export[0]['is_cheap'] ), true );
99                 asrt( isset( $export[0]['has_isbn_code'] ), true );
100                 asrt( isset( $export[0]['ownPage']['0']['id'] ), true );
101                 asrt( isset( $export[0]['ownPage']['0']['is_written_well'] ), true );
102                 asrt( isset( $export[0]['ownPage']['0']['contains_interesting_text'] ), true );
103                 asrt( isset( $export[0]['ownPage']['0']['book_id'] ), true );
104
105                 try {
106                         R::useExportCase( 'invalid' );
107                         fail();
108                 } catch ( RedException $exception ) {
109                         pass();
110                 }
111         }
112
113         /**
114          * Test whether we can duplicate part of a tree
115          * without infinite loops.
116          *
117          * @return void
118          */
119         public function testDupPortionOfATree()
120         {
121                 R::nuke();
122                 $article = R::dispense( 'article' );
123                 $article->name = 'article 1';
124                 list( $article2, $article3 ) = R::dispense( 'article', 2 );
125                 $article2->name = 'article 2';
126                 $article3->name = 'article 3';
127                 list( $article4, $article5 ) = R::dispense( 'article' , 2);
128                 $article4->name = 'article 4';
129                 $article5->name = 'article 5';
130                 list( $article6, $article7 ) = R::dispense( 'article' , 2);
131                 $article6->name = 'article 6';
132                 $article7->name = 'article 7';
133                 $article3->xownArticleList[] = $article7;
134                 $article4->xownArticleList[] = $article6;
135                 $article2->xownArticleList = array( $article5, $article4 );
136                 $article->xownArticleList = array( $article2, $article3 );
137                 R::store( $article );
138                 asrt( R::count( 'article' ), 7 );
139                 $article2 = $article2->fresh();
140                 $dupArticle2 = R::duplicate( $article2 );
141                 $dupArticle2->name = 'article 2b';
142                 $dupBeans = $dupArticle2->xownArticleList;
143                 foreach( $dupBeans as $dupBean ) {
144                         $list[] = $dupBean->name;
145                 }
146                 sort( $list );
147                 $listStr = implode( ',', $list );
148                 asrt( $listStr, 'article 4,article 5' );
149                 foreach( $dupBeans as $dupBean ) {
150                         if ( $dupBean->name === 'article 4' ) {
151                                 $dup4 = $dupBean;
152                         }
153                 }
154                 asrt( isset( $dup4 ), TRUE );
155                 $dupBeans = $dup4->xownArticleList;
156                 foreach( $dupBeans as $dupBean ) {
157                         asrt( $dupBean->name, 'article 6' );
158                 }
159
160                 //so we have extracted part of the tree, can we store it?
161                 $id = R::store( $dupArticle2 );
162                 asrt( ( $id > 0 ), TRUE );
163                 asrt( R::count( 'article' ), 11 );
164
165                 $originalArticle = $article->fresh();
166                 asrt( $originalArticle->name, 'article 1' );
167
168                 $subArticles = $originalArticle->xownArticleList;
169                 $list = array();
170                 foreach( $subArticles as $subArticle ) {
171                         $list[] = $subArticle->name;
172                 }
173                 sort( $list );
174                 $listStr = implode( ',', $list );
175                 asrt( $listStr, 'article 2,article 2b,article 3' );
176
177                 foreach( $subArticles as $subArticle ) {
178                         if ( $subArticle->name === 'article 2' ) {
179                                 $sub2 = $subArticle;
180                         }
181                         if ( $subArticle->name === 'article 3' ) {
182                                 $sub3 = $subArticle;
183                         }
184                 }
185
186                 $subArticles = $sub2->xownArticleList;
187                 $list = array();
188                 foreach( $subArticles as $subArticle ) {
189                         $list[] = $subArticle->name;
190                 }
191                 sort( $list );
192                 $listStr = implode( ',', $list );
193                 asrt( $listStr, 'article 4,article 5' );
194
195                 $subArticles = $sub3->xownArticleList;
196                 $list = array();
197                 foreach( $subArticles as $subArticle ) {
198                         $list[] = $subArticle->name;
199                 }
200                 sort( $list );
201                 $listStr = implode( ',', $list );
202                 asrt( $listStr, 'article 7' );
203
204                 $subArticles = $sub2->xownArticleList;
205                 foreach( $subArticles as $subArticle ) {
206                         if ( $subArticle->name === 'article 4' ) {
207                                 $sub4 = $subArticle;
208                         }
209                         if ( $subArticle->name === 'article 5' ) {
210                                 $sub5 = $subArticle;
211                         }
212                 }
213
214                 asrt( count( $sub4->xownArticleList ), 1 );
215                 $subBeans = $sub4->xownArticleList;
216                 $subBean = reset( $subBeans );
217                 asrt( $subBean->name, 'article 6');
218
219                 asrt( count( $sub5->xownArticleList ), 0 );
220
221                 $dupArticle2 = $dupArticle2->fresh();
222                 $subArticles = $dupArticle2->xownArticleList;
223                 $list = array();
224                 foreach( $subArticles as $subArticle ) {
225                         $list[] = $subArticle->name;
226                 }
227                 sort( $list );
228                 $listStr = implode( ',', $list );
229                 asrt( $listStr, 'article 4,article 5' );
230
231                 foreach( $subArticles as $subArticle ) {
232                         if ( $subArticle->name === 'article 4' ) {
233                                 $sub4 = $subArticle;
234                         }
235                         if ( $subArticle->name === 'article 5' ) {
236                                 $sub5 = $subArticle;
237                         }
238                 }
239
240                 asrt( count( $sub4->xownArticleList ), 1 );
241                 $subBeans = $sub4->xownArticleList;
242                 $subBean = reset( $subBeans );
243                 asrt( $subBean->name, 'article 6');
244
245                 asrt( count( $sub5->xownArticleList ), 0 );
246         }
247
248         /**
249          * Test exportAll and caching.
250          *
251          * @return void
252          */
253         public function testExportAllAndCache()
254         {
255                 testpack( 'exportAll() and Cache' );
256
257                 $can = R::dispense( 'can' )->setAttr( 'size', 3 );
258
259                 $can->ownCoffee[] = R::dispense( 'coffee' )->setAttr( 'color', 'black' );
260                 $can->sharedTag[] = R::dispense( 'tag' )->setAttr( 'name', 'cool' );
261
262                 $id = R::store( $can );
263
264                 R::debug( TRUE );
265
266                 ob_start();
267
268                 $can = R::load( 'can', $id );
269
270                 $cache = $this->getCache();
271
272                 $data = R::exportAll( array( $can ), TRUE );
273
274                 $queries = ob_get_contents();
275
276                 R::debug( FALSE );
277                 ob_end_clean();
278                 $len1 = strlen( $queries );
279
280                 $can              = R::dispense( 'can' )->setAttr( 'size', 3 );
281                 $can->ownCoffee[] = R::dispense( 'coffee' )->setAttr( 'color', 'black' );
282                 $can->sharedTag[] = R::dispense( 'tag' )->setAttr( 'name', 'cool' );
283
284                 $id = R::store( $can );
285
286                 R::debug( TRUE );
287
288                 ob_start();
289
290                 $can = R::load( 'can', $id );
291
292                 $cache = $this->getCache();
293
294                 $data = R::exportAll( array( $can ), TRUE );
295
296                 $queries = ob_get_contents();
297
298                 R::debug( FALSE );
299
300                 ob_end_clean();
301
302                 $len2 = strlen( $queries );
303
304                 asrt( ( $len1 ), ( $len2 ) );
305
306                 $can = R::dispense( 'can' )->setAttr( 'size', 3 );
307
308                 $can->ownCoffee[] = R::dispense( 'coffee' )->setAttr( 'color', 'black' );
309                 $can->sharedTag[] = R::dispense( 'tag' )->setAttr( 'name', 'cool' );
310
311                 $id = R::store( $can );
312
313                 R::debug( TRUE );
314
315                 ob_start();
316
317                 $can = R::load( 'can', $id );
318
319                 $cache = $this->getCache();
320
321                 R::getDuplicationManager()->setTables( $cache );
322
323                 $data = R::exportAll( array( $can ), TRUE );
324
325                 $queries = ob_get_contents();
326
327                 R::debug( FALSE );
328
329                 ob_end_clean();
330
331                 $len3 = strlen( $queries );
332
333                 asrt( ( ( $len3 ) < ( $len2 ) ), TRUE );
334                 asrt( count( $data ), 1 );
335                 asrt( $data[0]['ownCoffee'][0]['color'], 'black' );
336
337                 R::getDuplicationManager()->setCacheTables( FALSE );
338         }
339
340         /**
341          * Test duplication and caching.
342          *
343          * @return void
344          */
345         public function DupAndCache()
346         {
347                 testpack( 'Dup() and Cache' );
348
349                 $can = R::dispense( 'can' )->setAttr( 'size', 3 );
350
351                 $can->ownCoffee[] = R::dispense( 'coffee' )->setAttr( 'color', 'black' );
352                 $can->sharedTag[] = R::dispense( 'tag' )->setAttr( 'name', 'cool' );
353
354                 $can = R::load( 'can', R::store( $can ) );
355
356                 $d = new DuplicationManager( R::getToolBox() );
357
358                 $d->setCacheTables( TRUE );
359
360                 ob_start();
361
362                 R::debug( 1 );
363
364                 $x = $d->dup( $can );
365
366                 $queries = ob_get_contents();
367
368                 R::debug( 0 );
369
370                 ob_end_clean();
371
372                 $len1 = strlen( $queries );
373
374                 asrt( ( $len1 > 40 ), TRUE );
375                 asrt( isset( $x->ownCoffee ), TRUE );
376                 asrt( count( $x->ownCoffee ), 1 );
377                 asrt( isset( $x->sharedTag ), TRUE );
378                 asrt( count( $x->sharedTag ), 1 );
379
380                 $cache = $d->getSchema();
381
382                 R::nuke();
383
384                 $can = R::dispense( 'can' )->setAttr( 'size', 3 );
385
386                 $can->ownCoffee[] = R::dispense( 'coffee' )->setAttr( 'color', 'black' );
387                 $can->sharedTag[] = R::dispense( 'tag' )->setAttr( 'name', 'cool' );
388
389                 $can = R::load( 'can', R::store( $can ) );
390
391                 $d = new DuplicationManager( R::getToolBox() );
392
393                 /**
394                  * $cache = '{"book": {
395                  *  "id": "INTEGER",
396                  *  "title": "TEXT"
397                  * }, "bean": {
398                  *  "id": "INTEGER",
399                  *  "prop": "INTEGER"
400                  * }, "pessoa": {
401                  *  "id": "INTEGER",
402                  *  "nome": "TEXT",
403                  *  "nome_meio": "TEXT",
404                  *  "sobrenome": "TEXT",
405                  *  "nascimento": "NUMERIC",
406                  *  "reg_owner": "TEXT"
407                  * }, "documento": {
408                  *  "id": "INTEGER",
409                  *  "nome_documento": "TEXT",
410                  *  "numero_documento": "TEXT",
411                  *  "reg_owner": "TEXT",
412                  *  "ownPessoa_id": "INTEGER"
413                  * }, "can": {
414                  *  "id": "INTEGER",
415                  *  "size": "INTEGER"
416                  * }, "coffee": {
417                  *  "id": "INTEGER",
418                  *  "color": "TEXT",
419                  *  "can_id": "INTEGER"
420                  * }, "tag": {
421                  *  "id": "INTEGER",
422                  *  "name": "TEXT"
423                  * }, "can_tag": {
424                  *  "id": "INTEGER",
425                  *  "tag_id": "INTEGER",
426                  *  "can_id": "INTEGER"
427                  * }}'
428                  */
429
430                 $d->setTables( $cache );
431
432                 ob_start();
433
434                 R::debug( 1 );
435
436                 $x = $d->dup( $can );
437
438                 $queries = ob_get_contents();
439
440                 ob_end_clean();
441
442                 R::debug( 0 );
443
444                 $len2 = strlen( $queries );
445
446                 asrt( isset( $x->ownCoffee ), TRUE );
447                 asrt( count( $x->ownCoffee ), 1 );
448                 asrt( isset( $x->sharedTag ), TRUE );
449                 asrt( count( $x->sharedTag ), 1 );
450                 asrt( json_encode( $cache ), json_encode( $d->getSchema() ) );
451                 asrt( ( $len1 > $len2 ), TRUE );
452         }
453
454         /**
455          * Test duplication and tainting.
456          *
457          * @return void
458          */
459         public function testDupAndExportNonTainting()
460         {
461                 testpack( 'Dup() and Export() should not taint beans' );
462
463                 $p            = R::dispense( 'page' );
464                 $b            = R::dispense( 'book' );
465
466                 $b->ownPage[] = $p;
467                 $b->title     = 'a';
468
469                 $id           = R::store( $b );
470
471                 $b            = R::load( 'book', $id );
472
473                 asrt( ( !$b->getMeta( 'tainted' ) ), TRUE );
474
475                 R::exportAll( $b );
476
477                 asrt( ( !$b->getMeta( 'tainted' ) ), TRUE );
478
479                 R::dup( $b );
480
481                 asrt( ( !$b->getMeta( 'tainted' ) ), TRUE );
482
483                 testpack( 'Test issue with ownItems and stealing Ids.' );
484
485                 R::nuke();
486                 $bill                  = R::dispense( 'bill' );
487                 $item                  = R::dispense( 'item' );
488                 $element               = R::dispense( 'element' );
489                 $bill->ownItem[]       = $item;
490                 $bill->sharedElement[] = $element;
491                 R::store( $bill );
492                 $bill = R::load( 'bill', 1 );
493                 $bill->ownItem;
494                 $bill->sharedElement;
495                 $copy = R::dup( $bill );
496                 R::store( $copy );
497
498                 $rows = ( R::getAll( 'select * from bill_element' ) );
499                 asrt( count( $rows ), 2 );
500
501                 $rows = ( R::getAll( 'select * from item' ) );
502
503                 foreach ( $rows as $row ) {
504                         asrt( ( $row['bill_id'] > 0 ), TRUE );
505                 }
506
507                 R::nuke();
508
509                 $this->runOnce();
510
511                 R::freeze( TRUE );
512
513                 $this->runOnce( FALSE );
514
515                 R::freeze( FALSE );
516         }
517
518         /**
519          * Test exporting with filters.
520          *
521          * @return void
522          */
523         public function ExportWithFilters()
524         {
525                 testpack( 'Export with filters' );
526
527                 $book      = R::dispense( 'book' );
528                 $pages     = R::dispense( 'page', 2 );
529                 $texts     = R::dispense( 'text', 2 );
530                 $images    = R::dispense( 'image', 2 );
531                 $author    = R::dispense( 'author' );
532                 $pub       = R::dispense( 'publisher' );
533                 $bookmarks = R::dispense( 'bookmark', 2 );
534
535                 $pages[0]->ownText  = array( $texts[0] );
536                 $pages[0]->ownImage = array( $images[0] );
537                 $pages[1]->ownText  = array( $texts[1] );
538                 $pages[1]->ownImage = array( $images[1] );
539
540                 $pages[0]->sharedBookmark[] = $bookmarks[0];
541                 $pages[1]->sharedBookmark[] = $bookmarks[1];
542
543                 $bookmarks[0]->ownNote[] = R::dispense( 'note' )->setAttr( 'text', 'a note' );
544                 $bookmarks[1]->ownNote[] = R::dispense( 'note' )->setAttr( 'text', 'a note' );
545
546                 $book->ownPage = $pages;
547                 $book->author  = $author;
548
549                 $author->publisher = $pub;
550                 $bookID            = R::store( $book );
551
552                 R::getDuplicationManager()->setTables( R::getWriter()->getTables() );
553
554                 $objects = ( R::exportAll( array( $book ), TRUE, array() ) );
555
556                 asrt( isset( $objects[0]['ownPage'] ), TRUE );
557                 asrt( count( $objects[0]['ownPage'] ), 2 );
558                 asrt( isset( $objects[0]['author'] ), TRUE );
559                 asrt( isset( $objects[0]['ownPage'][0]['ownText'] ), TRUE );
560                 asrt( count( $objects[0]['ownPage'][0]['ownText'] ), 1 );
561                 asrt( isset( $objects[0]['ownPage'][0]['ownImage'] ), TRUE );
562                 asrt( count( $objects[0]['ownPage'][0]['ownImage'] ), 1 );
563
564                 $objects = ( R::exportAll( array( $book ), TRUE, array( 'page', 'author', 'text', 'image' ) ) );
565
566                 asrt( isset( $objects[0]['ownPage'] ), TRUE );
567                 asrt( count( $objects[0]['ownPage'] ), 2 );
568                 asrt( isset( $objects[0]['author'] ), TRUE );
569                 asrt( isset( $objects[0]['ownPage'][0]['ownText'] ), TRUE );
570                 asrt( count( $objects[0]['ownPage'][0]['ownText'] ), 1 );
571                 asrt( isset( $objects[0]['ownPage'][0]['ownImage'] ), TRUE );
572                 asrt( count( $objects[0]['ownPage'][0]['ownImage'] ), 1 );
573
574                 $objects = ( R::exportAll( array( $book ), TRUE, 'author' ) );
575
576                 asrt( isset( $objects[0]['ownPage'] ), FALSE );
577                 asrt( isset( $objects[0]['ownPage'][0]['ownText'] ), FALSE );
578
579                 $objects = ( R::exportAll( array( $book ), TRUE, array( 'page' ) ) );
580
581                 asrt( isset( $objects[0]['author'] ), FALSE );
582                 asrt( isset( $objects[0]['ownPage'][0]['ownText'] ), FALSE );
583
584                 $objects = ( R::exportAll( array( $book ), TRUE, array( 'page', 'text' ) ) );
585
586                 asrt( isset( $objects[0]['author'] ), FALSE );
587                 asrt( isset( $objects[0]['ownPage'] ), TRUE );
588                 asrt( isset( $objects[0]['ownPage'][0]['ownText'] ), TRUE );
589                 asrt( count( $objects[0]['ownPage'][0]['ownText'] ), 1 );
590                 asrt( isset( $objects[0]['ownPage'][0]['ownImage'] ), FALSE );
591
592                 $objects = ( R::exportAll( array( $book ), TRUE, array( 'none' ) ) );
593
594                 asrt( isset( $objects[0]['author'] ), FALSE );
595                 asrt( isset( $objects[0]['ownPage'] ), FALSE );
596
597                 $texts = R::find( 'text' );
598
599                 R::getDuplicationManager()->setCacheTables( FALSE );
600
601                 testpack( 'Keyless export' );
602
603                 $book = R::load( 'book', $bookID );
604
605                 $book->ownPage;
606
607                 $export = $book->export();
608
609                 asrt( isset( $export['ownPage'][0] ), TRUE );
610
611         }
612
613         /**
614          * Helper function getCache().
615          *
616          * @return array
617          */
618         private function getCache()
619         {
620                 return array(
621                         'coffee' => array(
622                                 'color' => 'color',
623                                 'id' => 'id',
624                                 'can_id' => 'can_id'
625                         ),
626                         'can' => array(
627                                 'size' => 'size',
628                                 'id' => 'id'
629                         ),
630                         'can_tag' => array(
631                                 'id' => 'id',
632                                 'can_id' => 'can_id',
633                                 'tag_id' => 'tag_id'
634                         ),
635                         'tag' => array(
636                                 'id' => 'id',
637                                 'name' => 'name' )
638                 );
639         }
640
641         /**
642          * Compares object with export
643          *
644          * @param type $object
645          * @param type $array
646          */
647         private function compare( $object, $array )
648         {
649                 foreach ( $object as $property => $value ) {
650                         if ( is_array( $value ) ) {
651                                 foreach ( $value as $index => $nestedObject ) {
652                                         if ( $nestedObject->id ) {
653                                                 $foundMatch = FALSE;
654                                                 //order might be different
655                                                 foreach ( $array[$property] as $k => $a ) {
656                                                         if ( $a['id'] == $nestedObject->id ) {
657                                                                 $foundMatch = TRUE;
658                                                                 $index      = $k;
659                                                         }
660                                                 }
661                                                 if ( !$foundMatch ) throw new\Exception( 'failed to find match for object ' . $nestedObject->id );
662                                         }
663                                         $this->compare( $nestedObject, $array[$property][$index] );
664                                 }
665                         } elseif ( !is_object( $value ) ) {
666                                 asrt( strval( $array[$property] ), strval( $value ) );
667                         }
668                 }
669         }
670
671         /**
672          * Run tests
673          */
674         private function runOnce( $n = TRUE )
675         {
676
677                 $books   = R::dispense( 'book', 10 );
678                 $pages   = R::dispense( 'page', 10 );
679                 $readers = R::dispense( 'reader', 10 );
680                 $texts   = R::dispense( 'text', 10 );
681
682                 $i = 0;
683                 foreach ( $books as $book ) $book->name = 'book-' . ( $i++ );
684                 $i = 0;
685                 foreach ( $pages as $page ) $page->name = 'page-' . ( $i++ );
686                 $i = 0;
687                 foreach ( $readers as $reader ) $reader->name = 'reader-' . ( $i++ );
688                 $i = 0;
689                 foreach ( $texts as $text ) $text->content = 'lorem ipsum -' . ( $i++ );
690
691                 foreach ( $texts as $text ) {
692                         $pages[array_rand( $pages )]->ownText[] = $text;
693                 }
694                 foreach ( $pages as $page ) {
695                         $books[array_rand( $books )]->ownPage[] = $page;
696                 }
697                 foreach ( $readers as $reader ) {
698                         $books[array_rand( $books )]->sharedReader[] = $reader;
699                 }
700                 $i = $noOfReaders = $noOfPages = $noOfTexts = 0;
701                 foreach ( $books as $key => $book ) {
702                         $i++;
703                         $noOfPages += count( $book->ownPage );
704                         $noOfReaders += count( $book->sharedReader );
705                         foreach ( $book->ownPage as $page ) $noOfTexts += count( $page->ownText );
706                         $arr = R::exportAll( $book );
707                         echo "\nIntermediate info: " . json_encode( $arr ) . ": Totals = $i,$noOfPages,$noOfReaders,$noOfTexts ";
708
709                         $this->compare( $book, $arr[0] );
710                         $copiedBook      = R::dup( $book );
711                         $copiedBookArray = R::exportAll( $copiedBook );
712                         $this->compare( $book, $copiedBookArray[0] );
713                         $copiedBookArrayII = $copiedBook->export();
714                         $this->compare( $book, $copiedBookArrayII );
715                         $copyFromCopy      = R::dup( $copiedBook );
716                         $copyFromCopyArray = R::exportAll( $copyFromCopy );
717                         $this->compare( $book, $copyFromCopyArray[0] );
718                         $copyFromCopyArrayII = $copyFromCopy->export();
719                         $this->compare( $book, $copyFromCopyArrayII );
720                         $id         = R::store( $book );
721                         $copiedBook = R::dup( $book );
722                         R::store( $book ); //should not be damaged
723                         $copiedBookArray   = R::exportAll( $copiedBook );
724                         $originalBookArray = R::exportAll( $book );
725                         $this->compare( $copiedBook, $copiedBookArray[0] );
726                         $this->compare( $book, $originalBookArray[0] );
727                         $book = R::load( 'book', $id );
728                         $this->compare( $book, $originalBookArray[0] );
729                         $copiedBook = R::dup( $book );
730                         $this->compare( $copiedBook, $copiedBook->export() );
731                         R::store( $copiedBook );
732                         $this->compare( $copiedBook, $copiedBook->export() );
733                         $copyFromCopy = R::dup( $copiedBook );
734                         $this->compare( $copyFromCopy, $copyFromCopy->export() );
735                         R::store( $copyFromCopy );
736                         $newPage                 = R::dispense( 'page' );
737                         $newPage->name           = 'new';
738                         $copyFromCopy->ownPage[] = $newPage;
739                         $modifiedCopy            = R::dup( $copyFromCopy );
740                         $exportMod               = R::exportAll( $modifiedCopy );
741                         $this->compare( $modifiedCopy, $exportMod[0] );
742                         asrt( count( $modifiedCopy->ownPage ), count( $copiedBook->ownPage ) + 1 );
743                         R::store( $modifiedCopy );
744
745                         if ( $n ) {
746                                 asrt( (int) R::getCell( 'SELECT count(*) FROM book' ), $i * 4 );
747                                 asrt( (int) R::getCell( 'SELECT count(*) FROM page' ), ( $noOfPages * 4 ) + $i );
748                                 asrt( (int) R::getCell( 'SELECT count(*) FROM text' ), $noOfTexts * 4 );
749                                 asrt( (int) R::getCell( 'SELECT count(*) FROM book_reader' ), $noOfReaders * 4 );
750                                 asrt( (int) R::getCell( 'SELECT count(*) FROM reader' ), $noOfReaders );
751                         }
752                 }
753
754                 if ( $n ) {
755                         asrt( $noOfTexts, 10 );
756                         asrt( $noOfReaders, 10 );
757                         asrt( $noOfPages, 10 );
758                         asrt( $i, 10 );
759                 }
760         }
761 }