#!/usr/bin/perl

use Modern::Perl;

use Test::More tests => 12;

use_ok("MARC::Field");
use_ok("MARC::Record");
use_ok(
    "Koha::SimpleMARC",
    qw( field_exists read_field update_field copy_field copy_and_replace_field move_field delete_field field_equals update_last_transaction_time )
);

sub new_record {
    my $record = MARC::Record->new;
    $record->leader('03174nam a2200445 a 4500');
    my @fields = (
        MARC::Field->new(
            '008', '120829t20132012nyu bk 001 0ceng',
        ),
        MARC::Field->new(
            100, '1', ' ',
            a => 'Knuth, Donald Ervin',
            d => '1938',
        ),
        MARC::Field->new(
            245, '1', '4',
            a => 'The art of computer programming',
            c => 'Donald E. Knuth.',
        ),
        MARC::Field->new(
            650, ' ', '0',
            a => 'Computer programming.',
            9 => '462',
        ),
        MARC::Field->new(
            952, ' ', ' ',
            p => '3010023917',
            y => 'BK',
            c => 'GEN',
            d => '2001-06-25',
        ),
    );
    $record->append_fields(@fields);
    return $record;
}

# field_exists
subtest 'field_exists' => sub {
    plan tests => 3;
    my $record = new_record;
    is_deeply(
        field_exists( { record => $record, field => '650', subfield => 'a' } ),
        [1],
        '650$a exists'
    );
    is_deeply(
        field_exists( { record => $record, field => '650', subfield => 'b' } ),
        [],
        '650$b does not exist'
    );

    $record->append_fields(
        MARC::Field->new(
            650, ' ', '0',
            a => 'Computer algorithms.',
            9 => '463',
        )
    );

    is_deeply(
        field_exists( { record => $record, field => '650', subfield => 'a' } ),
        [ 1, 2 ],
        '650$a exists, field_exists returns the 2 field numbers'
    );
};

# read_field
subtest 'read_field' => sub {
    plan tests              => 2;
    subtest 'read subfield' => sub {
        plan tests => 6;
        my $record = new_record;
        $record->append_fields(
            MARC::Field->new(
                650, ' ', '0',
                a => 'Computer algorithms.',
                9 => '463',
            ),
            MARC::Field->new(
                600, ' ', '0',
                0 => '123456',
            )
        );

        my @fields_650a =
          read_field( { record => $record, field => '650', subfield => 'a' } );
        is_deeply( $fields_650a[0], 'Computer programming.', 'first 650$a' );
        is_deeply( $fields_650a[1], 'Computer algorithms.',  'second 650$a' );
        is_deeply(
            [
                read_field(
                    {
                        record        => $record,
                        field         => '650',
                        subfield      => 'a',
                        field_numbers => [1]
                    }
                )
            ],
            ['Computer programming.'],
            'first 650$a bis'
        );
        is_deeply(
            [
                read_field(
                    {
                        record        => $record,
                        field         => '650',
                        subfield      => 'a',
                        field_numbers => [2]
                    }
                )
            ],
            ['Computer algorithms.'],
            'second 650$a bis'
        );
        is_deeply(
            [
                read_field(
                    {
                        record        => $record,
                        field         => '650',
                        subfield      => 'a',
                        field_numbers => [3]
                    }
                )
            ],
            [],
            'There is no 3 650$a'
        );
        is_deeply(
            [
                read_field(
                    {
                        record        => $record,
                        field         => '600',
                        subfield      => '0',
                        field_numbers => [1]
                    }
                )
            ],
            ['123456'],
            'first 600$0'
        );
    };
    subtest 'read field' => sub {
        plan tests => 4;
        my $record = new_record;
        $record->append_fields(
            MARC::Field->new(
                650, ' ', '0',
                a => 'Computer algorithms.',
                9 => '463',
            )
        );
        is_deeply(
            [
                read_field(
                    {
                        record => $record,
                        field  => '650'
                    }
                )
            ],
            [ 'Computer programming.', '462', 'Computer algorithms.', '463' ],
            'Get the all subfield values for field 650'
        );
        is_deeply(
            [
                read_field(
                    {
                        record        => $record,
                        field         => '650',
                        field_numbers => [1]
                    }
                )
            ],
            [ 'Computer programming.', '462' ],
            'Get the all subfield values for the first field 650'
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '650', field_numbers => [2] }
                )
            ],
            [ 'Computer algorithms.', '463' ],
            'Get the all subfield values for the second field 650'
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '650', field_numbers => [3] }
                )
            ],
            [],
'Get the all subfield values for the third field 650 which does not exist'
        );
    };
};

# update_field
subtest 'update_field' => sub {
    plan tests                => 1;
    subtest 'update subfield' => sub {
        plan tests => 6;
        my $record = new_record;

        update_field(
            {
                record   => $record,
                field    => '952',
                subfield => 'p',
                values   => ['3010023918']
            }
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '952', subfield => 'p' }
                )
            ],
            ['3010023918'],
            'update existing subfield 952$p'
        );
        delete_field( { record => $record, field => '952' } );
        update_field(
            {
                record   => $record,
                field    => '952',
                subfield => 'p',
                values   => ['3010023918']
            }
        );
        update_field(
            {
                record   => $record,
                field    => '952',
                subfield => 'y',
                values   => ['BK']
            }
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '952', subfield => 'p' }
                )
            ],
            ['3010023918'],
            'create subfield 952$p'
        );
        is_deeply(
            read_field(
                { record => $record, field => '952', subfield => 'y' }
            ),
            'BK',
            'create subfield 952$k on existing 952 field'
        );

        $record->append_fields(
            MARC::Field->new(
                952, ' ', ' ',
                p => '3010023917',
                y => 'BK',
                0 => '123456',
            ),
        );
        update_field(
            {
                record   => $record,
                field    => '952',
                subfield => 'p',
                values   => ['3010023919']
            }
        );
        my @fields_952p =
          read_field( { record => $record, field => '952', subfield => 'p' } );
        is_deeply(
            \@fields_952p,
            [ '3010023919', '3010023919' ],
            'update all subfields 952$p with the same value'
        );

        update_field(
            {
                record   => $record,
                field    => '952',
                subfield => 'p',
                values   => [ '3010023917', '3010023918' ]
            }
        );
        @fields_952p =
          read_field( { record => $record, field => '952', subfield => 'p' } );
        is_deeply(
            \@fields_952p,
            [ '3010023917', '3010023918' ],
            'update all subfields 952$p with the different values'
        );

        update_field(
            {
                record   => $record,
                field    => '952',
                subfield => '0',
                values   => [ '654321' ]
            }
        );
        my @fields_9520 =
          read_field( { record => $record, field => '952', subfield => '0' } );
        is_deeply(
            \@fields_9520,
            [ '654321', '654321' ],
            'update all subfields 952$0 with the same value'
        );

    };
};

# copy_field - subfield
subtest 'copy_field' => sub {
    plan tests              => 2;
    subtest 'copy subfield' => sub {
        plan tests => 21;
        my $record = new_record;
        $record->append_fields(
            MARC::Field->new(
                650, ' ', '0',
                a => 'Computer algorithms.',
                9 => '463',
            )
        );
        copy_field(
            {
                record        => $record,
                from_field    => '245',
                from_subfield => 'a',
                to_field      => '246',
                to_subfield   => 'a'
            }
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '245', subfield => 'a' }
                )
            ],
            ['The art of computer programming'],
            'After copy 245$a still exists'
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '246', subfield => 'a' }
                )
            ],
            ['The art of computer programming'],
            '246$a is a new field'
        );
        delete_field( { record => $record, field => '246' } );
        is_deeply(
            field_exists(
                { record => $record, field => '246', subfield => 'a' }
            ),
            [],
            '246$a does not exist anymore'
        );

        copy_field(
            {
                record        => $record,
                from_field    => '650',
                from_subfield => 'a',
                to_field      => '651',
                to_subfield   => 'a'
            }
        );
        my @fields_651a =
          read_field( { record => $record, field => '651', subfield => 'a' } );
        is_deeply(
            \@fields_651a,
            [ 'Computer algorithms.', 'Computer programming.' ],
            'Copy multivalued field'
        );
        delete_field( { record => $record, field => '651' } );

        copy_field(
            {
                record        => $record,
                from_field    => '650',
                from_subfield => 'a',
                to_field      => '651',
                to_subfield   => 'a',
                field_numbers => [1]
            }
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '651', subfield => 'a' }
                )
            ],
            ['Computer programming.'],
            'Copy first field 650$a'
        );
        delete_field( { record => $record, field => '652' } );

        copy_field(
            {
                record        => $record,
                from_field    => '650',
                from_subfield => 'a',
                to_field      => '651',
                to_subfield   => 'a',
                field_numbers => [2]
            }
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '651', subfield => 'a' }
                )
            ],
            ['Computer programming.', 'Computer algorithms.'],
            'Copy second field 650$a'
        );
        delete_field( { record => $record, field => '651' } );

        copy_field(
            {
                record        => $record,
                from_field    => '650',
                from_subfield => 'a',
                to_field      => '651',
                to_subfield   => 'a',
                regex => { search => 'Computer', replace => 'The art of' }
            }
        );
        @fields_651a =
          read_field( { record => $record, field => '651', subfield => 'a' } );
        is_deeply(
            \@fields_651a,
            [ 'The art of algorithms.', 'The art of programming.' ],
            'Copy field using regex'
        );
        delete_field( { record => $record, field => '651' } );

        copy_field(
            {
                record        => $record,
                from_field    => '650',
                from_subfield => 'a',
                to_field      => '651',
                to_subfield   => 'a',
                regex => { search => 'Computer', replace => 'The mistake of' }
            }
        );
        @fields_651a =
          read_field( { record => $record, field => '651', subfield => 'a' } );
        is_deeply(
            \@fields_651a,
            [ 'The mistake of algorithms.', 'The mistake of programming.' ],
            'Copy fields using regex on existing fields'
        );
        delete_field( { record => $record, field => '651' } );

        copy_field(
            {
                record        => $record,
                from_field    => '650',
                from_subfield => 'a',
                to_field      => '651',
                to_subfield   => 'a',
                regex => { search => 'Computer', replace => 'The art of' }
            }
        );
        @fields_651a =
          read_field( { record => $record, field => '651', subfield => 'a' } );
        is_deeply(
            \@fields_651a,
            [ 'The art of algorithms.', 'The art of programming.', ],
            'Copy all fields using regex'
        );
        delete_field( { record => $record, field => '651' } );

        copy_field(
            {
                record        => $record,
                from_field    => '650',
                from_subfield => 'a',
                to_field      => '651',
                to_subfield   => 'a',
                regex => { search => 'Computer', replace => 'The art of' },
                field_numbers => [1]
            }
        );
        @fields_651a =
          read_field( { record => $record, field => '651', subfield => 'a' } );
        is_deeply(
            \@fields_651a,
            [ 'The art of programming.', ],
            'Copy first field using regex'
        );
        delete_field( { record => $record, field => '651' } );

        # Copy with regex modifiers
        $record = new_record;
        $record->append_fields(
            MARC::Field->new(
                650, ' ', '0',
                a => 'Computer algorithms.',
                9 => '463',
            )
        );
        copy_field(
            {
                record        => $record,
                from_field    => '650',
                from_subfield => 'a',
                to_field      => '652',
                to_subfield   => 'a',
                regex         => { search => 'o', replace => 'foo' }
            }
        );
        my @fields_652a =
          read_field( { record => $record, field => '652', subfield => 'a' } );
        is_deeply(
            \@fields_652a,
            [ 'Cfoomputer algorithms.', 'Cfoomputer programming.' ],
            'Copy field using regex'
        );

        copy_field(
            {
                record        => $record,
                from_field    => '650',
                from_subfield => 'a',
                to_field      => '653',
                to_subfield   => 'a',
                regex => { search => 'o', replace => 'foo', modifiers => 'g' }
            }
        );
        my @fields_653a =
          read_field( { record => $record, field => '653', subfield => 'a' } );
        is_deeply(
            \@fields_653a,
            [ 'Cfoomputer algfoorithms.', 'Cfoomputer prfoogramming.' ],
            'Copy field using regex'
        );

        copy_field(
            {
                record        => $record,
                from_field    => '650',
                from_subfield => 'a',
                to_field      => '654',
                to_subfield   => 'a',
                regex => { search => 'O', replace => 'foo', modifiers => 'i' }
            }
        );
        my @fields_654a =
          read_field( { record => $record, field => '654', subfield => 'a' } );
        is_deeply(
            \@fields_654a,
            [ 'Cfoomputer algorithms.', 'Cfoomputer programming.' ],
            'Copy field using regex'
        );

        copy_field(
            {
                record        => $record,
                from_field    => '650',
                from_subfield => 'a',
                to_field      => '655',
                to_subfield   => 'a',
                regex => { search => 'O', replace => 'foo', modifiers => 'gi' }
            }
        );
        my @fields_655a =
          read_field( { record => $record, field => '655', subfield => 'a' } );
        is_deeply(
            \@fields_655a,
            [ 'Cfoomputer algfoorithms.', 'Cfoomputer prfoogramming.' ],
            'Copy field using regex'
        );

        $record = new_record;
        $record->append_fields(
            MARC::Field->new(
                952, ' ', ' ',
                p => '3010023917',
                y => 'BK',
            ),
        );

        copy_field(
            {
                record        => $record,
                from_field    => '952',
                from_subfield => 'd',
                to_field      => '952',
                to_subfield   => 'd'
            }
        );
        my @fields_952d =
          read_field( { record => $record, field => '952', subfield => 'd' } );
        # FIXME We need a new action "duplicate" if we don't want to modify the original field
        is_deeply(
            \@fields_952d,
            [ '2001-06-25', '2001-06-25', '2001-06-25' ],
            'copy 952$d into others 952 field'
        );

        copy_field(
            {
                record        => $record,
                from_field    => '111',
                from_subfield => '1',
                to_field      => '999',
                to_subfield   => '9'
            }
        );
        my @fields_9999 =
          read_field( { record => $record, field => '999', subfield => '9' } );
        is_deeply( \@fields_9999, [],
            'copy a nonexistent subfield does not create a new one' );

        $record = new_record;
        copy_field(
            {
                record        => $record,
                from_field    => 245,
                from_subfield => 'a',
                to_field      => 245,
                to_subfield   => 'a',
                regex         => { search => '^', replace => 'BEGIN ' }
            }
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '245', subfield => 'a' }
                )
            ],
            ['The art of computer programming', 'BEGIN The art of computer programming'],
            'Update a subfield: add a string at the beginning'
        );

        $record = new_record;
        copy_field(
            {
                record        => $record,
                from_field    => 245,
                from_subfield => 'a',
                to_field      => 245,
                to_subfield   => 'a',
                regex         => { search => '$', replace => ' END' }
            }
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '245', subfield => 'a' }
                )
            ],
            ['The art of computer programming', 'The art of computer programming END'],
            'Update a subfield: add a string at the end'
        );

        $record = new_record;
        copy_field(
            {
                record        => $record,
                from_field    => 245,
                from_subfield => 'a',
                to_field      => 245,
                to_subfield   => 'a',
                regex         => { search => '(art)', replace => 'sm$1 $1' }
            }
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '245', subfield => 'a' }
                )
            ],
            ['The art of computer programming', 'The smart art of computer programming'],
            'Update a subfield: use capture groups'
        );

        $record = new_record;
        copy_field(
            {
                record        => $record,
                from_field    => 245,
                from_subfield => 'c',
                to_field      => 650,
                to_subfield   => 'c',
            }
        );

        is_deeply(
            [
                read_field(
                    { record => $record, field => '650' }
                )
            ],
            [ 'Computer programming.', '462', 'Donald E. Knuth.' ],
            'Copy a subfield to an existent field but inexistent subfield'
        );

        $record = new_record;
        copy_field(
            {
                record        => $record,
                from_field    => 245,
                from_subfield => 'c',
                to_field      => 650,
                to_subfield   => '9',
            }
        );

        is_deeply(
            [
                read_field(
                    { record => $record, field => '650' }
                )
            ],
            [ 'Computer programming.', '462', 'Donald E. Knuth.' ],
            'Copy a subfield to an existent field / subfield'
        );
    };

    subtest 'copy field' => sub {
        plan tests => 14;
        my $record = new_record;
        $record->append_fields(
            MARC::Field->new(
                952, ' ', ' ',
                p => '3010023918',
                y => 'CD',
            ),
        );

        #- copy all fields
        copy_field(
            { record => $record, from_field => '952', to_field => '953' } );
        my @fields_952 = read_field( { record => $record, field => '952' } );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '952', field_numbers => [1] }
                )
            ],
            [ '3010023917', 'BK', 'GEN', '2001-06-25' ],
            "copy all: original first field still exists"
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '952', field_numbers => [2] }
                )
            ],
            [ '3010023918', 'CD' ],
            "copy all: original second field still exists"
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '953', field_numbers => [1] }
                )
            ],
            [ '3010023917', 'BK', 'GEN', '2001-06-25' ],
            "copy all: first original fields has been copied"
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '953', field_numbers => [2] }
                )
            ],
            [ '3010023918', 'CD' ],
            "copy all: second original fields has been copied"
        );

        #- copy only the first field
        copy_field(
            {
                record        => $record,
                from_field    => '953',
                to_field      => '954',
                field_numbers => [1]
            }
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '953', field_numbers => [1] }
                )
            ],
            [ '3010023917', 'BK', 'GEN', '2001-06-25' ],
            "copy first: first original fields has been copied"
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '953', field_numbers => [2] }
                )
            ],
            [ '3010023918', 'CD' ],
            "copy first: second original fields has been copied"
        );
        is_deeply(
            [ read_field( { record => $record, field => '954' } ) ],
            [ '3010023917', 'BK', 'GEN', '2001-06-25' ],
            "copy first: only first, first 953 has been copied"
        );

        $record = new_record;
        $record->append_fields(
            MARC::Field->new(
                952, ' ', ' ',
                p => '3010023918',
                y => 'CD',
            ),
        );

        #- copy all fields and modify values using a regex
        copy_field(
            {
                record     => $record,
                from_field => '952',
                to_field   => '953',
                regex      => { search => '30100', replace => '42424' }
            }
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '952', field_numbers => [1] }
                )
            ],
            [ '3010023917', 'BK', 'GEN', '2001-06-25' ],
            "copy all with regex: original first field still exists"
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '952', field_numbers => [2] }
                )
            ],
            [ '3010023918', 'CD' ],
            "copy all with regex: original second field still exists"
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '953', field_numbers => [1] }
                )
            ],
            [ '4242423917', 'BK', 'GEN', '2001-06-25' ],
            "copy all with regex: first original fields has been copied"
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '953', field_numbers => [2] }
                )
            ],
            [ '4242423918', 'CD' ],
            "copy all with regex: second original fields has been copied"
        );
        copy_field(
            {
                record     => $record,
                from_field => '111',
                to_field   => '999',
            }
        );
        my @fields_9999 =
          read_field( { record => $record, field => '999', subfield => '9' } );
        is_deeply( \@fields_9999, [],
            'copy a nonexistent field does not create a new one' );

        $record = new_record;
        copy_field(
            {
                record        => $record,
                from_field    => 245,
                to_field      => 650,
            }
        );

        is_deeply(
            [
                read_field(
                    { record => $record, field => '650', field_numbers => [2] }
                )
            ],
            [ 'Computer programming.', '462' ],
            'Copy a field to existent fields should create a new field'
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '650', field_numbers => [1] }
                )
            ],
            [ 'The art of computer programming', 'Donald E. Knuth.' ],
            'Copy a field to existent fields should create a new field, the original one should not have been updated'
        );
    };
};

# copy_and_replace_field - subfield
subtest 'copy_and_replace_field' => sub {
    plan tests              => 3;
    subtest 'copy and replace subfield' => sub {
        plan tests => 20;
        my $record = new_record;
        $record->append_fields(
            MARC::Field->new(
                650, ' ', '0',
                a => 'Computer algorithms.',
                9 => '463',
            )
        );
        copy_and_replace_field(
            {
                record        => $record,
                from_field    => '245',
                from_subfield => 'a',
                to_field      => '246',
                to_subfield   => 'a'
            }
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '245', subfield => 'a' }
                )
            ],
            ['The art of computer programming'],
            'Copy and replace should not have modify original subfield 245$a (same as copy)'
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '246', subfield => 'a' }
                )
            ],
            ['The art of computer programming'],
            'Copy and replace should create a new 246$a (same as copy)'
        );

        $record = new_record;
        $record->append_fields(
            MARC::Field->new(
                650, ' ', '0',
                a => 'Computer algorithms.',
                9 => '463',
            )
        );
        copy_and_replace_field(
            {
                record        => $record,
                from_field    => '650',
                from_subfield => 'a',
                to_field      => '651',
                to_subfield   => 'a'
            }
        );
        my @fields_651a =
          read_field( { record => $record, field => '651', subfield => 'a' } );
        is_deeply(
            \@fields_651a,
            [ 'Computer algorithms.', 'Computer programming.' ],
            'Copy and replace multivalued field (same as copy)'
        );
        delete_field( { record => $record, field => '651' } );

        copy_and_replace_field(
            {
                record        => $record,
                from_field    => '650',
                from_subfield => 'a',
                to_field      => '651',
                to_subfield   => 'a',
                field_numbers => [1]
            }
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '651', subfield => 'a' }
                )
            ],
            ['Computer programming.'],
            'Copy and replace first field 650$a should only copy the 1st (same as copy)'
        );

        copy_and_replace_field(
            {
                record        => $record,
                from_field    => '650',
                from_subfield => 'a',
                to_field      => '651',
                to_subfield   => 'a',
                field_numbers => [2]
            }
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '651', subfield => 'a' }
                )
            ],
            ['Computer algorithms.'],
            'Copy and replace second field 650$a should erase 651$a'
        );
        delete_field( { record => $record, field => '651' } );

        copy_and_replace_field(
            {
                record        => $record,
                from_field    => '650',
                from_subfield => 'a',
                to_field      => '651',
                to_subfield   => 'a',
                regex => { search => 'Computer', replace => 'The art of' }
            }
        );
        @fields_651a =
          read_field( { record => $record, field => '651', subfield => 'a' } );
        is_deeply(
            \@fields_651a,
            [ 'The art of algorithms.', 'The art of programming.' ],
            'Copy and replace field using regex (same as copy)'
        );
        delete_field( { record => $record, field => '651' } );

        copy_and_replace_field(
            {
                record        => $record,
                from_field    => '650',
                from_subfield => 'a',
                to_field      => '651',
                to_subfield   => 'a',
                regex => { search => 'Computer', replace => 'The mistake of' }
            }
        );
        @fields_651a =
          read_field( { record => $record, field => '651', subfield => 'a' } );
        is_deeply(
            \@fields_651a,
            [ 'The mistake of algorithms.', 'The mistake of programming.' ],
            'Copy and replace fields using regex on existing fields (same as copy)'
        );
        delete_field( { record => $record, field => '651' } );

        copy_and_replace_field(
            {
                record        => $record,
                from_field    => '650',
                from_subfield => 'a',
                to_field      => '651',
                to_subfield   => 'a',
                regex => { search => 'Computer', replace => 'The art of' }
            }
        );
        @fields_651a =
          read_field( { record => $record, field => '651', subfield => 'a' } );
        is_deeply(
            \@fields_651a,
            [ 'The art of algorithms.', 'The art of programming.', ],
            'Copy and replace all fields using regex (same as copy)'
        );
        delete_field( { record => $record, field => '651' } );

        copy_and_replace_field(
            {
                record        => $record,
                from_field    => '650',
                from_subfield => 'a',
                to_field      => '651',
                to_subfield   => 'a',
                regex => { search => 'Computer', replace => 'The art of' },
                field_numbers => [1]
            }
        );
        @fields_651a =
          read_field( { record => $record, field => '651', subfield => 'a' } );
        is_deeply(
            \@fields_651a,
            [ 'The art of programming.', ],
            'Copy and replace first field using regex (same as copy)'
        );
        delete_field( { record => $record, field => '651' } );

        # Copy and replace with regex modifiers
        $record = new_record;
        $record->append_fields(
            MARC::Field->new(
                650, ' ', '0',
                a => 'Computer algorithms.',
                9 => '463',
            )
        );
        copy_and_replace_field(
            {
                record        => $record,
                from_field    => '650',
                from_subfield => 'a',
                to_field      => '652',
                to_subfield   => 'a',
                regex         => { search => 'o', replace => 'foo' }
            }
        );
        my @fields_652a =
          read_field( { record => $record, field => '652', subfield => 'a' } );
        is_deeply(
            \@fields_652a,
            [ 'Cfoomputer algorithms.', 'Cfoomputer programming.' ],
            'Copy and replace field using regex (same as copy)'
        );

        copy_and_replace_field(
            {
                record        => $record,
                from_field    => '650',
                from_subfield => 'a',
                to_field      => '653',
                to_subfield   => 'a',
                regex => { search => 'o', replace => 'foo', modifiers => 'g' }
            }
        );
        my @fields_653a =
          read_field( { record => $record, field => '653', subfield => 'a' } );
        is_deeply(
            \@fields_653a,
            [ 'Cfoomputer algfoorithms.', 'Cfoomputer prfoogramming.' ],
            'Copy and replace field using regex (same as copy)'
        );

        copy_and_replace_field(
            {
                record        => $record,
                from_field    => '650',
                from_subfield => 'a',
                to_field      => '654',
                to_subfield   => 'a',
                regex => { search => 'O', replace => 'foo', modifiers => 'i' }
            }
        );
        my @fields_654a =
          read_field( { record => $record, field => '654', subfield => 'a' } );
        is_deeply(
            \@fields_654a,
            [ 'Cfoomputer algorithms.', 'Cfoomputer programming.' ],
            'Copy and replace field using regex (same as copy)'
        );

        copy_and_replace_field(
            {
                record        => $record,
                from_field    => '650',
                from_subfield => 'a',
                to_field      => '655',
                to_subfield   => 'a',
                regex => { search => 'O', replace => 'foo', modifiers => 'gi' }
            }
        );
        my @fields_655a =
          read_field( { record => $record, field => '655', subfield => 'a' } );
        is_deeply(
            \@fields_655a,
            [ 'Cfoomputer algfoorithms.', 'Cfoomputer prfoogramming.' ],
            'Copy and replace field using regex (same as copy)'
        );

        $record = new_record;
        $record->append_fields(
            MARC::Field->new(
                952, ' ', ' ',
                p => '3010023917',
                y => 'BK',
            ),
        );

        copy_and_replace_field(
            {
                record        => $record,
                from_field    => '952',
                from_subfield => 'd',
                to_field      => '952',
                to_subfield   => 'd'
            }
        );
        my @fields_952d =
          read_field( { record => $record, field => '952', subfield => 'd' } );
        is_deeply(
            \@fields_952d,
            [ '2001-06-25', '2001-06-25' ],
            'copy and replace 952$d into others 952 field'
        );

        copy_and_replace_field(
            {
                record        => $record,
                from_field    => '111',
                from_subfield => '1',
                to_field      => '999',
                to_subfield   => '9'
            }
        );
        my @fields_9999 =
          read_field( { record => $record, field => '999', subfield => '9' } );
        is_deeply( \@fields_9999, [],
            'copy and replace a nonexistent subfield does not create a new one (same as copy)' );

        $record = new_record;
        copy_and_replace_field(
            {
                record        => $record,
                from_field    => 245,
                from_subfield => 'a',
                to_field      => 245,
                to_subfield   => 'a',
                regex         => { search => '^', replace => 'BEGIN ' }
            }
        );
        # This is the same as update the subfield
        is_deeply(
            [
                read_field(
                    { record => $record, field => '245', subfield => 'a' }
                )
            ],
            ['BEGIN The art of computer programming'],
            'Copy and replace - Update a subfield: add a string at the beginning'
        );

        $record = new_record;
        copy_and_replace_field(
            {
                record        => $record,
                from_field    => 245,
                from_subfield => 'a',
                to_field      => 245,
                to_subfield   => 'a',
                regex         => { search => '$', replace => ' END' }
            }
        );
        # This is the same as update the subfield
        is_deeply(
            [
                read_field(
                    { record => $record, field => '245', subfield => 'a' }
                )
            ],
            ['The art of computer programming END'],
            'Copy and replace - Update a subfield: add a string at the end'
        );

        $record = new_record;
        copy_and_replace_field(
            {
                record        => $record,
                from_field    => 245,
                from_subfield => 'a',
                to_field      => 245,
                to_subfield   => 'a',
                regex         => { search => '(art)', replace => 'sm$1 $1' }
            }
        );
        # This is the same as update the subfield
        is_deeply(
            [
                read_field(
                    { record => $record, field => '245', subfield => 'a' }
                )
            ],
            ['The smart art of computer programming'],
            'Copy and replace - Update a subfield: use capture groups'
        );

        $record = new_record;
        copy_and_replace_field(
            {
                record        => $record,
                from_field    => 245,
                from_subfield => 'c',
                to_field      => 650,
                to_subfield   => 'c',
            }
        );

        is_deeply(
            [
                read_field(
                    { record => $record, field => '650' }
                )
            ],
            [ 'Computer programming.', '462', 'Donald E. Knuth.' ],
            'Copy and replace a subfield to an existent field but inexistent subfield (same as copy)'
        );

        $record = new_record;
        copy_and_replace_field(
            {
                record        => $record,
                from_field    => 245,
                from_subfield => 'c',
                to_field      => 650,
                to_subfield   => '9',
            }
        );

        is_deeply(
            [
                read_field(
                    { record => $record, field => '650' }
                )
            ],
            [ 'Computer programming.', 'Donald E. Knuth.' ],
            'Copy and replace a subfield to an existent field / subfield, the origin subfield is replaced'
        );
    };

    subtest 'copy and replace field' => sub {
        plan tests => 14;
        my $record = new_record;
        $record->append_fields(
            MARC::Field->new(
                952, ' ', ' ',
                p => '3010023918',
                y => 'CD',
            ),
        );

        #- copy all fields
        copy_and_replace_field(
            { record => $record, from_field => '952', to_field => '953' } );
        my @fields_952 = read_field( { record => $record, field => '952' } );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '952', field_numbers => [1] }
                )
            ],
            [ '3010023917', 'BK', 'GEN', '2001-06-25' ],
            "copy all: original first field still exists (same as copy)"
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '952', field_numbers => [2] }
                )
            ],
            [ '3010023918', 'CD' ],
            "copy all: original second field still exists (same as copy)"
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '953', field_numbers => [1] }
                )
            ],
            [ '3010023917', 'BK', 'GEN', '2001-06-25' ],
            "copy all: first original fields has been copied (same as copy)"
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '953', field_numbers => [2] }
                )
            ],
            [ '3010023918', 'CD' ],
            "copy all: second original fields has been copied (same as copy)"
        );

        #- copy only the first field
        copy_and_replace_field(
            {
                record        => $record,
                from_field    => '953',
                to_field      => '954',
                field_numbers => [1]
            }
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '953', field_numbers => [1] }
                )
            ],
            [ '3010023917', 'BK', 'GEN', '2001-06-25' ],
            "copy and replace first: first original fields has been copied (same as copy)"
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '953', field_numbers => [2] }
                )
            ],
            [ '3010023918', 'CD' ],
            "copy and replace first: second original fields has been copied (same as copy)"
        );
        is_deeply(
            [ read_field( { record => $record, field => '954' } ) ],
            [ '3010023917', 'BK', 'GEN', '2001-06-25' ],
            "copy and replace first: only first, first 953 has been copied (same as copy)"
        );

        $record = new_record;
        $record->append_fields(
            MARC::Field->new(
                952, ' ', ' ',
                p => '3010023918',
                y => 'CD',
            ),
        );

        #- copy and replace all fields and modify values using a regex
        copy_and_replace_field(
            {
                record     => $record,
                from_field => '952',
                to_field   => '953',
                regex      => { search => '30100', replace => '42424' }
            }
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '952', field_numbers => [1] }
                )
            ],
            [ '3010023917', 'BK', 'GEN', '2001-06-25' ],
            "copy and replace all with regex: original first field still exists (same as copy)"
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '952', field_numbers => [2] }
                )
            ],
            [ '3010023918', 'CD' ],
            "copy and replace all with regex: original second field still exists (same as copy)"
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '953', field_numbers => [1] }
                )
            ],
            [ '4242423917', 'BK', 'GEN', '2001-06-25' ],
            "copy and replace all with regex: first original fields has been copied (same as copy)"
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '953', field_numbers => [2] }
                )
            ],
            [ '4242423918', 'CD' ],
            "copy and replace all with regex: second original fields has been copied (same as copy)"
        );
        copy_and_replace_field(
            {
                record     => $record,
                from_field => '111',
                to_field   => '999',
            }
        );
        my @fields_9999 =
          read_field( { record => $record, field => '999', subfield => '9' } );
        is_deeply( \@fields_9999, [],
            'copy and replace a nonexistent field does not create a new one (same as copy)' );

        $record = new_record;
        copy_and_replace_field(
            {
                record        => $record,
                from_field    => 245,
                to_field      => 650,
            }
        );

        is_deeply(
            [
                read_field(
                    { record => $record, field => '650', field_numbers => [1] }
                )
            ],
            [ 'The art of computer programming', 'Donald E. Knuth.' ],
            'Copy and replace to an existent field should erase the original field'
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '650', field_numbers => [2] }
                )
            ],
            [],
            'Copy and replace to an existent field should not create a new field'
        );
    };

    # Copy and replace with control field
    subtest 'copy and replace control field' => sub {
        plan tests => 1;
        my $record = new_record;
        $record->append_fields(
            MARC::Field->new( '001', '4815162342' ),
        );

        # Copy control field to subfield
        copy_and_replace_field( { record => $record, from_field => '001', to_field => '099', to_subfield => 'a' } );
        is_deeply(
            [ read_field( { record => $record, field => '099', subfield => 'a' } ) ],
            ['4815162342'],
            'Copy and replace - Update a subfield with content of control field'
        );
    };
};

# move_field - subfields
subtest 'move_field' => sub {
    plan tests              => 2;
    subtest 'move subfield' => sub {
        plan tests => 7;
        my $record = new_record;
        my ( @fields_952d, @fields_952c, @fields_954c, @fields_954p );
        $record->append_fields(
            MARC::Field->new(
                952, ' ', ' ',
                p => '3010023917',
                y => 'BK',
            ),
        );
        move_field(
            {
                record        => $record,
                from_field    => '952',
                from_subfield => 'c',
                to_field      => '954',
                to_subfield   => 'c'
            }
        );
        @fields_952c =
          read_field( { record => $record, field => '952', subfield => 'c' } );
        @fields_954c =
          read_field( { record => $record, field => '954', subfield => 'c' } );
        is_deeply( \@fields_952c, [],      'The 952$c has moved' );
        is_deeply( \@fields_954c, ['GEN'], 'Now 954$c exists' );

        move_field(
            {
                record        => $record,
                from_field    => '952',
                from_subfield => 'p',
                to_field      => '954',
                to_subfield   => 'p',
                field_numbers => [1]
            }
        );    # Move the first field
        my @fields_952p =
          read_field( { record => $record, field => '952', subfield => 'p' } );
        @fields_954p =
          read_field( { record => $record, field => '954', subfield => 'p' } );
        is_deeply( \@fields_952p, ['3010023917'], 'One of 952$p has moved' );
        is_deeply( \@fields_954p, ['3010023917'], 'Now 954$p exists' );

        $record = new_record;
        $record->append_fields(
            MARC::Field->new(
                952, ' ', ' ',
                p => '3010023917',
                y => 'BK',
            ),
        );

        move_field(
            {
                record        => $record,
                from_field    => '952',
                from_subfield => 'p',
                to_field      => '954',
                to_subfield   => 'p'
            }
        );    # Move all field
        @fields_952p =
          read_field( { record => $record, field => '952', subfield => 'p' } );
        @fields_954p =
          read_field( { record => $record, field => '954', subfield => 'p' } );
        is_deeply( \@fields_952p, [], 'All 952$p have moved' );
        is_deeply(
            \@fields_954p,
            [ '3010023917', '3010023917' ],
            'Now 2 954$p exist'
        );

        move_field(
            {
                record        => $record,
                from_field    => '111',
                from_subfield => '1',
                to_field      => '999',
                to_subfield   => '9'
            }
        );
        my @fields_9999 =
          read_field( { record => $record, field => '999', subfield => '9' } );
        is_deeply( \@fields_9999, [],
            'move a nonexistent subfield does not create a new one' );
    };

    subtest 'move field' => sub {
        plan tests => 9;

        # move_field - fields
        my $record = new_record;
        $record->append_fields(
            MARC::Field->new(
                952, ' ', ' ',
                p => '3010023917',
                y => 'BK',
            ),
        );

        #- Move all fields
        move_field(
            { record => $record, from_field => '952', to_field => '953' } );
        is_deeply( [ read_field( { record => $record, field => '952' } ) ],
            [], "original fields don't exist" );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '953', field_numbers => [1] }
                )
            ],
            [ '3010023917', 'BK', 'GEN', '2001-06-25' ],
            "first original fields has been copied"
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '953', field_numbers => [2] }
                )
            ],
            [ '3010023917', 'BK' ],
            "second original fields has been copied"
        );

        #- Move only the first field
        move_field(
            {
                record        => $record,
                from_field    => '953',
                to_field      => '954',
                field_numbers => [1]
            }
        );
        is_deeply(
            [ read_field( { record => $record, field => '953' } ) ],
            [ '3010023917', 'BK' ],
            "only first, the second 953 still exists"
        );
        is_deeply(
            [ read_field( { record => $record, field => '954' } ) ],
            [ '3010023917', 'BK', 'GEN', '2001-06-25' ],
            "only first, first 953 has been copied"
        );

        $record = new_record;
        $record->append_fields(
            MARC::Field->new(
                952, ' ', ' ',
                p => '3010023917',
                y => 'BK',
            ),
        );

        #- Move all fields and modify values using a regex
        move_field(
            {
                record     => $record,
                from_field => '952',
                to_field   => '953',
                regex      => { search => 'BK', replace => 'DVD' }
            }
        );
        is_deeply( [ read_field( { record => $record, field => '952' } ) ],
            [], "use a regex, original fields don't exist" );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '953', field_numbers => [1] }
                )
            ],
            [ '3010023917', 'DVD', 'GEN', '2001-06-25' ],
            "use a regex, first original fields has been copied"
        );
        is_deeply(
            [
                read_field(
                    { record => $record, field => '953', field_numbers => [2] }
                )
            ],
            [ '3010023917', 'DVD' ],
            "use a regex, second original fields has been copied"
        );

        move_field(
            {
                record     => $record,
                from_field => '111',
                to_field   => '999',
            }
        );
        my @fields_9999 =
          read_field( { record => $record, field => '999', subfield => '9' } );
        is_deeply( \@fields_9999, [],
            'move a nonexistent field does not create a new one' );

    };
};

# delete_field
subtest 'delete_field' => sub {
    plan tests                => 2;
    subtest 'delete subfield' => sub {
        plan tests => 3;
        my $record = new_record;
        $record->append_fields(
            MARC::Field->new(
                952, ' ', ' ',
                p => '3010023917',
                y => 'BK',
            ),
        );

        delete_field(
            {
                record        => $record,
                field         => '952',
                subfield      => 'p',
                field_numbers => [1]
            }
        );
        my @fields_952p =
          read_field( { record => $record, field => '952', subfield => 'p' } );
        is_deeply( \@fields_952p, ['3010023917'], 'Delete first 952$p' );

        $record = new_record;
        $record->append_fields(
            MARC::Field->new(
                952, ' ', ' ',
                p => '3010023917',
                y => 'BK',
            ),
        );
        delete_field( { record => $record, field => '952', subfield => 'p' } );
        @fields_952p =
          read_field( { record => $record, field => '952', subfield => 'p' } );
        is_deeply( \@fields_952p, [], 'Delete all 952$p' );

        $record = new_record;
        $record->append_fields(
            MARC::Field->new(
                600, ' ', ' ',
                a => 'Murakami, Haruki',
                0 => 'https://id.loc.gov/authorities/names/n81152393.html',
            ),
        );
        delete_field( { record => $record, field => '600', subfield => '0' } );
        my @fields_600 = read_field( { record => $record, field => '600' } );
        is_deeply( \@fields_600, ['Murakami, Haruki'], 'Delete all 600$0, only subfield 0 deleted' );
    };

    subtest 'delete field' => sub {
        plan tests => 2;
        my $record = new_record;
        delete_field( { record => $record, field => '952' } );
        my @fields_952 = read_field( { record => $record, field => '952' } );
        is_deeply( \@fields_952, [], 'Delete all 952, 1 deleted' );

        $record = new_record;
        $record->append_fields(
            MARC::Field->new(
                952, ' ', ' ',
                p => '3010023917',
                y => 'BK',
            ),
        );
        delete_field( { record => $record, field => '952' } );
        @fields_952 = read_field( { record => $record, field => '952' } );
        is_deeply( \@fields_952, [], 'Delete all 952, 2 deleted' );
    };
};

subtest 'field_equals' => sub {
    plan tests => 2;
    my $record = new_record;
    subtest 'standard MARC fields' => sub {
        plan tests => 2;
        my $match = Koha::SimpleMARC::field_equals({
                record => $record,
                value => 'Donald',
                field => '100',
                subfield => 'a',
            });
        is_deeply( $match, [], '100$a not equal to "Donald"' );

        $match = Koha::SimpleMARC::field_equals({
                record => $record,
                value => 'Donald',
                field => '100',
                subfield => 'a',
                is_regex => 1,
            });
        is_deeply( $match, [1], 'first 100$a matches "Donald"');
    };

    subtest 'control fields' => sub {
        plan tests => 2;
        my $match = Koha::SimpleMARC::field_equals({
                record => $record,
                value => 'eng',
                field => '008',
                subfield => '',
            });
        is_deeply( $match, [], '008 control field not equal to "eng"' );

        $match = Koha::SimpleMARC::field_equals({
                record => $record,
                value => 'eng',
                field => '008',
                subfield => '',
                is_regex => 1,
            });
        is_deeply( $match, [1], 'first 008 control field matches "eng"' );
    };
};

subtest 'update_last_transaction_time' => sub {
    plan tests => 3;
    my $record = MARC::Record->new;
    update_last_transaction_time( { record => $record } );
    my $value1 = $record->field('005')->data;
    like( $value1, qr/^\d{14}\.0$/, 'Looks like a 005' );
    sleep 1;
    update_last_transaction_time( { record => $record } );
    my $value2 = $record->field('005')->data;
    like( $value2, qr/^\d{14}\.0$/, 'Still looks like a 005' );
    isnt( $value1, $value2, 'Should not be the same a second later' );
};
