Bug 19532: (follow-up) aria-hidden attr on OPAC, and more
[koha.git] / t / db_dependent / Koha / Objects.t
1 #!/usr/bin/perl
2
3 # Copyright 2019 Koha Development team
4 #
5 # This file is part of Koha
6 #
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20 use Modern::Perl;
21
22 use Test::More tests => 23;
23 use Test::Exception;
24 use Test::MockModule;
25 use Test::Warn;
26
27 use C4::Context;
28
29 use Koha::Authority::Types;
30 use Koha::Cities;
31 use Koha::Biblios;
32 use Koha::Patron::Category;
33 use Koha::Patron::Categories;
34 use Koha::Patrons;
35 use Koha::Database;
36 use Koha::DateUtils qw( dt_from_string );
37
38 use t::lib::TestBuilder;
39 use t::lib::Mocks;
40
41 use Try::Tiny;
42
43 my $schema = Koha::Database->new->schema;
44 $schema->storage->txn_begin;
45 my $builder = t::lib::TestBuilder->new;
46
47 is( ref(Koha::Authority::Types->find('')), 'Koha::Authority::Type', 'Koha::Objects->find should work if the primary key is an empty string' );
48
49 my @columns = Koha::Patrons->columns;
50 my $borrowernumber_exists = grep { /^borrowernumber$/ } @columns;
51 is( $borrowernumber_exists, 1, 'Koha::Objects->columns should return the table columns' );
52
53 subtest 'find' => sub {
54     plan tests => 6;
55     my $patron = $builder->build({source => 'Borrower'});
56     my $patron_object = Koha::Patrons->find( $patron->{borrowernumber} );
57     is( $patron_object->borrowernumber, $patron->{borrowernumber}, '->find should return the correct object' );
58
59     my @patrons = Koha::Patrons->find( $patron->{borrowernumber} );
60     is(scalar @patrons, 1, '->find in list context returns a value');
61     is($patrons[0]->borrowernumber, $patron->{borrowernumber}, '->find in list context returns the same value as in scalar context');
62
63     my $patrons = {
64         foo => Koha::Patrons->find('foo'),
65         bar => 'baz',
66     };
67     is ($patrons->{foo}, undef, '->find in list context returns undef when no record is found');
68
69     # Test sending undef to find; should not generate a warning
70     warning_is { $patron = Koha::Patrons->find( undef ); }
71         "", "Sending undef does not trigger a DBIx warning";
72     warning_is { $patron = Koha::Patrons->find( undef, undef ); }
73         "", "Sending two undefs does not trigger a DBIx warning too";
74 };
75
76 subtest 'update' => sub {
77     plan tests => 2;
78
79     $builder->build( { source => 'City', value => { city_country => 'UK' } } );
80     $builder->build( { source => 'City', value => { city_country => 'UK' } } );
81     $builder->build( { source => 'City', value => { city_country => 'UK' } } );
82     $builder->build( { source => 'City', value => { city_country => 'France' } } );
83     $builder->build( { source => 'City', value => { city_country => 'France' } } );
84     $builder->build( { source => 'City', value => { city_country => 'Germany' } } );
85     Koha::Cities->search( { city_country => 'UK' } )->update( { city_country => 'EU' } );
86     is( Koha::Cities->search( { city_country => 'EU' } )->count, 3, 'Koha::Objects->update should have updated the 3 rows' );
87     is( Koha::Cities->search( { city_country => 'UK' } )->count, 0, 'Koha::Objects->update should have updated the 3 rows' );
88 };
89
90 subtest 'reset' => sub {
91     plan tests => 3;
92
93     my $patrons = Koha::Patrons->search;
94     my $first_borrowernumber = $patrons->next->borrowernumber;
95     my $second_borrowernumber = $patrons->next->borrowernumber;
96     is( ref( $patrons->reset ), 'Koha::Patrons', 'Koha::Objects->reset should allow chaining' );
97     is( ref( $patrons->reset->next ), 'Koha::Patron', 'Koha::Objects->reset should allow chaining' );
98     is( $patrons->reset->next->borrowernumber, $first_borrowernumber, 'Koha::Objects->reset should work as expected');
99 };
100
101 subtest 'delete' => sub {
102     plan tests => 2;
103
104     my $patron_1 = $builder->build({source => 'Borrower'});
105     my $patron_2 = $builder->build({source => 'Borrower'});
106     is( Koha::Patrons->search({ -or => { borrowernumber => [ $patron_1->{borrowernumber}, $patron_2->{borrowernumber}]}})->delete, 2, '');
107     is( Koha::Patrons->search({ -or => { borrowernumber => [ $patron_1->{borrowernumber}, $patron_2->{borrowernumber}]}})->count, 0, '');
108 };
109
110 subtest 'new' => sub {
111     plan tests => 2;
112     my $a_cat_code = 'A_CAT_CODE';
113     my $patron_category = Koha::Patron::Category->new( { categorycode => $a_cat_code } )->store;
114     is( Koha::Patron::Categories->find($a_cat_code)->category_type, 'A', 'Koha::Object->new should set the default value' );
115     Koha::Patron::Categories->find($a_cat_code)->delete;
116     $patron_category = Koha::Patron::Category->new( { categorycode => $a_cat_code, category_type => undef } )->store;
117     is( Koha::Patron::Categories->find($a_cat_code)->category_type, 'A', 'Koha::Object->new should set the default value even if the argument exists but is not defined' );
118     Koha::Patron::Categories->find($a_cat_code)->delete;
119 };
120
121 subtest 'find' => sub {
122     plan tests => 4;
123
124     # check find on a single PK
125     my $patron = $builder->build({ source => 'Borrower' });
126     is( Koha::Patrons->find($patron->{borrowernumber})->surname,
127         $patron->{surname}, "Checking an arbitrary patron column after find"
128     );
129     # check find with unique column
130     my $obj = Koha::Patrons->find($patron->{cardnumber}, { key => 'cardnumber' });
131     is( $obj->borrowernumber, $patron->{borrowernumber},
132         'Find with unique column and key specified' );
133     # check find with an additional where clause in the attrs hash
134     # we do not expect to find something now
135     is( Koha::Patrons->find(
136         $patron->{borrowernumber},
137         { where => { surname => { '!=', $patron->{surname} }}},
138     ), undef, 'Additional where clause in find call' );
139
140     is( Koha::Patrons->find(), undef, 'Find returns undef if no params passed' );
141 };
142
143 subtest 'search_related' => sub {
144
145     plan tests => 3;
146
147     my $builder   = t::lib::TestBuilder->new;
148     my $patron_1  = $builder->build( { source => 'Borrower' } );
149     my $patron_2  = $builder->build( { source => 'Borrower' } );
150     my $libraries = Koha::Patrons->search(
151         {
152             -or => {
153                 borrowernumber =>
154                   [ $patron_1->{borrowernumber}, $patron_2->{borrowernumber} ]
155             }
156         }
157     )->search_related('branchcode');
158     is( ref($libraries), 'Koha::Libraries',
159         'Koha::Objects->search_related should return an instanciated Koha::Objects-based object'
160     );
161     is( $libraries->count, 2,
162         'Koha::Objects->search_related should work as expected' );
163     ok( eq_array(
164         [ $libraries->get_column('branchcode') ],
165         [ $patron_1->{branchcode}, $patron_2->{branchcode} ] ),
166         'Koha::Objects->search_related should work as expected'
167     );
168 };
169
170 subtest 'single' => sub {
171     plan tests => 2;
172     my $builder   = t::lib::TestBuilder->new;
173     my $patron_1  = $builder->build( { source => 'Borrower' } );
174     my $patron_2  = $builder->build( { source => 'Borrower' } );
175     my $patron = Koha::Patrons->search({}, { rows => 1 })->single;
176     is(ref($patron), 'Koha::Patron', 'Koha::Objects->single returns a single Koha::Patron object.');
177     warning_like { Koha::Patrons->search->single } qr/SQL that returns multiple rows/,
178     "Warning is presented if single is used for a result with multiple rows.";
179 };
180
181 subtest 'last' => sub {
182     plan tests => 3;
183     my $builder = t::lib::TestBuilder->new;
184     my $patron_1  = $builder->build( { source => 'Borrower' } );
185     my $patron_2  = $builder->build( { source => 'Borrower' } );
186     my $last_patron = Koha::Patrons->search->last;
187     is( $last_patron->borrowernumber, $patron_2->{borrowernumber}, '->last should return the last inserted patron' );
188     $last_patron = Koha::Patrons->search({ borrowernumber => $patron_1->{borrowernumber} })->last;
189     is( $last_patron->borrowernumber, $patron_1->{borrowernumber}, '->last should work even if there is only 1 result' );
190     $last_patron = Koha::Patrons->search({ surname => 'should_not_exist' })->last;
191     is( $last_patron, undef, '->last should return undef if search does not return any results' );
192 };
193
194 subtest 'get_column' => sub {
195     plan tests => 1;
196     my @cities = Koha::Cities->search->as_list;
197     my @city_names = map { $_->city_name } @cities;
198     is_deeply( [ Koha::Cities->search->get_column('city_name') ], \@city_names, 'Koha::Objects->get_column should be allowed' );
199 };
200
201 subtest 'Exceptions' => sub {
202     plan tests => 7;
203
204     my $patron_borrowernumber = $builder->build({ source => 'Borrower' })->{ borrowernumber };
205     my $patron = Koha::Patrons->find( $patron_borrowernumber );
206
207     # Koha::Object
208     try {
209         $patron->blah('blah');
210     } catch {
211         ok( $_->isa('Koha::Exceptions::Object::MethodNotCoveredByTests'),
212             'Calling a non-covered method should raise a Koha::Exceptions::Object::MethodNotCoveredByTests exception' );
213         is( $_->message, 'The method Koha::Patron->blah is not covered by tests!', 'The message raised should contain the package and the method' );
214     };
215
216     try {
217         $patron->set({ blah => 'blah' });
218     } catch {
219         ok( $_->isa('Koha::Exceptions::Object::PropertyNotFound'),
220             'Setting a non-existent property should raise a Koha::Exceptions::Object::PropertyNotFound exception' );
221     };
222
223     # Koha::Objects
224     try {
225         Koha::Patrons->search->not_covered_yet;
226     } catch {
227         ok( $_->isa('Koha::Exceptions::Object::MethodNotCoveredByTests'),
228             'Calling a non-covered method should raise a Koha::Exceptions::Object::MethodNotCoveredByTests exception' );
229         is( $_->message, 'The method Koha::Patrons->not_covered_yet is not covered by tests!', 'The message raised should contain the package and the method' );
230     };
231
232     try {
233         Koha::Patrons->not_covered_yet;
234     } catch {
235         ok( $_->isa('Koha::Exceptions::Object::MethodNotCoveredByTests'),
236             'Calling a non-covered method should raise a Koha::Exceptions::Object::MethodNotCoveredByTests exception' );
237         is( $_->message, 'The method Koha::Patrons->not_covered_yet is not covered by tests!', 'The message raised should contain the package and the method' );
238     };
239 };
240
241 $schema->storage->txn_rollback;
242
243 subtest '->is_paged and ->pager tests' => sub {
244
245     plan tests => 5;
246
247     $schema->storage->txn_begin;
248
249     # Count existing patrons
250     my $nb_patrons = Koha::Patrons->search()->count;
251     # Create 10 more patrons
252     foreach (1..10) {
253         $builder->build_object({ class => 'Koha::Patrons' });
254     }
255
256     # Non-paginated search
257     my $patrons = Koha::Patrons->search();
258     is( $patrons->count, $nb_patrons + 10, 'Search returns all patrons' );
259     ok( !$patrons->is_paged, 'Search is not paged' );
260
261     # Paginated search
262     $patrons = Koha::Patrons->search( undef, { 'page' => 1, 'rows' => 3 } );
263     is( $patrons->count, 3, 'Search returns only one page, 3 patrons' );
264     ok( $patrons->is_paged, 'Search is paged' );
265     my $pager = $patrons->pager;
266     is( ref($patrons->pager), 'DBIx::Class::ResultSet::Pager',
267        'Koha::Objects->pager returns a valid DBIx::Class object' );
268
269     $schema->storage->txn_rollback;
270 };
271
272 subtest "to_api() tests" => sub {
273
274     plan tests => 19;
275
276     $schema->storage->txn_begin;
277
278     my $city_1 = $builder->build_object( { class => 'Koha::Cities' } );
279     my $city_2 = $builder->build_object( { class => 'Koha::Cities' } );
280
281     my $cities = Koha::Cities->search(
282         {
283             cityid => [ $city_1->cityid, $city_2->cityid ]
284         },
285         { -orderby => { -desc => 'cityid' } }
286     );
287
288     is( $cities->count, 2, 'Count is correct' );
289     my $cities_api = $cities->to_api;
290     is( ref( $cities_api ), 'ARRAY', 'to_api returns an array' );
291     is_deeply( $cities_api->[0], $city_1->to_api, 'to_api returns the individual objects with ->to_api' );
292     is_deeply( $cities_api->[1], $city_2->to_api, 'to_api returns the individual objects with ->to_api' );
293
294     my $biblio_1 = $builder->build_sample_biblio();
295     my $item_1   = $builder->build_sample_item({ biblionumber => $biblio_1->biblionumber });
296     my $hold_1   = $builder->build_object(
297         {
298             class => 'Koha::Holds',
299             value => { itemnumber => $item_1->itemnumber }
300         }
301     );
302
303     my $biblio_2 = $builder->build_sample_biblio();
304     my $item_2   = $builder->build_sample_item({ biblionumber => $biblio_2->biblionumber });
305     my $hold_2   = $builder->build_object(
306         {
307             class => 'Koha::Holds',
308             value => { itemnumber => $item_2->itemnumber }
309         }
310     );
311
312     my $embed = { 'items' => {} };
313
314     my $i = 0;
315     my @items = ( $item_1, $item_2 );
316     my @holds = ( $hold_1, $hold_2 );
317
318     my $biblios_api = Koha::Biblios->search(
319         {
320             biblionumber => [ $biblio_1->biblionumber, $biblio_2->biblionumber ]
321         }
322     )->to_api( { embed => $embed } );
323
324     foreach my $biblio_api ( @{ $biblios_api } ) {
325         ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
326         is($biblio_api->{items}->[0]->{item_id}, $items[$i]->itemnumber, 'Item matches');
327         ok(!exists $biblio_api->{items}->[0]->{holds}, 'No holds info should be embedded yet');
328
329         $i++;
330     }
331
332     # One more level
333     $embed = {
334         'items' => {
335             children => { 'holds' => {} }
336         }
337     };
338
339     $i = 0;
340
341     $biblios_api = Koha::Biblios->search(
342         {
343             biblionumber => [ $biblio_1->biblionumber, $biblio_2->biblionumber ]
344         }
345     )->to_api( { embed => $embed } );
346
347     foreach my $biblio_api ( @{ $biblios_api } ) {
348
349         ok(exists $biblio_api->{items}, 'Items where embedded in biblio results');
350         is($biblio_api->{items}->[0]->{item_id}, $items[$i]->itemnumber, 'Item still matches');
351         ok(exists $biblio_api->{items}->[0]->{holds}, 'Holds info should be embedded');
352         is($biblio_api->{items}->[0]->{holds}->[0]->{hold_id}, $holds[$i]->reserve_id, 'Hold matches');
353
354         $i++;
355     }
356
357     subtest 'unprivileged request tests' => sub {
358
359         my @all_attrs = Koha::Libraries->columns();
360         my $public_attrs = { map { $_ => 1 } @{ Koha::Library->public_read_list() } };
361         my $mapping = Koha::Library->to_api_mapping;
362
363         # Create sample libraries
364         my $library_1 = $builder->build_object({ class => 'Koha::Libraries' });
365         my $library_2 = $builder->build_object({ class => 'Koha::Libraries' });
366         my $libraries = Koha::Libraries->search(
367             {
368                 branchcode => {
369                     '-in' => [
370                         $library_1->branchcode, $library_2->branchcode
371                     ]
372                 }
373             }
374         );
375
376         plan tests => scalar @all_attrs * 2 * $libraries->count;
377
378         my $libraries_unprivileged_representation = $libraries->to_api({ public => 1 });
379         my $libraries_privileged_representation   = $libraries->to_api();
380
381         for (my $i = 0; $i < $libraries->count; $i++) {
382             my $privileged_representation   = $libraries_privileged_representation->[$i];
383             my $unprivileged_representation = $libraries_unprivileged_representation->[$i];
384             foreach my $attr (@all_attrs) {
385                 my $mapped = exists $mapping->{$attr} ? $mapping->{$attr} : $attr;
386                 if ( defined($mapped) ) {
387                     ok(
388                         exists $privileged_representation->{$mapped},
389                         "Attribute '$attr' is present when privileged"
390                     );
391                     if ( exists $public_attrs->{$attr} ) {
392                         ok(
393                             exists $unprivileged_representation->{$mapped},
394                             "Attribute '$attr' is present when public"
395                         );
396                     }
397                     else {
398                         ok(
399                             !exists $unprivileged_representation->{$mapped},
400                             "Attribute '$attr' is not present when public"
401                         );
402                     }
403                 }
404                 else {
405                     ok(
406                         !exists $privileged_representation->{$attr},
407                         "Unmapped attribute '$attr' is not present when privileged"
408                     );
409                     ok(
410                         !exists $unprivileged_representation->{$attr},
411                         "Unmapped attribute '$attr' is not present when public"
412                     );
413                 }
414             }
415         }
416     };
417
418
419     $schema->storage->txn_rollback;
420 };
421
422 subtest "TO_JSON() tests" => sub {
423
424     plan tests => 4;
425
426     $schema->storage->txn_begin;
427
428     my $city_1 = $builder->build_object( { class => 'Koha::Cities' } );
429     my $city_2 = $builder->build_object( { class => 'Koha::Cities' } );
430
431     my $cities = Koha::Cities->search(
432         {
433             cityid => [ $city_1->cityid, $city_2->cityid ]
434         },
435         { -orderby => { -desc => 'cityid' } }
436     );
437
438     is( $cities->count, 2, 'Count is correct' );
439     my $cities_json = $cities->TO_JSON;
440     is( ref($cities_json), 'ARRAY', 'to_api returns an array' );
441     is_deeply( $cities_json->[0], $city_1->TO_JSON, 'TO_JSON returns the individual objects with ->TO_JSON' );
442     is_deeply( $cities_json->[1], $city_2->TO_JSON,'TO_JSON returns the individual objects with ->TO_JSON' );
443
444     $schema->storage->txn_rollback;
445 };
446
447 # Koha::Object[s] must behave the same as DBIx::Class
448 subtest 'Return same values as DBIx::Class' => sub {
449     plan tests => 2;
450
451     subtest 'Delete' => sub {
452         plan tests => 2;
453
454         $schema->storage->txn_begin;
455
456         subtest 'Simple Koha::Objects - Koha::Cities' => sub {
457             plan tests => 2;
458
459             subtest 'Koha::Object->delete' => sub {
460
461                 plan tests => 5;
462
463                 my ( $r_us, $e_us, $r_them, $e_them );
464
465                 # CASE 1 - Delete an existing object
466                 my $c = Koha::City->new( { city_name => 'city4test' } )->store;
467                 try { $r_us = $c->delete; } catch { $e_us = $_ };
468                 $c = $schema->resultset('City')->new( { city_name => 'city4test_2' } )->update_or_insert;
469                 try { $r_them = $c->delete; } catch { $e_them = $_ };
470                 ok( ref($r_us) && ref($r_them),
471                     'Successful delete should return the object ' );
472                 ok( !defined $e_us && !defined $e_them,
473                     'Successful delete should not raise an exception' );
474                 is( ref($r_us), 'Koha::City', 'Successful delete should return our Koha::Obect based object' );
475
476                 # CASE 2 - Delete an object that is not in storage
477                 try { $r_us   = $r_us->delete;   } catch { $e_us   = $_ };
478                 try { $r_them = $r_them->delete; } catch { $e_them = $_ };
479                 ok(
480                     defined $e_us && defined $e_them,
481                     'Delete an object that is not in storage should raise an exception'
482                 );
483                 is( ref($e_us), 'DBIx::Class::Exception' )
484                   ; # FIXME This needs adjustement, we want to throw a Koha::Exception
485
486             };
487
488             subtest 'Koha::Objects->delete' => sub {
489
490                 plan tests => 4;
491
492                 my ( $r_us, $e_us, $r_them, $e_them );
493
494                 # CASE 1 - Delete existing objects
495                 my $city_1 = $builder->build_object({ class => 'Koha::Cities' });
496                 my $city_2 = $builder->build_object({ class => 'Koha::Cities' });
497                 my $city_3 = $builder->build_object({ class => 'Koha::Cities' });
498                 my $cities = Koha::Cities->search(
499                     {
500                         cityid => {
501                             -in => [
502                                 $city_1->cityid,
503                                 $city_2->cityid,
504                                 $city_3->cityid,
505                             ]
506                         }
507                     }
508                 );
509
510                 try { $r_us = $cities->delete; } catch { $e_us = $_ };
511
512                 $city_1 = $builder->build_object({ class => 'Koha::Cities' });
513                 $city_2 = $builder->build_object({ class => 'Koha::Cities' });
514                 $city_3 = $builder->build_object({ class => 'Koha::Cities' });
515                 $cities = $schema->resultset('City')->search(
516                     {
517                         cityid => {
518                             -in => [
519                                 $city_1->cityid,
520                                 $city_2->cityid,
521                                 $city_3->cityid,
522                             ]
523                         }
524                     }
525                 );
526
527                 try { $r_them = $cities->delete; } catch { $e_them = $_ };
528
529                 ok( $r_us == 3 && $r_them == 3 );
530                 ok (!defined($e_us) && !defined($e_them));
531
532                 # CASE 2 - One of the object is not in storage
533                 $city_1 = $builder->build_object({ class => 'Koha::Cities' });
534                 $city_2 = $builder->build_object({ class => 'Koha::Cities' });
535                 $city_3 = $builder->build_object({ class => 'Koha::Cities' });
536                 $cities = Koha::Cities->search(
537                     {
538                         cityid => {
539                             -in => [
540                                 $city_1->cityid,
541                                 $city_2->cityid,
542                                 $city_3->cityid,
543                             ]
544                         }
545                     }
546                 );
547
548                 $city_2->delete; # We delete one of the object
549                 try { $r_us = $cities->delete; } catch { $e_us = $_ };
550
551                 $city_1 = $builder->build_object({ class => 'Koha::Cities' });
552                 $city_2 = $builder->build_object({ class => 'Koha::Cities' });
553                 $city_3 = $builder->build_object({ class => 'Koha::Cities' });
554                 $cities = $schema->resultset('City')->search(
555                     {
556                         cityid => {
557                             -in => [
558                                 $city_1->cityid,
559                                 $city_2->cityid,
560                                 $city_3->cityid,
561                             ]
562                         }
563                     }
564                 );
565
566                 $city_2->delete; # We delete one of the object
567                 try { $r_them = $cities->delete; } catch { $e_them = $_ };
568
569                 ok( $r_us == 2 && $r_them == 2 );
570                 ok (!defined($e_us) && !defined($e_them));
571             };
572         };
573
574         subtest 'Overwritten Koha::Objects->delete - Koha::Patrons' => sub {
575
576             plan tests => 2;
577
578             subtest 'Koha::Object->delete' => sub {
579
580                 plan tests => 7;
581
582                 my ( $r_us, $e_us, $r_them, $e_them );
583
584                 # CASE 1 - Delete an existing patron
585                 my $patron = $builder->build_object({ class => 'Koha::Patrons' });
586                 my $patron_data = $patron->unblessed;
587                 $patron->delete;
588
589                 $patron = Koha::Patron->new( $patron_data )->store;
590                 try {$r_us = $patron->delete;} catch { $e_us = $_ };
591                 $patron = $schema->resultset('Borrower')->new( $patron_data )->update_or_insert;
592                 try {$r_them = $patron->delete;} catch { $e_them = $_ };
593                 ok( ref($r_us) && ref($r_them),
594                     'Successful delete should return the patron object' );
595                 ok( !defined $e_us && !defined $e_them,
596                     'Successful delete should not raise an exception' );
597                 is( ref($r_us), 'Koha::Patron',
598                     'Successful delete should return our Koha::Obect based object' );
599
600                 # CASE 2 - Delete a patron that is not in storage
601                 try { $r_us   = $r_us->delete;   } catch { $e_us   = $_ };
602                 try { $r_them = $r_them->delete; } catch { $e_them = $_ };
603                 ok(
604                     defined $e_us && defined $e_them,
605                     'Delete a patron that is not in storage should raise an exception'
606                 );
607                 is( ref($e_us), 'DBIx::Class::Exception' )
608                   ; # FIXME This needs adjustement, we want to throw a Koha::Exception
609
610                 # CASE 3 - Delete a patron that cannot be deleted (as a checkout)
611                 $patron = Koha::Patron->new($patron_data)->store;
612                 $builder->build_object(
613                     {
614                         class => 'Koha::Checkouts',
615                         value => { borrowernumber => $patron->borrowernumber }
616                     }
617                 );
618                 try { $r_us = $r_us->delete; } catch { $e_us = $_ };
619                 $patron = $schema->resultset('Borrower')->find( $patron->borrowernumber );
620                 try { $r_them = $r_them->delete; } catch { $e_them = $_ };
621                 ok(
622                     defined $e_us && defined $e_them,
623                     'Delete a patron that cannot be deleted should raise an exception'
624                 );
625                 is( ref($e_us), 'DBIx::Class::Exception' )
626                   ; # FIXME This needs adjustement, we want to throw a Koha::Exception
627             };
628
629             subtest 'Koha::Objects->delete' => sub {
630
631                 plan tests => 7;
632
633                 my ( $r_us, $e_us, $r_them, $e_them );
634
635                 # CASE 1 - Delete existing objects
636                 my $patron_1 = $builder->build_object({ class => 'Koha::Patrons' });
637                 my $patron_2 = $builder->build_object({ class => 'Koha::Patrons' });
638                 my $patron_3 = $builder->build_object({ class => 'Koha::Patrons' });
639                 my $patrons = Koha::Patrons->search(
640                     {
641                         borrowernumber => {
642                             -in => [
643                                 $patron_1->borrowernumber,
644                                 $patron_2->borrowernumber,
645                                 $patron_3->borrowernumber
646                             ]
647                         }
648                     }
649                 );
650
651                 try { $r_us = $patrons->delete; } catch { $e_us = $_ };
652
653                 $patron_1 = $builder->build_object({ class => 'Koha::Patrons' });
654                 $patron_2 = $builder->build_object({ class => 'Koha::Patrons' });
655                 $patron_3 = $builder->build_object({ class => 'Koha::Patrons' });
656                 $patrons = $schema->resultset('Borrower')->search(
657                     {
658                         borrowernumber => {
659                             -in => [
660                                 $patron_1->borrowernumber,
661                                 $patron_2->borrowernumber,
662                                 $patron_3->borrowernumber
663                             ]
664                         }
665                     }
666                 );
667
668                 try { $r_them = $patrons->delete; } catch { $e_them = $_ };
669
670                 ok( $r_us == 3 && $r_them == 3, '->delete should return the number of deleted patrons' );
671                 ok (!defined($e_us) && !defined($e_them), '->delete should not raise exception if everything went well');
672
673                 # CASE 2 - One of the patrons is not in storage
674                 undef $_ for $r_us, $e_us, $r_them, $e_them;
675                 $patron_1 = $builder->build_object({ class => 'Koha::Patrons' });
676                 $patron_2 = $builder->build_object({ class => 'Koha::Patrons' });
677                 $patron_3 = $builder->build_object({ class => 'Koha::Patrons' });
678                 $patrons = Koha::Patrons->search(
679                     {
680                         borrowernumber => {
681                             -in => [
682                                 $patron_1->borrowernumber,
683                                 $patron_2->borrowernumber,
684                                 $patron_3->borrowernumber
685                             ]
686                         }
687                     }
688                 );
689
690                 $patron_2->delete; # We delete one of the patron
691                 try { $r_us = $patrons->delete; } catch { $e_us = $_ };
692
693                 $patron_1 = $builder->build_object({ class => 'Koha::Patrons' });
694                 $patron_2 = $builder->build_object({ class => 'Koha::Patrons' });
695                 $patron_3 = $builder->build_object({ class => 'Koha::Patrons' });
696                 $patrons = $schema->resultset('Borrower')->search(
697                     {
698                         borrowernumber => {
699                             -in => [
700                                 $patron_1->borrowernumber,
701                                 $patron_2->borrowernumber,
702                                 $patron_3->borrowernumber
703                             ]
704                         }
705                     }
706                 );
707
708                 $patron_2->delete; # We delete one of the patron
709                 try { $r_them = $patrons->delete; } catch { $e_them = $_ };
710
711                 ok( $r_us == 2 && $r_them == 2, 'Delete patrons with one that was not in storage should delete the patrons' );
712                 ok (!defined($e_us) && !defined($e_them), 'no exception should be raised if at least one patron was not in storage');
713
714                 # CASE 3 - Delete a set of patrons with one that that cannot be deleted (as a checkout)
715                 undef $_ for $r_us, $e_us, $r_them, $e_them;
716                 $patron_1 = $builder->build_object({ class => 'Koha::Patrons' });
717                 $patron_2 = $builder->build_object({ class => 'Koha::Patrons' });
718                 $patron_3 = $builder->build_object({ class => 'Koha::Patrons' });
719                 $patrons = Koha::Patrons->search(
720                     {
721                         borrowernumber => {
722                             -in => [
723                                 $patron_1->borrowernumber,
724                                 $patron_2->borrowernumber,
725                                 $patron_3->borrowernumber
726                             ]
727                         }
728                     }
729                 );
730
731                 # Adding a checkout to patron_2
732                 $builder->build_object(
733                     {
734                         class => 'Koha::Checkouts',
735                         value => { borrowernumber => $patron_2->borrowernumber }
736                     }
737                 );
738
739                 try { $r_us = $patrons->delete; } catch { $e_us = $_ };
740                 my $not_deleted_us = $patron_1->in_storage + $patron_2->in_storage + $patron_3->in_storage;
741
742                 $patron_1 = $builder->build_object({ class => 'Koha::Patrons' });
743                 $patron_2 = $builder->build_object({ class => 'Koha::Patrons' });
744                 $patron_3 = $builder->build_object({ class => 'Koha::Patrons' });
745                 $patrons = $schema->resultset('Borrower')->search(
746                     {
747                         borrowernumber => {
748                             -in => [
749                                 $patron_1->borrowernumber,
750                                 $patron_2->borrowernumber,
751                                 $patron_3->borrowernumber
752                             ]
753                         }
754                     }
755                 );
756
757                 # Adding a checkout to patron_2
758                 $builder->build_object(
759                     {
760                         class => 'Koha::Checkouts',
761                         value => { borrowernumber => $patron_2->borrowernumber }
762                     }
763                 );
764
765                 try { $r_them = $patrons->delete; } catch { $e_them = $_ };
766
767                 my $not_deleted_them = $patron_1->in_storage + $patron_2->in_storage + $patron_3->in_storage;
768                 ok(
769                     defined $e_us && defined $e_them,
770                     'Delete patrons with one that cannot be deleted should raise an exception'
771                 );
772                 is( ref($e_us), 'DBIx::Class::Exception' )
773                   ; # FIXME This needs adjustement, we want to throw a Koha::Exception
774
775                 ok($not_deleted_us == 3 && $not_deleted_them == 3, 'If one patron cannot be deleted, none should have been deleted');
776             };
777         };
778
779         $schema->storage->txn_rollback;
780
781     };
782
783     subtest 'Update (set/store)' => sub {
784         plan tests => 2;
785
786         $schema->storage->txn_begin;
787
788         subtest 'Simple Koha::Objects - Koha::Cities' => sub {
789             plan tests => 2;
790
791             subtest 'Koha::Object->update' => sub {
792
793                 plan tests => 5;
794
795                 my ( $r_us, $e_us, $r_them, $e_them );
796
797                 # CASE 1 - Update an existing object
798                 my $c_us = Koha::City->new( { city_name => 'city4test' } )->store;
799                 try { $r_us = $c_us->update({ city_country => 'country4test' }); } catch { $e_us = $_ };
800                 my $c_them = $schema->resultset('City')->new( { city_name => 'city4test_2' } )->update_or_insert;
801                 try { $r_them = $c_them->update({ city_country => 'country4test_2' }); } catch { $e_them = $_ };
802                 ok( ref($r_us) && ref($r_them),
803                     'Successful update should return the object ' );
804                 ok( !defined $e_us && !defined $e_them,
805                     'Successful update should not raise an exception' );
806                 is( ref($r_us), 'Koha::City', 'Successful update should return our Koha::Obect based object' );
807
808                 # CASE 2 - Update an object that is not in storage
809                 $c_us->delete;
810                 $c_them->delete;
811                 try { $r_us   = $c_us->update({ city_country => 'another_country' });   } catch { $e_us   = $_ };
812                 try { $r_them = $c_them->update({ city_country => 'another_country' }); } catch { $e_them = $_ };
813                 ok(
814                     defined $e_us && defined $e_them,
815                     'Update an object that is not in storage should raise an exception'
816                 );
817                 is( ref($e_us), 'Koha::Exceptions::Object::NotInStorage' );
818             };
819
820             subtest 'Koha::Objects->update' => sub {
821
822                 plan tests => 6;
823
824                 my ( $r_us, $e_us, $r_them, $e_them );
825
826                 # CASE 1 - update existing objects
827                 my $city_1 = $builder->build_object({ class => 'Koha::Cities' });
828                 my $city_2 = $builder->build_object({ class => 'Koha::Cities' });
829                 my $city_3 = $builder->build_object({ class => 'Koha::Cities' });
830                 my $cities = Koha::Cities->search(
831                     {
832                         cityid => {
833                             -in => [
834                                 $city_1->cityid,
835                                 $city_2->cityid,
836                                 $city_3->cityid,
837                             ]
838                         }
839                     }
840                 );
841
842                 try { $r_us = $cities->update({ city_country => 'country4test' }); } catch { $e_us = $_ };
843
844                 $city_1 = $builder->build_object({ class => 'Koha::Cities' });
845                 $city_2 = $builder->build_object({ class => 'Koha::Cities' });
846                 $city_3 = $builder->build_object({ class => 'Koha::Cities' });
847                 $cities = $schema->resultset('City')->search(
848                     {
849                         cityid => {
850                             -in => [
851                                 $city_1->cityid,
852                                 $city_2->cityid,
853                                 $city_3->cityid,
854                             ]
855                         }
856                     }
857                 );
858
859                 try { $r_them = $cities->update({ city_country => 'country4test' }); } catch { $e_them = $_ };
860
861                 ok( $r_us == 3 && $r_them == 3, '->update should return the number of updated cities' );
862                 ok(!defined($e_us) && !defined($e_them));
863
864                 # CASE 2 - One of the object is not in storage
865                 $city_1 = $builder->build_object({ class => 'Koha::Cities' });
866                 $city_2 = $builder->build_object({ class => 'Koha::Cities' });
867                 $city_3 = $builder->build_object({ class => 'Koha::Cities' });
868                 $cities = Koha::Cities->search(
869                     {
870                         cityid => {
871                             -in => [
872                                 $city_1->cityid,
873                                 $city_2->cityid,
874                                 $city_3->cityid,
875                             ]
876                         }
877                     }
878                 );
879
880                 $city_2->delete; # We delete one of the object
881                 try { $r_us = $cities->update({ city_country => 'country4test' }); } catch { $e_us = $_ };
882
883                 $city_1 = $builder->build_object({ class => 'Koha::Cities' });
884                 $city_2 = $builder->build_object({ class => 'Koha::Cities' });
885                 $city_3 = $builder->build_object({ class => 'Koha::Cities' });
886                 $cities = $schema->resultset('City')->search(
887                     {
888                         cityid => {
889                             -in => [
890                                 $city_1->cityid,
891                                 $city_2->cityid,
892                                 $city_3->cityid,
893                             ]
894                         }
895                     }
896                 );
897
898                 $city_2->delete; # We delete one of the object
899                 try { $r_them = $cities->update({ city_country => 'country4test' }); } catch { $e_them = $_ };
900
901                 ok( $r_us == 2 && $r_them == 2, '->update should return the number of updated cities' );
902                 ok(!defined($e_us) && !defined($e_them));
903
904                 throws_ok
905                     { Koha::Cities->update({ city_country => 'Castalia' }); }
906                     'Koha::Exceptions::Object::NotInstantiated',
907                     'Exception thrown if not instantiated class';
908
909                 is( "$@", 'Tried to access the \'update\' method, but Koha::Cities is not instantiated', 'Exception stringified correctly' );
910
911             };
912         };
913
914         subtest 'Overwritten Koha::Objects->store|update - Koha::Patrons' => sub {
915
916             plan tests => 2;
917
918             subtest 'Koha::Object->update' => sub {
919
920                 plan tests => 5;
921
922                 my ( $r_us, $e_us, $r_them, $e_them );
923
924                 # CASE 1 - Update an existing patron
925                 my $patron_us = $builder->build_object({ class => 'Koha::Patrons' });
926                 try {$r_us = $patron_us->update({city => 'a_city'});} catch { $e_us = $_ };
927
928                 my $patron_data = $builder->build_object({ class => 'Koha::Patrons' })->delete->unblessed;
929                 my $patron_them = $schema->resultset('Borrower')->new( $patron_data )->update_or_insert;
930                 try {$r_them = $patron_them->update({city => 'a_city'});} catch { $e_them = $_ };
931                 ok( ref($r_us) && ref($r_them),
932                     'Successful update should return the patron object' );
933                 ok( !defined $e_us && !defined $e_them,
934                     'Successful update should not raise an exception' );
935                 is( ref($r_us), 'Koha::Patron',
936                     'Successful update should return our Koha::Obect based object' );
937
938                 # CASE 2 - Update a patron that is not in storage
939                 $patron_us->delete;
940                 $patron_them->delete;
941                 try { $r_us   = $patron_us->update({ city => 'another_city' });   } catch { $e_us   = $_ };
942                 try { $r_them = $patron_them->update({ city => 'another_city' }); } catch { $e_them = $_ };
943                 ok(
944                     defined $e_us && defined $e_them,
945                     'Update a patron that is not in storage should raise an exception'
946                 );
947                 is( ref($e_us), 'Koha::Exceptions::Object::NotInStorage' );
948
949             };
950
951             subtest 'Koha::Objects->Update ' => sub {
952
953                 plan tests => 6;
954
955                 my ( $r_us, $e_us, $r_them, $e_them );
956
957                 # CASE 1 - Update existing objects
958                 my $patron_1 = $builder->build_object({ class => 'Koha::Patrons' });
959                 my $patron_2 = $builder->build_object({ class => 'Koha::Patrons' });
960                 my $patron_3 = $builder->build_object({ class => 'Koha::Patrons' });
961                 my $patrons_us = Koha::Patrons->search(
962                     {
963                         borrowernumber => {
964                             -in => [
965                                 $patron_1->borrowernumber,
966                                 $patron_2->borrowernumber,
967                                 $patron_3->borrowernumber
968                             ]
969                         }
970                     }
971                 );
972
973                 try { $r_us = $patrons_us->update({ city => 'a_city' }); } catch { $e_us = $_ };
974
975                 $patron_1 = $builder->build_object({ class => 'Koha::Patrons' });
976                 $patron_2 = $builder->build_object({ class => 'Koha::Patrons' });
977                 $patron_3 = $builder->build_object({ class => 'Koha::Patrons' });
978                 my $patrons_them = $schema->resultset('Borrower')->search(
979                     {
980                         borrowernumber => {
981                             -in => [
982                                 $patron_1->borrowernumber,
983                                 $patron_2->borrowernumber,
984                                 $patron_3->borrowernumber
985                             ]
986                         }
987                     }
988                 );
989
990                 try { $r_them = $patrons_them->update({ city => 'a_city' }); } catch { $e_them = $_ };
991
992                 ok( $r_us == 3 && $r_them == 3, '->update should return the number of update patrons' );
993                 ok (!defined($e_us) && !defined($e_them), '->update should not raise exception if everything went well');
994
995                 # CASE 2 - One of the patrons is not in storage
996                 undef $_ for $r_us, $e_us, $r_them, $e_them;
997                 $patron_1 = $builder->build_object({ class => 'Koha::Patrons' });
998                 $patron_2 = $builder->build_object({ class => 'Koha::Patrons' });
999                 $patron_3 = $builder->build_object({ class => 'Koha::Patrons' });
1000                 $patrons_us = Koha::Patrons->search(
1001                     {
1002                         borrowernumber => {
1003                             -in => [
1004                                 $patron_1->borrowernumber,
1005                                 $patron_2->borrowernumber,
1006                                 $patron_3->borrowernumber
1007                             ]
1008                         }
1009                     }
1010                 );
1011
1012                 $patron_2->delete; # We delete one of the patron
1013                 try { $r_us = $patrons_us->update({ city => 'another_city' }); } catch { $e_us = $_ };
1014
1015                 $patron_1 = $builder->build_object({ class => 'Koha::Patrons' });
1016                 $patron_2 = $builder->build_object({ class => 'Koha::Patrons' });
1017                 $patron_3 = $builder->build_object({ class => 'Koha::Patrons' });
1018                 $patrons_them = $schema->resultset('Borrower')->search(
1019                     {
1020                         borrowernumber => {
1021                             -in => [
1022                                 $patron_1->borrowernumber,
1023                                 $patron_2->borrowernumber,
1024                                 $patron_3->borrowernumber
1025                             ]
1026                         }
1027                     }
1028                 );
1029
1030                 $patron_2->delete; # We delete one of the patron
1031                 try { $r_them = $patrons_them->update({ city => 'another_city' }); } catch { $e_them = $_ };
1032
1033                 ok( $r_us == 2 && $r_them == 2, 'Update patrons with one that was not in storage should update the patrons' );
1034                 ok (!defined($e_us) && !defined($e_them), 'no exception should be raised if at least one patron was not in storage');
1035
1036
1037                 # Testing no_triggers
1038                 t::lib::Mocks::mock_preference('uppercasesurnames', 1);
1039                 $patrons_us = Koha::Patrons->search(
1040                     {
1041                         borrowernumber => {
1042                             -in => [
1043                                 $patron_1->borrowernumber,
1044                                 $patron_2->borrowernumber,
1045                                 $patron_3->borrowernumber
1046                             ]
1047                         }
1048                     }
1049                 );
1050                 $patrons_us->update({ surname => 'foo' }); # Koha::Patron->store is supposed to uppercase the surnames
1051                 is( $patrons_us->search({ surname => 'FOO' })->count, 2, 'Koha::Patron->store is hit' );
1052
1053                 $patrons_us->update({ surname => 'foo' }, { no_triggers => 1 }); # The surnames won't be uppercase as we won't hit Koha::Patron->store
1054                 is( $patrons_us->search({ surname => 'foo' })->count, 2, 'Koha::Patron->store is not hit');
1055
1056             };
1057
1058         };
1059
1060         $schema->storage->txn_rollback;
1061
1062     };
1063
1064 };
1065
1066 subtest "attributes_from_api() tests" => sub {
1067
1068     plan tests => 1;
1069
1070     $schema->storage->txn_begin;
1071
1072     my $cities_rs = Koha::Cities->new;
1073     my $city      = Koha::City->new;
1074
1075     my $api_attributes = {
1076         name        => 'Cordoba',
1077         postal_code => 5000
1078     };
1079
1080     is_deeply(
1081         $cities_rs->attributes_from_api($api_attributes),
1082         $city->attributes_from_api($api_attributes)
1083     );
1084
1085     $schema->storage->txn_rollback;
1086
1087 };
1088
1089 subtest "filter_by_last_update" => sub {
1090
1091     $schema->storage->txn_begin;
1092
1093     my $now = dt_from_string->truncate( to => 'day' );
1094     my @borrowernumbers;
1095     # Building 6 patrons that have been created today, yesterday, ... 1 per day
1096     for my $i ( 0 .. 5 ) {
1097         push @borrowernumbers,
1098           $builder->build_object(
1099             {
1100                 class => 'Koha::Patrons',
1101                 value => { updated_on => $now->clone->subtract( days => $i ) }
1102             }
1103           )->borrowernumber;
1104     }
1105
1106     my $patrons = Koha::Patrons->search(
1107         { borrowernumber => { -in => \@borrowernumbers } } );
1108
1109     try {
1110         $patrons->filter_by_last_update( { timestamp_column_name => 'updated_on' } )
1111           ->count;
1112     }
1113     catch {
1114         ok(
1115             $_->isa('Koha::Exceptions::MissingParameter'),
1116             'Should raise an exception if no parameter given'
1117         );
1118     };
1119
1120     my $filtered_patrons = $patrons->filter_by_last_update(
1121         { timestamp_column_name => 'updated_on', days => 2 } );
1122     is( ref($filtered_patrons), 'Koha::Patrons', 'filter_by_last_update must return a Koha::Objects-based object' );
1123
1124     my $count = $patrons->filter_by_last_update(
1125         { timestamp_column_name => 'updated_on', days => 2 } )->count;
1126     is( $count, 3, '3 patrons have been updated before the last 2 days (exclusive)' );
1127
1128     $count = $patrons->filter_by_last_update(
1129         { timestamp_column_name => 'updated_on', days => 2, days_inclusive => 1 } )->count;
1130     is( $count, 4, '4 patrons have been updated before the last 2 days (inclusive)' );
1131
1132     $count = $patrons->filter_by_last_update(
1133         { timestamp_column_name => 'updated_on', days => 1 } )->count;
1134     is( $count, 4, '4 patrons have been updated before yesterday (exclusive)' );
1135
1136     $count = $patrons->filter_by_last_update(
1137         { timestamp_column_name => 'updated_on', days => 1, days_inclusive => 1 } )->count;
1138     is( $count, 5, '5 patrons have been updated before yesterday (inclusive)' );
1139
1140     $count = $patrons->filter_by_last_update(
1141         { timestamp_column_name => 'updated_on', days => 0 } )->count;
1142     is( $count, 5, '5 patrons have been updated before today (exclusive)' );
1143
1144     $count = $patrons->filter_by_last_update(
1145         { timestamp_column_name => 'updated_on', days => 0, days_inclusive => 1 } )->count;
1146     is( $count, 6, '6 patrons have been updated before today (inclusive)' );
1147
1148     $count = $patrons->filter_by_last_update(
1149         { timestamp_column_name => 'updated_on', from => $now } )->count;
1150     is( $count, 1, '1 patron has been updated "from today" (inclusive)' );
1151
1152     $count = $patrons->filter_by_last_update(
1153         { timestamp_column_name => 'updated_on', to => $now } )->count;
1154     is( $count, 6, '6 patrons have been updated "to today" (inclusive)' );
1155
1156     $count = $patrons->filter_by_last_update(
1157         {
1158             timestamp_column_name => 'updated_on',
1159             from                  => $now->clone->subtract( days => 4 ),
1160             to                    => $now->clone->subtract( days => 2 )
1161         }
1162     )->count;
1163     is( $count, 3, '3 patrons have been updated between D-4 and D-2' );
1164
1165     t::lib::Mocks::mock_preference( 'dateformat', 'metric' );
1166     try {
1167         $count = $patrons->filter_by_last_update(
1168             { timestamp_column_name => 'updated_on', from => '1970-12-31' } )
1169           ->count;
1170     }
1171     catch {
1172         ok(
1173             $_->isa(
1174                 'No exception raised, from and to parameters can take an iso formatted date'
1175             )
1176         );
1177     };
1178     try {
1179         $count = $patrons->filter_by_last_update(
1180             { timestamp_column_name => 'updated_on', from => '31/12/1970' } )
1181           ->count;
1182     }
1183     catch {
1184         ok(
1185             $_->isa(
1186                 'No exception raised, from and to parameters can take an metric formatted date (depending on dateformat syspref)'
1187             )
1188         );
1189     };
1190
1191     $schema->storage->txn_rollback;
1192 };
1193
1194 subtest "from_api_mapping() tests" => sub {
1195
1196     plan tests => 1;
1197
1198     $schema->storage->txn_begin;
1199
1200     my $cities_rs = Koha::Cities->new;
1201     my $city      = Koha::City->new;
1202
1203     is_deeply(
1204         $cities_rs->from_api_mapping,
1205         $city->from_api_mapping
1206     );
1207
1208     $schema->storage->txn_rollback;
1209 };
1210
1211 subtest 'prefetch_whitelist() tests' => sub {
1212
1213     plan tests => 3;
1214
1215     $schema->storage->txn_begin;
1216
1217     my $biblios = Koha::Biblios->new;
1218
1219     my $prefetch_whitelist = $biblios->prefetch_whitelist;
1220
1221     ok(
1222         exists $prefetch_whitelist->{orders},
1223         'Relationship matching method name is listed'
1224     );
1225     is(
1226         $prefetch_whitelist->{orders},
1227         'Koha::Acquisition::Order',
1228         'Guessed the non-standard object class correctly'
1229     );
1230
1231     is(
1232         $prefetch_whitelist->{items},
1233         'Koha::Item',
1234         'Guessed the standard object class correctly'
1235     );
1236
1237     $schema->storage->txn_rollback;
1238 };
1239
1240 subtest 'empty() tests' => sub {
1241
1242     plan tests => 6;
1243
1244     $schema->storage->txn_begin;
1245
1246     # Add a patron, we need at least 1
1247     my $patron = $builder->build_object({ class => 'Koha::Patrons' });
1248     ok( Koha::Patrons->count > 0, 'There is at least one Koha::Patron on the resultset' );
1249
1250     my $empty = Koha::Patrons->new->empty;
1251     is( ref($empty), 'Koha::Patrons', '->empty returns a Koha::Patrons iterator' );
1252     is( $empty->count, 0, 'The empty resultset is, well, empty :-D' );
1253
1254     my $new_rs = $empty->search({ borrowernumber => $patron->borrowernumber });
1255
1256     is( $new_rs->count, 0, 'Further chaining an empty resultset, returns an empty resultset' );
1257
1258     throws_ok
1259         { Koha::Patrons->empty; }
1260         'Koha::Exceptions::Object::NotInstantiated',
1261         'Exception thrown if not instantiated class';
1262
1263     is( "$@", 'Tried to access the \'empty\' method, but Koha::Patrons is not instantiated', 'Exception stringified correctly' );
1264
1265     $schema->storage->txn_rollback;
1266 };
1267
1268 subtest 'delete() tests' => sub {
1269
1270     plan tests => 2;
1271
1272     $schema->storage->txn_begin;
1273
1274     # Make sure no cities
1275     warnings_are { Koha::Cities->delete }[],
1276       "No warnings, no Koha::City->delete called as it doesn't exist";
1277
1278     # Mock Koha::City
1279     my $mocked_city = Test::MockModule->new('Koha::City');
1280     $mocked_city->mock(
1281         'delete',
1282         sub {
1283             shift->_result->delete;
1284             warn "delete called!";
1285         }
1286     );
1287
1288     # Add two cities
1289     $builder->build_object( { class => 'Koha::Cities' } );
1290     $builder->build_object( { class => 'Koha::Cities' } );
1291
1292     my $cities = Koha::Cities->search;
1293     $cities->next;
1294     warnings_are { $cities->delete }
1295         [ "delete called!", "delete called!" ],
1296         "No warnings, no Koha::City->delete called as it doesn't exist";
1297
1298     $schema->storage->txn_rollback;
1299 };