3 # This file is part of Koha.
5 # Koha is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
10 # Koha is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with Koha; if not, see <http://www.gnu.org/licenses>.
24 use C4::Biblio qw( AddBiblio ModBiblio DelBiblio GetMarcBiblio );
27 use Test::More tests => 23;
30 use Koha::MarcOverlayRules;
34 my $schema = Koha::Database->schema;
35 $schema->storage->txn_begin;
37 t::lib::Mocks::mock_preference('MARCOverlayRules', '1');
40 my $orig_record = MARC::Record->new();
41 $orig_record->append_fields (
42 MARC::Field->new('250', '','', 'a' => '250 bottles of beer on the wall'),
43 MARC::Field->new('250', '','', 'a' => '256 bottles of beer on the wall'),
44 MARC::Field->new('500', '','', 'a' => 'One bottle of beer in the fridge'),
47 my $incoming_record = MARC::Record->new();
48 $incoming_record->append_fields(
49 MARC::Field->new('250', '', '', 'a' => '256 bottles of beer on the wall'), # Unchanged
50 MARC::Field->new('250', '', '', 'a' => '251 bottles of beer on the wall'), # Appended
51 # MARC::Field->new('250', '', '', 'a' => '250 bottles of beer on the wall'), # Removed
52 # MARC::Field->new('500', '', '', 'a' => 'One bottle of beer in the fridge'), # Deleted
53 MARC::Field->new('501', '', '', 'a' => 'One cold bottle of beer in the fridge'), # Added
54 MARC::Field->new('501', '', '', 'a' => 'Two cold bottles of beer in the fridge'), # Added
57 # Test default behavior when MARCOverlayRules is enabled, but no rules defined (overwrite)
58 subtest 'Record fields has been overwritten when no merge rules are defined' => sub {
61 my $merged_record = Koha::MarcOverlayRules->merge_records($orig_record, $incoming_record, { 'source' => 'test' });
63 my @all_fields = $merged_record->fields();
65 cmp_ok(scalar @all_fields, '==', 4, "Record has the expected number of fields");
67 [map { $_->subfield('a') } $merged_record->field('250') ],
68 ['256 bottles of beer on the wall', '251 bottles of beer on the wall'],
69 '"250" fields has been appended and removed'
72 my @fields = $merged_record->field('500');
73 cmp_ok(scalar @fields, '==', 0, '"500" field has been deleted');
76 [map { $_->subfield('a') } $merged_record->field('501') ],
77 ['One cold bottle of beer in the fridge', 'Two cold bottles of beer in the fridge'],
78 '"501" fields has been added'
82 my $rule = Koha::MarcOverlayRules->find_or_create({
92 subtest 'Record fields has been protected when matched merge all rule operations are set to "0"' => sub {
95 my $merged_record = Koha::MarcOverlayRules->merge_records($orig_record, $incoming_record, { 'source' => 'test' });
97 my @all_fields = $merged_record->fields();
98 cmp_ok(scalar @all_fields, '==', 3, "Record has the expected number of fields");
101 [map { $_->subfield('a') } $merged_record->field('250') ],
102 ['250 bottles of beer on the wall', '256 bottles of beer on the wall'],
103 '"250" fields has retained their original value'
106 [map { $_->subfield('a') } $merged_record->field('500') ],
107 ['One bottle of beer in the fridge'],
108 '"500" field has retained it\'s original value'
112 subtest 'Only new fields has been added when add = 1, append = 0, remove = 0, delete = 0' => sub {
125 my $merged_record = Koha::MarcOverlayRules->merge_records($orig_record, $incoming_record, { 'source' => 'test' });
127 my @all_fields = $merged_record->fields();
128 cmp_ok(scalar @all_fields, '==', 5, "Record has the expected number of fields");
131 [map { $_->subfield('a') } $merged_record->field('250') ],
132 ['250 bottles of beer on the wall', '256 bottles of beer on the wall'],
133 '"250" fields retain their original value'
137 [map { $_->subfield('a') } $merged_record->field('500') ],
138 ['One bottle of beer in the fridge'],
139 '"500" field retain it\'s original value'
143 [map { $_->subfield('a') } $merged_record->field('501') ],
144 ['One cold bottle of beer in the fridge', 'Two cold bottles of beer in the fridge'],
145 '"501" fields has been added'
149 subtest 'Only appended fields has been added when add = 0, append = 1, remove = 0, delete = 0' => sub {
162 my $merged_record = Koha::MarcOverlayRules->merge_records($orig_record, $incoming_record, { 'source' => 'test' });
164 my @all_fields = $merged_record->fields();
165 cmp_ok(scalar @all_fields, '==', 4, "Record has the expected number of fields");
168 [map { $_->subfield('a') } $merged_record->field('250') ],
169 ['250 bottles of beer on the wall', '256 bottles of beer on the wall', '251 bottles of beer on the wall'],
170 '"251" field has been appended'
174 [map { $_->subfield('a') } $merged_record->field('500') ],
175 ['One bottle of beer in the fridge'],
176 '"500" field has retained it\'s original value'
181 subtest 'Appended and added fields has been added when add = 1, append = 1, remove = 0, delete = 0' => sub {
194 my $merged_record = Koha::MarcOverlayRules->merge_records($orig_record, $incoming_record, { 'source' => 'test' });
196 my @all_fields = $merged_record->fields();
197 cmp_ok(scalar @all_fields, '==', 6, "Record has the expected number of fields");
200 [map { $_->subfield('a') } $merged_record->field('250') ],
201 ['250 bottles of beer on the wall', '256 bottles of beer on the wall', '251 bottles of beer on the wall'],
202 '"251" field has been appended'
206 [map { $_->subfield('a') } $merged_record->field('500') ],
207 ['One bottle of beer in the fridge'],
208 '"500" field has retained it\'s original value'
212 [map { $_->subfield('a') } $merged_record->field('501') ],
213 ['One cold bottle of beer in the fridge', 'Two cold bottles of beer in the fridge'],
214 '"501" fields has been added'
218 subtest 'Record fields has been only removed when add = 0, append = 0, remove = 1, delete = 0' => sub {
231 my $merged_record = Koha::MarcOverlayRules->merge_records($orig_record, $incoming_record, { 'source' => 'test' });
233 my @all_fields = $merged_record->fields();
234 cmp_ok(scalar @all_fields, '==', 2, "Record has the expected number of fields");
237 [map { $_->subfield('a') } $merged_record->field('250') ],
238 ['256 bottles of beer on the wall'],
239 '"250" field has been removed'
242 [map { $_->subfield('a') } $merged_record->field('500') ],
243 ['One bottle of beer in the fridge'],
244 '"500" field has retained it\'s original value'
248 subtest 'Record fields has been added and removed when add = 1, append = 0, remove = 1, delete = 0' => sub {
261 my $merged_record = Koha::MarcOverlayRules->merge_records($orig_record, $incoming_record, { 'source' => 'test' });
263 my @all_fields = $merged_record->fields();
264 cmp_ok(scalar @all_fields, '==', 4, "Record has the expected number of fields");
267 [map { $_->subfield('a') } $merged_record->field('250') ],
268 ['256 bottles of beer on the wall'],
269 '"250" field has been removed'
272 [map { $_->subfield('a') } $merged_record->field('500') ],
273 ['One bottle of beer in the fridge'],
274 '"500" field has retained it\'s original value'
278 [map { $_->subfield('a') } $merged_record->field('501') ],
279 ['One cold bottle of beer in the fridge', 'Two cold bottles of beer in the fridge'],
280 '"501" fields has been added'
284 subtest 'Record fields has been appended and removed when add = 0, append = 1, remove = 1, delete = 0' => sub {
297 my $merged_record = Koha::MarcOverlayRules->merge_records($orig_record, $incoming_record, { 'source' => 'test' });
299 my @all_fields = $merged_record->fields();
300 cmp_ok(scalar @all_fields, '==', 3, "Record has the expected number of fields");
303 [map { $_->subfield('a') } $merged_record->field('250') ],
304 ['256 bottles of beer on the wall', '251 bottles of beer on the wall'],
305 '"250" fields has been appended and removed'
308 [map { $_->subfield('a') } $merged_record->field('500') ],
309 ['One bottle of beer in the fridge'],
310 '"500" field has retained it\'s original value'
314 subtest 'Record fields has been added, appended and removed when add = 0, append = 1, remove = 1, delete = 0' => sub {
327 my $merged_record = Koha::MarcOverlayRules->merge_records($orig_record, $incoming_record, { 'source' => 'test' });
329 my @all_fields = $merged_record->fields();
330 cmp_ok(scalar @all_fields, '==', 5, "Record has the expected number of fields");
333 [map { $_->subfield('a') } $merged_record->field('250') ],
334 ['256 bottles of beer on the wall', '251 bottles of beer on the wall'],
335 '"250" fields has been appended and removed'
339 [map { $_->subfield('a') } $merged_record->field('500') ],
340 ['One bottle of beer in the fridge'],
341 '"500" field has retained it\'s original value'
345 [map { $_->subfield('a') } $merged_record->field('501') ],
346 ['One cold bottle of beer in the fridge', 'Two cold bottles of beer in the fridge'],
347 '"501" fields has been added'
351 subtest 'Record fields has been deleted when add = 0, append = 0, remove = 0, delete = 1' => sub {
364 my $merged_record = Koha::MarcOverlayRules->merge_records($orig_record, $incoming_record, { 'source' => 'test' });
366 my @all_fields = $merged_record->fields();
367 cmp_ok(scalar @all_fields, '==', 2, "Record has the expected number of fields");
370 [map { $_->subfield('a') } $merged_record->field('250') ],
371 ['250 bottles of beer on the wall', '256 bottles of beer on the wall'],
372 '"250" fields has retained their original value'
376 subtest 'Record fields has been added and deleted when add = 1, append = 0, remove = 0, delete = 1' => sub {
389 my $merged_record = Koha::MarcOverlayRules->merge_records($orig_record, $incoming_record, { 'source' => 'test' });
391 my @all_fields = $merged_record->fields();
392 cmp_ok(scalar @all_fields, '==', 4, "Record has the expected number of fields");
395 [map { $_->subfield('a') } $merged_record->field('250') ],
396 ['250 bottles of beer on the wall', '256 bottles of beer on the wall'],
397 '"250" fields has retained their original value'
401 [map { $_->subfield('a') } $merged_record->field('501') ],
402 ['One cold bottle of beer in the fridge', 'Two cold bottles of beer in the fridge'],
403 '"501" fields has been added'
407 subtest 'Record fields has been appended and deleted when add = 0, append = 1, remove = 0, delete = 1' => sub {
420 my $merged_record = Koha::MarcOverlayRules->merge_records($orig_record, $incoming_record, { 'source' => 'test' });
422 my @all_fields = $merged_record->fields();
423 cmp_ok(scalar @all_fields, '==', 3, "Record has the expected number of fields");
426 [map { $_->subfield('a') } $merged_record->field('250') ],
427 ['250 bottles of beer on the wall', '256 bottles of beer on the wall', '251 bottles of beer on the wall'],
428 '"250" field has been appended'
432 subtest 'Record fields has been added, appended and deleted when add = 1, append = 1, remove = 0, delete = 1' => sub {
445 my $merged_record = Koha::MarcOverlayRules->merge_records($orig_record, $incoming_record, { 'source' => 'test' });
447 my @all_fields = $merged_record->fields();
448 cmp_ok(scalar @all_fields, '==', 5, "Record has the expected number of fields");
451 [map { $_->subfield('a') } $merged_record->field('250') ],
452 ['250 bottles of beer on the wall', '256 bottles of beer on the wall', '251 bottles of beer on the wall'],
453 '"250" field has been appended'
457 [map { $_->subfield('a') } $merged_record->field('501') ],
458 ['One cold bottle of beer in the fridge', 'Two cold bottles of beer in the fridge'],
459 '"501" fields has been added'
463 subtest 'Record fields has been removed and deleted when add = 0, append = 0, remove = 1, delete = 1' => sub {
476 my $merged_record = Koha::MarcOverlayRules->merge_records($orig_record, $incoming_record, { 'source' => 'test' });
478 my @all_fields = $merged_record->fields();
479 cmp_ok(scalar @all_fields, '==', 1, "Record has the expected number of fields");
482 [map { $_->subfield('a') } $merged_record->field('250') ],
483 ['256 bottles of beer on the wall'],
484 '"250" field has been removed'
488 subtest 'Record fields has been added, removed and deleted when add = 1, append = 0, remove = 1, delete = 1' => sub {
501 my $merged_record = Koha::MarcOverlayRules->merge_records($orig_record, $incoming_record, { 'source' => 'test' });
503 my @all_fields = $merged_record->fields();
504 cmp_ok(scalar @all_fields, '==', 3, "Record has the expected number of fields");
507 [map { $_->subfield('a') } $merged_record->field('250') ],
508 ['256 bottles of beer on the wall'],
509 '"250" field has been removed'
513 [map { $_->subfield('a') } $merged_record->field('501') ],
514 ['One cold bottle of beer in the fridge', 'Two cold bottles of beer in the fridge'],
515 '"501" fields has been added'
519 subtest 'Record fields has been appended, removed and deleted when add = 0, append = 1, remove = 1, delete = 1' => sub {
532 my $merged_record = Koha::MarcOverlayRules->merge_records($orig_record, $incoming_record, { 'source' => 'test' });
534 my @all_fields = $merged_record->fields();
535 cmp_ok(scalar @all_fields, '==', 2, "Record has the expected number of fields");
538 [map { $_->subfield('a') } $merged_record->field('250') ],
539 ['256 bottles of beer on the wall', '251 bottles of beer on the wall'],
540 '"250" fields has been appended and removed'
544 subtest 'Record fields has been overwritten when add = 1, append = 1, remove = 1, delete = 1' => sub {
557 my $merged_record = Koha::MarcOverlayRules->merge_records($orig_record, $incoming_record, { 'source' => 'test' });
559 my @all_fields = $merged_record->fields();
561 cmp_ok(scalar @all_fields, '==', 4, "Record has the expected number of fields");
563 [map { $_->subfield('a') } $merged_record->field('250') ],
564 ['256 bottles of beer on the wall', '251 bottles of beer on the wall'],
565 '"250" fields has been appended and removed'
568 my @fields = $merged_record->field('500');
569 cmp_ok(scalar @fields, '==', 0, '"500" field has been deleted');
572 [map { $_->subfield('a') } $merged_record->field('501') ],
573 ['One cold bottle of beer in the fridge', 'Two cold bottles of beer in the fridge'],
574 '"501" fields has been added'
578 # Test rule tag specificity
580 # Protect field 500 with more specific tag value
581 my $skip_all_rule = Koha::MarcOverlayRules->find_or_create({
591 subtest '"500" field has been protected when rule matching on tag "500" is add = 0, append = 0, remove = 0, delete = 0' => sub {
594 my $merged_record = Koha::MarcOverlayRules->merge_records($orig_record, $incoming_record, { 'source' => 'test' });
596 my @all_fields = $merged_record->fields();
598 cmp_ok(scalar @all_fields, '==', 5, "Record has the expected number of fields");
600 [map { $_->subfield('a') } $merged_record->field('250') ],
601 ['256 bottles of beer on the wall', '251 bottles of beer on the wall'],
602 '"250" fields has been appended and removed'
606 [map { $_->subfield('a') } $merged_record->field('500') ],
607 ['One bottle of beer in the fridge'],
608 '"500" field has retained it\'s original value'
612 [map { $_->subfield('a') } $merged_record->field('501') ],
613 ['One cold bottle of beer in the fridge', 'Two cold bottles of beer in the fridge'],
614 '"501" fields has been added'
618 # Test regexp matching
619 subtest '"5XX" fields has been protected when rule matching on regexp "5\d{2}" is add = 0, append = 0, remove = 0, delete = 0' => sub {
627 $skip_all_rule->store();
629 my $merged_record = Koha::MarcOverlayRules->merge_records($orig_record, $incoming_record, { 'source' => 'test' });
631 my @all_fields = $merged_record->fields();
633 cmp_ok(scalar @all_fields, '==', 3, "Record has the expected number of fields");
635 [map { $_->subfield('a') } $merged_record->field('250') ],
636 ['256 bottles of beer on the wall', '251 bottles of beer on the wall'],
637 '"250" fields has been appended and removed'
641 [map { $_->subfield('a') } $merged_record->field('500') ],
642 ['One bottle of beer in the fridge'],
643 '"500" field has retained it\'s original value'
647 # Test module specificity, the 0 all rule should no longer be included in set of applied rules
648 subtest 'Record fields has been overwritten when non wild card rule with filter match is add = 1, append = 1, remove = 1, delete = 1' => sub {
658 my $merged_record = Koha::MarcOverlayRules->merge_records($orig_record, $incoming_record, { 'source' => 'test' });
660 my @all_fields = $merged_record->fields();
662 cmp_ok(scalar @all_fields, '==', 4, "Record has the expected number of fields");
664 [map { $_->subfield('a') } $merged_record->field('250') ],
665 ['256 bottles of beer on the wall', '251 bottles of beer on the wall'],
666 '"250" fields has been appended and removed'
669 my @fields = $merged_record->field('500');
670 cmp_ok(scalar @fields, '==', 0, '"500" field has been deleted');
673 [map { $_->subfield('a') } $merged_record->field('501') ],
674 ['One cold bottle of beer in the fridge', 'Two cold bottles of beer in the fridge'],
675 '"501" fields has been added'
679 subtest 'An exception is thrown when append = 1, remove = 0 is set for control field rule' => sub {
681 my $exception = try {
682 Koha::MarcOverlayRules->validate({
691 ok(defined $exception, "Exception was caught");
692 ok($exception->isa('Koha::Exceptions::MarcOverlayRule::InvalidControlFieldActions'), "Exception is of correct class");
695 subtest 'An exception is thrown when rule tag is set to invalid regexp' => sub {
698 my $exception = try {
699 Koha::MarcOverlayRules->validate({
706 ok(defined $exception, "Exception was caught");
707 ok($exception->isa('Koha::Exceptions::MarcOverlayRule::InvalidTagRegExp'), "Exception is of correct class");
710 $skip_all_rule->delete();
712 subtest 'context option in ModBiblio is handled correctly' => sub {
726 my ($biblionumber) = AddBiblio($orig_record, '');
728 # Since marc merc rules are not run on save, only update
729 # saved record should be identical to orig_record
730 my $saved_record = GetMarcBiblio({ biblionumber => $biblionumber });
732 my @all_fields = $saved_record->fields();
733 # Koha also adds 999c field, therefore 4 not 3
734 cmp_ok(scalar @all_fields, '==', 4, 'Saved record has the expected number of fields');
736 [map { $_->subfield('a') } $saved_record->field('250') ],
737 ['250 bottles of beer on the wall', '256 bottles of beer on the wall'],
738 'All "250" fields of saved record are identical to original record passed to AddBiblio'
742 [map { $_->subfield('a') } $saved_record->field('500') ],
743 ['One bottle of beer in the fridge'],
744 'All "500" fields of saved record are identical to original record passed to AddBiblio'
747 $saved_record->append_fields(
748 MARC::Field->new('250', '', '', 'a' => '251 bottles of beer on the wall'), # Appended
749 MARC::Field->new('500', '', '', 'a' => 'One cold bottle of beer in the fridge'), # Appended
752 ModBiblio($saved_record, $biblionumber, '', { context => { 'source' => 'test' } });
754 my $updated_record = GetMarcBiblio({ biblionumber => $biblionumber });
756 @all_fields = $updated_record->fields();
757 cmp_ok(scalar @all_fields, '==', 5, 'Updated record has the expected number of fields');
759 [map { $_->subfield('a') } $updated_record->field('250') ],
760 ['250 bottles of beer on the wall', '256 bottles of beer on the wall'],
761 '"250" fields have retained their original values'
765 [map { $_->subfield('a') } $updated_record->field('500') ],
766 ['One bottle of beer in the fridge', 'One cold bottle of beer in the fridge'],
767 '"500" field has been appended'
770 # To trigger removal from search index etc
771 DelBiblio($biblionumber);
774 # Explicityly delete rule to trigger clearing of cache
777 $schema->storage->txn_rollback;