Convert-Pheno

 view release on metacpan or  search on metacpan

t/15-convertpheno-orchestration.t  view on Meta::CPAN

use strict;
use warnings;

use lib qw(./lib ../lib t/lib);
use Test::More;
use Test::Exception;
use File::Temp qw(tempfile);
use Convert::Pheno;
use Convert::Pheno::Runner qw(resolve_operation run_operation);

my $orig_warn_handler = $SIG{__WARN__};
local $SIG{__WARN__} = sub {
    return if $_[0] =~ /^Subroutine .* redefined /;
    return $orig_warn_handler ? $orig_warn_handler->(@_) : warn @_;
};

{
    no warnings 'redefine';

    local *Convert::Pheno::redcap2bff = sub { return [ { id => 'r1' } ] };
    local *Convert::Pheno::cdisc2bff  = sub { return [ { id => 'c1' } ] };
    local *Convert::Pheno::csv2bff    = sub { return [ { id => 'csv1' } ] };
    local *Convert::Pheno::pxf2bff    = sub { return [ { id => 'p1' } ] };
    local *Convert::Pheno::omop2bff   = sub { return [ { id => 'o1' } ] };
    local *Convert::Pheno::_run_primary_view = sub {
        my ($self) = @_;
        return {
            method      => $self->{method},
            data        => $self->{data},
            in_textfile => $self->{in_textfile},
        };
    };
    local *Convert::Pheno::merge_omop_tables = sub { return { merged => shift } };

    my $redcap = Convert::Pheno->new( { method => 'redcap2pxf', in_textfile => 1 } )->redcap2pxf;
    is( $redcap->{method}, 'bff2pxf', 'redcap2pxf switches to bff2pxf' );
    is_deeply( $redcap->{data}, [ { id => 'r1' } ], 'redcap2pxf forwards redcap2bff output' );
    is( $redcap->{in_textfile}, 0, 'redcap2pxf forces in_textfile off' );

    my $cdisc = Convert::Pheno->new( { method => 'cdisc2omop', in_textfile => 1 } )->cdisc2omop;
    is( $cdisc->{merged}{data}[0]{id}, 'c1', 'cdisc2omop merges cdisc2bff output' );

    my $csv = Convert::Pheno->new( { method => 'csv2omop', in_textfile => 1 } )->csv2omop;
    is( $csv->{merged}{data}[0]{id}, 'csv1', 'csv2omop merges csv2bff output' );

    my $pxf = Convert::Pheno->new( { method => 'pxf2omop', in_textfile => 1 } )->pxf2omop;
    is( $pxf->{merged}{data}[0]{id}, 'p1', 'pxf2omop merges pxf2bff output' );
}

{
    my ( undef, $tmp_file ) = tempfile();
    my $convert = Convert::Pheno->new(
        {
            method    => 'omop2bff',
            out_file  => $tmp_file,
            in_textfile => 0,
        }
    );
    $convert->{omop_cli} = 1;
    my $stream = Convert::Pheno::_dispatcher_open_stream_out($convert);
    ok( $stream->{fh}, '_dispatcher_open_stream_out opens output file in streaming mode' );
    close $stream->{fh};
}

{
    my $convert = Convert::Pheno->new(
        {
            method      => 'bff2pxf',
            in_textfile => 0,
            data        => { inline => 1 },
        }
    );
    is_deeply( Convert::Pheno::_dispatcher_input_data($convert), { inline => 1 }, '_dispatcher_input_data returns in-memory data when not reading a file' );
}

{
    my $convert = Convert::Pheno->new(
        {
            method      => 'bff2pxf',
            in_textfile => 1,
            in_file     => 't/bff2pxf/in/individuals.json',
        }
    );
    my $data = Convert::Pheno::_dispatcher_input_data($convert);
    is( ref($data), 'ARRAY', '_dispatcher_input_data reads structured file input for bff-like methods' );
}

{
    my $convert = Convert::Pheno->new( { stream => 1 } );
    local *Convert::Pheno::transpose_omop_data_structure = sub { die 'should not be called' };
    my $data = { CONCEPT => [] };
    ok( Convert::Pheno::_omop_prepare_data_shape( $convert, $data ), '_omop_prepare_data_shape succeeds in stream mode' );
    is( $convert->{data}, $data, '_omop_prepare_data_shape keeps data as-is in stream mode' );
}

{
    my $convert = Convert::Pheno->new( { stream => 0 } );
    local *Convert::Pheno::transpose_omop_data_structure = sub { return [ { PERSON => { person_id => 1 } } ] };
    ok( Convert::Pheno::_omop_prepare_data_shape( $convert, { CONCEPT => [] } ), '_omop_prepare_data_shape succeeds in non-stream mode' );
    is_deeply( $convert->{data}, [ { PERSON => { person_id => 1 } } ], '_omop_prepare_data_shape transposes data in non-stream mode' );
}

{
    my $convert = Convert::Pheno->new( {} );
    dies_ok { Convert::Pheno::_omop_require_concept( $convert, {} ) } '_omop_require_concept dies when CONCEPT is missing';
    ok( Convert::Pheno::_omop_require_concept( $convert, { CONCEPT => [] } ), '_omop_require_concept passes when CONCEPT exists' );
}

{
    my $convert = Convert::Pheno->new( { method => 'omop2bff', prev_omop_tables => [ 'DRUG_EXPOSURE', 'PERSON' ], person => { 1 => { person_id => 1 } } } );
    my @csv_calls;
    my @sql_calls;
    local *Convert::Pheno::open_connections_SQLite = sub { return 1 };
    local *Convert::Pheno::read_csv_stream = sub { push @csv_calls, $_[0]{in}; return 1 };
    local *Convert::Pheno::read_sqldump_stream = sub { push @sql_calls, $_[0]{self}{omop_tables}[0]; return 1 };

    ok( Convert::Pheno::process_csv_files_stream( $convert, [ 'a.csv', 'b.csv' ] ), 'process_csv_files_stream succeeds' );
    is_deeply( \@csv_calls, [ 'a.csv', 'b.csv' ], 'process_csv_files_stream forwards each file' );

    ok( Convert::Pheno::process_sqldump_stream( $convert, 'dump.sql', [ 'CONCEPT', 'DRUG_EXPOSURE', 'PERSON' ] ), 'process_sqldump_stream succeeds' );
    is_deeply( \@sql_calls, [ 'DRUG_EXPOSURE' ], 'process_sqldump_stream skips RAM-memory OMOP tables' );



( run in 0.841 second using v1.01-cache-2.11-cpan-140bd7fdf52 )