From f436b7821922d6d7cc29c7418966c393ef00595f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Cohen=20Arazi?= Date: Mon, 26 Jan 2026 16:30:31 -0300 Subject: [PATCH] Bug 41714: Add tests This patch adds tests for the syspref-controlled behavior. --- installer/data/mysql/mandatory/sysprefs.sql | 2 +- t/db_dependent/Heading.t | 72 +++++++++++- t/db_dependent/Heading/MARC21.t | 117 ++++++++++++++++++++ t/db_dependent/Heading_MARC21.t | 37 ------- 4 files changed, 186 insertions(+), 42 deletions(-) create mode 100755 t/db_dependent/Heading/MARC21.t delete mode 100755 t/db_dependent/Heading_MARC21.t diff --git a/installer/data/mysql/mandatory/sysprefs.sql b/installer/data/mysql/mandatory/sysprefs.sql index 6f96a24f98..c5fcffde00 100644 --- a/installer/data/mysql/mandatory/sysprefs.sql +++ b/installer/data/mysql/mandatory/sysprefs.sql @@ -78,7 +78,6 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` ('AuthoritiesLog','1',NULL,'If ON, log edit/create/delete actions on authorities.','YesNo'), ('AuthorityControlledIndicators','# PERSO_NAME 100 600 696 700 796 800 896\nmarc21, 100, ind1:auth1\nmarc21, 600, ind1:auth1, ind2:thesaurus\nmarc21, 696, ind1:auth1\nmarc21, 700, ind1:auth1\nmarc21, 796, ind1:auth1\nmarc21, 800, ind1:auth1\nmarc21, 896, ind1:auth1\n# CORPO_NAME 110 610 697 710 797 810 897\nmarc21, 110, ind1:auth1\nmarc21, 610, ind1:auth1, ind2:thesaurus\nmarc21, 697, ind1:auth1\nmarc21, 710, ind1:auth1\nmarc21, 797, ind1:auth1\nmarc21, 810, ind1:auth1\nmarc21, 897, ind1:auth1\n# MEETI_NAME 111 611 698 711 798 811 898\nmarc21, 111, ind1:auth1\nmarc21, 611, ind1:auth1, ind2:thesaurus\nmarc21, 698, ind1:auth1\nmarc21, 711, ind1:auth1\nmarc21, 798, ind1:auth1\nmarc21, 811, ind1:auth1\nmarc21, 898, ind1:auth1\n# UNIF_TITLE 130 440 630 699 730 799 830 899\nmarc21, 130, ind1:auth2\nmarc21, 240, , ind2:auth2\nmarc21, 440, , ind2:auth2\nmarc21, 630, ind1:auth2, ind2:thesaurus\nmarc21, 699, ind1:auth2\nmarc21, 730, ind1:auth2\nmarc21, 799, ind1:auth2\nmarc21, 830, , ind2:auth2\nmarc21, 899, ind1:auth2\n# CHRON_TERM 648 \nmarc21, 648, , ind2:thesaurus\n# TOPIC_TERM 650 654 656 657 658 690\nmarc21, 650, , ind2:thesaurus\n# GEOGR_NAME 651 662 691\nmarc21, 651, , ind2:thesaurus\n# GENRE/FORM 655 \nmarc21, 655, , ind2:thesaurus\n\n# UNIMARC: Always copy the indicators from the authority\nunimarc, *, ind1:auth1, ind2:auth2',NULL,'Authority controlled indicators per biblio field','Free'), ('AuthorityMergeLimit','50',NULL,'Maximum number of biblio records updated immediately when an authority record has been modified.','Integer'), -('LinkerUseFrameworkAuthTypes','0',NULL,'Use authority types defined in MARC bibliographic frameworks when linking headings to authorities (MARC21 only). When enabled, the authority type configured in the Default framework will be used instead of the hardcoded MARC21 defaults.','YesNo'), ('AuthorityMergeMode','loose','loose|strict','Authority merge mode','Choice'), ('AuthoritySeparator','--','10','Used to separate a list of authorities in a display. Usually --','free'), ('AuthorityXSLTDetailsDisplay','',NULL,'Enable XSL stylesheet control over authority details page display on intranet','Free'), @@ -399,6 +398,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` ('LinkerModule','Default','Default|FirstMatch|LastMatch','Chooses which linker module to use (see documentation).','Choice'), ('LinkerOptions','',NULL,'A pipe-separated list of options for the linker.','free'), ('LinkerRelink','1',NULL,'If ON the authority linker will relink headings that have previously been linked every time it runs.','YesNo'), +('LinkerUseFrameworkAuthTypes','0',NULL,'Use authority types defined in MARC bibliographic frameworks when linking headings to authorities (MARC21 only). When enabled, the authority type configured in the Default framework will be used instead of the hardcoded MARC21 defaults.','YesNo'), ('ListOwnerDesignated', '', NULL, 'Designated list owner at patron deletion', 'Free'), ('ListOwnershipUponPatronDeletion', 'delete', 'delete|transfer|transfer_public', 'Defines the action on their public or shared lists when patron is deleted', 'Choice'), ('LoadCheckoutsTableDelay','0',NULL,'Delay before auto-loading checkouts table on checkouts screen','Integer'), diff --git a/t/db_dependent/Heading.t b/t/db_dependent/Heading.t index 362528a310..5a382edadb 100755 --- a/t/db_dependent/Heading.t +++ b/t/db_dependent/Heading.t @@ -1,5 +1,5 @@ #!/usr/bin/perl -# + # This file is part of Koha. # # Koha is free software; you can redistribute it and/or modify it @@ -15,15 +15,16 @@ # You should have received a copy of the GNU General Public License # along with Koha; if not, see . -use strict; -use warnings; +use Modern::Perl; use Test::NoWarnings; -use Test::More tests => 6; +use Test::More tests => 7; use open qw/ :std :utf8 /; use t::lib::Mocks; +use t::lib::TestBuilder; + use Test::MockModule; use MARC::Record; @@ -31,6 +32,9 @@ use MARC::Field; use utf8; use C4::AuthoritiesMarc qw/ AddAuthority /; +use Koha::Caches; +use Koha::MarcSubfieldStructures; + BEGIN { use_ok('C4::Heading'); } @@ -403,3 +407,63 @@ subtest "authorities exact match tests" => sub { $schema->storage->txn_rollback; }; + +subtest 'LinkerUseFrameworkAuthTypes' => sub { + plan tests => 2; + + my $schema = Koha::Database->new->schema; + my $cache = Koha::Caches->get_instance; + my $builder = t::lib::TestBuilder->new; + $schema->storage->txn_begin; + + t::lib::Mocks::mock_preference( 'marcflavour', 'MARC21' ); + + subtest 'Preference disabled (default behavior)' => sub { + plan tests => 1; + + t::lib::Mocks::mock_preference( 'LinkerUseFrameworkAuthTypes', 0 ); + + my $field = MARC::Field->new( '650', ' ', '0', a => 'Test subject' ); + my $heading = C4::Heading->new_from_field($field); + + is( $heading->auth_type(), 'TOPIC_TERM', 'Uses hardcoded TOPIC_TERM when preference disabled' ); + }; + + subtest 'Preference enabled with framework override' => sub { + + plan tests => 1; + + t::lib::Mocks::mock_preference( 'LinkerUseFrameworkAuthTypes', 1 ); + + # Delete any existing 650$a in default framework to avoid unique constraint violation + Koha::MarcSubfieldStructures->search( + { + frameworkcode => '', + tagfield => '650', + tagsubfield => 'a', + } + )->delete; + + # Create marc_subfield_structure entry using TestBuilder + my $mss = $builder->build_object( + { + class => 'Koha::MarcSubfieldStructures', + value => { + frameworkcode => '', + tagfield => '650', + tagsubfield => 'a', + } + } + ); + + # Clear all caches + Koha::Caches->get_instance->flush_all; + + my $field = MARC::Field->new( '650', ' ', '0', a => 'Test subject' ); + my $heading = C4::Heading->new_from_field($field); + + is( $heading->auth_type(), $mss->authtypecode, 'Uses framework authority type when enabled' ); + }; + + $schema->storage->txn_rollback; +}; diff --git a/t/db_dependent/Heading/MARC21.t b/t/db_dependent/Heading/MARC21.t new file mode 100755 index 0000000000..27ca377193 --- /dev/null +++ b/t/db_dependent/Heading/MARC21.t @@ -0,0 +1,117 @@ +#!/usr/bin/perl + +# This file is part of Koha +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +use Test::NoWarnings; +use Test::More tests => 6; + +use t::lib::Mocks; +use t::lib::TestBuilder; + +use Koha::Caches; +use Koha::MarcSubfieldStructures; + +BEGIN { + use_ok( 'C4::Heading', qw( new_from_field ) ); +} + +my $schema = Koha::Database->new->schema; +my $builder = t::lib::TestBuilder->new; + +t::lib::Mocks::mock_preference( 'marcflavour', 'MARC21' ); + +subtest 'Display and search forms' => sub { + plan tests => 3; + + my $field = MARC::Field->new( '650', ' ', '2', a => 'Uncles', x => 'Fiction' ); + my $heading = C4::Heading->new_from_field($field); + is( $heading->display_form(), 'Uncles--Fiction', 'Display form generation' ); + is( $heading->search_form(), 'Uncles generalsubdiv Fiction', 'Search form generation' ); + is( $heading->{thesaurus}, 'mesh', 'Thesaurus generation' ); +}; + +subtest 'Uniform titles' => sub { + plan tests => 3; + + my $field = MARC::Field->new( '830', ' ', '4', a => 'The dark is rising ;', v => '3' ); + my $heading = C4::Heading->new_from_field($field); + is( $heading->display_form(), 'The dark is rising ;', 'Display form generation' ); + is( $heading->search_form(), 'The dark is rising', 'Search form generation' ); + ok( !defined $heading->{thesaurus}, 'Thesaurus is not generated outside of 6XX fields' ); +}; + +subtest 'Personal names' => sub { + plan tests => 3; + + my $field = MARC::Field->new( '100', '1', '', a => 'Yankovic, Al', d => '1959-' ); + my $heading = C4::Heading->new_from_field($field); + is( $heading->display_form(), 'Yankovic, Al 1959-', 'Display form generation' ); + is( $heading->search_form(), 'Yankovic, Al 1959', 'Search form generation' ); + ok( !defined $heading->{thesaurus}, 'Thesaurus is not generated outside of 6XX fields' ); +}; + +subtest 'LinkerUseFrameworkAuthTypes' => sub { + plan tests => 3; + + $schema->storage->txn_begin; + + # Test 1: Preference disabled uses hardcoded + t::lib::Mocks::mock_preference( 'LinkerUseFrameworkAuthTypes', 0 ); + my $field = MARC::Field->new( '650', ' ', '0', a => 'Test' ); + my $heading = C4::Heading->new_from_field($field); + is( $heading->auth_type(), 'TOPIC_TERM', 'Uses hardcoded TOPIC_TERM when preference disabled' ); + + # Test 2: Preference enabled with framework override + t::lib::Mocks::mock_preference( 'LinkerUseFrameworkAuthTypes', 1 ); + + # Delete any existing 650$a in default framework to avoid unique constraint violation + Koha::MarcSubfieldStructures->search( + { + frameworkcode => '', + tagfield => '650', + tagsubfield => 'a', + } + )->delete; + + # Create marc_subfield_structure entry using TestBuilder + my $mss = $builder->build_object( + { + class => 'Koha::MarcSubfieldStructures', + value => { + frameworkcode => '', + tagfield => '650', + tagsubfield => 'a', + } + } + ); + + no warnings 'once'; + %C4::Heading::authority_type_cache = (); + Koha::Caches->get_instance->flush_all; + + $field = MARC::Field->new( '650', ' ', '0', a => 'Test' ); + $heading = C4::Heading->new_from_field($field); + is( $heading->auth_type(), $mss->authtypecode, 'Uses framework override when preference enabled' ); + + # Test 3: Falls back to hardcoded for unconfigured tags + $field = MARC::Field->new( '600', ' ', '0', a => 'Person' ); + $heading = C4::Heading->new_from_field($field); + is( $heading->auth_type(), 'PERSO_NAME', 'Falls back to hardcoded for unconfigured tags' ); + + $schema->storage->txn_rollback; +}; diff --git a/t/db_dependent/Heading_MARC21.t b/t/db_dependent/Heading_MARC21.t deleted file mode 100755 index cc3da31eb9..0000000000 --- a/t/db_dependent/Heading_MARC21.t +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/perl -# -# This Koha test module is a stub! -# Add more tests here!!! - -use strict; -use warnings; - -use Test::NoWarnings; -use Test::More tests => 11; -use C4::Context; - -BEGIN { - use_ok( 'C4::Heading', qw( new_from_field ) ); -} - -SKIP: { - skip "MARC21 heading tests not applicable to UNIMARC", 2 if C4::Context->preference('marcflavour') eq 'UNIMARC'; - my $field = MARC::Field->new( '650', ' ', '2', a => 'Uncles', x => 'Fiction' ); - my $heading = C4::Heading->new_from_field($field); - is( $heading->display_form(), 'Uncles--Fiction', 'Display form generation' ); - is( $heading->search_form(), 'Uncles generalsubdiv Fiction', 'Search form generation' ); - is( $heading->{thesaurus}, 'mesh', 'Thesaurus generation' ); - - $field = MARC::Field->new( '830', ' ', '4', a => 'The dark is rising ;', v => '3' ); - $heading = C4::Heading->new_from_field($field); - is( $heading->display_form(), 'The dark is rising ;', 'Display form generation' ); - is( $heading->search_form(), 'The dark is rising', 'Search form generation' ); - ok( !defined $heading->{thesaurus}, 'Thesaurus is not generated outside of 6XX fields' ); - - $field = MARC::Field->new( '100', '1', '', a => 'Yankovic, Al', d => '1959-' ); - $heading = C4::Heading->new_from_field($field); - is( $heading->display_form(), 'Yankovic, Al 1959-', 'Display form generation' ); - is( $heading->search_form(), 'Yankovic, Al 1959', 'Search form generation' ); - ok( !defined $heading->{thesaurus}, 'Thesaurus is not generated outside of 6XX fields' ); - -} -- 2.50.1 (Apple Git-155)