t/unit/MGH_Biostat/TravEpi/SimpleRulesBase/Translator.t


#!/usr/bin/env perl
use Modern::Perl '2013';
use Test2::V0;
use Test2::Tools::Spec;

use MGH_Biostat::TravEpi::SimpleRulesBase::Countries;

BEGIN {
    $MGH_Biostat::TravEpi::SimpleRulesBase::Countries::countries = {
        'test1' => 'test1',
        'test2' => 'test1',
        'us'    => 'us',
    };
}

package MGH_Biostat::Locale::DB::test {
    $INC{'MGH_Biostat/Locale/DB/test.pm'} = 't/unit/MGH_Biostat/TravEpi/SimpleRulesBase/Translator.t';
    our $cldr_version = '26';
    our $orientation  = 'left-to-right';
    our $englishname  = 'Test language';
    our $list         = {
        '2'      => '{0} and {1}',
        'start'  => '{0}, {1}',
        'middle' => '{0}, {1}',
        'end'    => '{0}, and {1}'
    };
    1;
};

use Path::Tiny;
use Set::Tiny 'set';
use MGH_Biostat::TravEpi::SimpleRulesBase::Translator;
use MGH_Biostat::TravEpi::SimpleRulesBase::DynamicText;

# @TODO this is stupid, there must be a better way to create the catalog for each of the tests
package t::unit::MGH_Biostat::TravEpi::SimpleRulesBase::Translator::preload {

    sub create_catalog {
        my $dir = Path::Tiny->tempdir();
        $dir->child('test.po')->spew_utf8(<<'EOPO');
# Test "test" po file
msgid ""
msgstr ""
"Language: test\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"

msgctxt "Menu"
msgid "test1"
msgstr "Test first test country"

msgctxt "Menu"
msgid "test2"
msgstr "Test Another name for First test country"

msgctxt "Menu"
msgid "us"
msgstr "Test United States"

msgctxt "List"
msgid "test1"
msgstr "Test test1 list"

msgctxt "List"
msgid "test2"
msgstr "Test test2 list"

msgctxt "List"
msgid "us"
msgstr "Test us list"

msgid "in language"
msgstr "in Test"

msgid "This is a test"
msgstr "Test te t test"

#. See http://localization-guide.readthedocs.org/en/latest/l10n/pluralforms.html for information about plural forms used.
#. For Arabic, 0 is the first form.
#: dynamic.strings#plural."%s year old"
#, c-format
msgid "%s year old"
msgid_plural "%s years old"
msgstr[0] "%s год"
msgstr[1] "%s года"
msgstr[2] "%s лет"

EOPO

        $dir->child('en-US.po')->spew_utf8(<<'EOPO');
# Test "en" po file
msgid ""
msgstr ""
"Language: en\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

msgctxt "Menu"
msgid "test1"
msgstr "First test country"

msgctxt "Menu"
msgid "us"
msgstr "United States"

msgctxt "Menu"
msgid "test2"
msgstr "Another name for First test country"

msgid "in language"
msgstr "in English"

msgid "This is a test"
msgstr "EnUS en e enus"
EOPO

        return $dir;
    }
};

describe 'new()' => sub {
    my $dir = t::unit::MGH_Biostat::TravEpi::SimpleRulesBase::Translator::preload::create_catalog();
    my $t   = MGH_Biostat::TravEpi::SimpleRulesBase::Translator->new( 'dir' => $dir );

    tests 'correct_class' => sub {
        isa_ok( $t, [ 'MGH_Biostat::TravEpi::SimpleRulesBase::Translator' ], 'correctly created object' );
    };

    tests 'catalog' => sub {
        isa_ok( $t->{'catalog'}, [ 'MGH_Biostat::Locale::POCatalog' ], 'created the catalog' );
        like( $t->{'catalog'}{'dir'}, qr[\Q$dir\E/?], 'catalog points to the correct location' );
    };

    tests 'locales' => sub {
        is(
            $t->{'locales'},
            hash {
                field 'test' => object {
                    prop blessed       => 'MGH_Biostat::Locale::Locale';
                    field cldr_version => 26;
                    field orientation  => 'left-to-right';
                    field englishname  => 'Test language';
                    field list         => meta { prop reftype => 'HASH'; prop size => 4; };
                };
                field 'en-US' => meta { prop reftype => 'HASH' };
                end;
            },
            'correct locales created'
        );
    };

    tests 'country_sort_cache' => sub {
        is(
            $t->{'country_sort_cache'},
            hash {
                field 'test' => hash {
                    field 'test1' => meta { prop reftype => undef };
                    field 'test2' => meta { prop reftype => undef };
                    field 'us'    => meta { prop reftype => undef };
                };
                field 'en-US' => hash {
                    field 'test1' => meta { prop reftype => undef };
                    field 'test2' => meta { prop reftype => undef };
                    field 'us'    => meta { prop reftype => undef };
                };
            },
            'country sort cache created'
        );
    };
};

describe 'get_locale()' => sub {
    my $dir = t::unit::MGH_Biostat::TravEpi::SimpleRulesBase::Translator::preload::create_catalog();
    my $t   = MGH_Biostat::TravEpi::SimpleRulesBase::Translator->new( 'dir' => $dir );

    tests 'structure ' => sub {
        is(
            $t->get_locale('test'),
            object {
                prop blessed       => 'MGH_Biostat::Locale::Locale';
                field cldr_version => 26;
                field englishname  => 'Test language';
                field orientation  => 'left-to-right';
                field list         => hash {
                    field start  => '{0}, {1}';
                    field 2      => '{0} and {1}';
                    field middle => '{0}, {1}';
                    field end    => '{0}, and {1}';
                };
            },
            'returns the correct locale'
        );
    };
};

describe 'valid_languages()' => sub {
    my $dir = t::unit::MGH_Biostat::TravEpi::SimpleRulesBase::Translator::preload::create_catalog();
    my $t   = MGH_Biostat::TravEpi::SimpleRulesBase::Translator->new( 'dir' => $dir );

    my $expected = set( 'en-US', 'test' );

    tests languages => sub {
        ok( $t->valid_languages()->is_equal($expected), 'correct languages list' );
    };
};

describe 'is_valid_language()' => sub {
    my $dir = t::unit::MGH_Biostat::TravEpi::SimpleRulesBase::Translator::preload::create_catalog();
    my $t   = MGH_Biostat::TravEpi::SimpleRulesBase::Translator->new( 'dir' => $dir );

    tests 'languages' => sub {
        is( $t->is_valid_language('test'),               T(), 'test is a valid language' );
        is( $t->is_valid_language('en-US'),              T(), 'en-US is a valid language' );
        is( $t->is_valid_language('en'),                 F(), 'en is not a valid language' );
        is( $t->is_valid_language('es'),                 F(), 'es is not a valid language' );
        is( $t->is_valid_language('1123aoeusaoesuntdf'), F(), 'gibberish is not valid' );
    };
};

describe 'default_language()' => sub {
    my $dir = t::unit::MGH_Biostat::TravEpi::SimpleRulesBase::Translator::preload::create_catalog();
    my $t   = MGH_Biostat::TravEpi::SimpleRulesBase::Translator->new( 'dir' => $dir );

    tests 'default language' => sub {
        is( $t->default_language(), 'en-US', 'en-US is the default language' );
    };
};

describe 'ordered_languages()' => sub {
    my $dir = t::unit::MGH_Biostat::TravEpi::SimpleRulesBase::Translator::preload::create_catalog();
    my $t   = MGH_Biostat::TravEpi::SimpleRulesBase::Translator->new( 'dir' => $dir );

    tests 'order' => sub {
        is(
            $t->ordered_languages(),
            [ 'en-US', 'test' ],
            'languages in correct order'
        );
    };
};

describe 'get_inlanguage()' => sub {
    my $dir = t::unit::MGH_Biostat::TravEpi::SimpleRulesBase::Translator::preload::create_catalog();
    my $t   = MGH_Biostat::TravEpi::SimpleRulesBase::Translator->new( 'dir' => $dir );

    tests 'names' => sub {
        is( $t->get_inlanguage('en-US'), 'in English', 'en-US ok' );
        is( $t->get_inlanguage('test'),  'in Test',    'test ok' );
    };
};

describe 'translate_template()' => sub {
    my $dir = t::unit::MGH_Biostat::TravEpi::SimpleRulesBase::Translator::preload::create_catalog();
    my $t   = MGH_Biostat::TravEpi::SimpleRulesBase::Translator->new( 'dir' => $dir );

    my $templates = {
        'test' => {
            'rep' => {
                't' => <<'EOTMPL',
<div lang="!!$langshort" dir="!!$langdir" data-longleng="!!$langlong">
<p>This is a test</p>
<select name="foo">
!!$countries
</select>
</div>
EOTMPL
                'x' => <<'EOEXPT',
<div lang="test" dir="ltr" data-longleng="test">
<p>This is a test</p>
<select name="foo">
<option value="test2">Test Another name for First test country</option><option value="test1">Test first test country</option><option value="us">Test United States</option>
</select>
</div>
EOEXPT
            },
            'trans' => {
                't' => <<'EOTMPL',
<p data-gettext>This is a test</p>
<span data-gettext>in language</span>
EOTMPL
                'x' => <<'EOEXPT',
<p data-gettext>Test te t test</p>
<span data-gettext>in Test</span>
EOEXPT
            },
        },
        'en-US' => {
            'rep' => {
                't' => <<'EOTMPL',
<div lang="!!$langshort" dir="!!$langdir" data-longleng="!!$langlong">
<p>This is a test</p>
<select name="foo">
!!$countries
</select>
</div>
EOTMPL
                'x' => <<'EOEXPT',
<div lang="en" dir="ltr" data-longleng="en-US">
<p>This is a test</p>
<select name="foo">
<option value="test2">Another name for First test country</option><option value="test1">First test country</option><option value="us">United States</option>
</select>
</div>
EOEXPT
            },
            'trans' => {
                't' => <<'EOTMPL',
<p data-gettext>This is a test</p>
<span data-gettext>in language</span>
EOTMPL
                'x' => <<'EOEXPT',
<p data-gettext>EnUS en e enus</p>
<span data-gettext>in English</span>
EOEXPT
            },
        },
    };

    tests 'replacement' => sub {
        foreach my $l ( sort keys %$templates ) {
            is(
                $t->translate_template( $l, $templates->{$l}{'rep'}{'t'} ),
                $templates->{$l}{'rep'}{'x'},
                "$l replacements correct"
            );
        }
    };

    tests 'translation' => sub {
        foreach my $l ( sort keys %$templates ) {
            is(
                $t->translate_template( $l, $templates->{$l}{'trans'}{'t'} ),
                $templates->{$l}{'trans'}{'x'},
                "$l translations correct"
            );
        }
    };
};

describe 'countries_menu()' => sub {
    my $dir = t::unit::MGH_Biostat::TravEpi::SimpleRulesBase::Translator::preload::create_catalog();
    my $t   = MGH_Biostat::TravEpi::SimpleRulesBase::Translator->new( 'dir' => $dir );

    tests 'menu' => sub {
        is(
            $t->countries_menu('test'),
            "<option value=\"test2\">Test Another name for First test country</option><option value=\"test1\">Test first test country</option><option value=\"us\">Test United States</option>",
            'test countries menu ok'
        );
        is(
            $t->countries_menu('en-US'),
            "<option value=\"test2\">Another name for First test country</option><option value=\"test1\">First test country</option><option value=\"us\">United States</option>",
            'en-US countries menu ok'
        );
        my $invalid_menu;
        is(
            warning { $invalid_menu = $t->countries_menu('invalid'); },
            match qr/^Countries menu requested for unknown language \('invalid'\)\. Using default language\.\n/,
            'warns for invalid language'
        );
        is(
            $invalid_menu,
            "<option value=\"test2\">Another name for First test country</option><option value=\"test1\">First test country</option><option value=\"us\">United States</option>",
            'invalid language returns default language menu'
        );
    };
};

describe 'translate_dynamic_text()' => sub {
    my $dir = t::unit::MGH_Biostat::TravEpi::SimpleRulesBase::Translator::preload::create_catalog();
    my $t   = MGH_Biostat::TravEpi::SimpleRulesBase::Translator->new( 'dir' => $dir );

    tests 'age' => sub {
        my $ages = [
            { 'dt' => newdt( 'age', 1 ), 'x' => '1 год',  'd' => '1 year ok' },
            { 'dt' => newdt( 'age', 3 ), 'x' => '3 года', 'd' => '3 year ok' },
            { 'dt' => newdt( 'age', 9 ), 'x' => '9 лет',  'd' => '9 year ok' },
        ];
        foreach my $test (@$ages) {
            is(
                $t->translate_dynamic_text( $test->{'dt'}, 'test' ),
                $test->{'x'},
                $test->{'d'}
            );
        }
    };

    tests 'countries' => sub {
        my $countries = [
            { 'dt' => newdt( 'countries', set('test1') ), 'x' => 'Test test1 list', 'd' => 'single country no context' },
            { 'dt' => newdt( 'countries', set( 'test1', 'test2' ) ), 'x' => 'Test test2 list and Test test1 list', 'd' => 'two countries no context' },
        ];
        foreach my $test (@$countries) {
            is(
                $t->translate_dynamic_text( $test->{'dt'}, 'test' ),
                $test->{'x'},
                $test->{'d'}
            );
        }
    };
    tests 'destlinks' => sub {
        my $destlinks = [
            {
                'dt' => newdt( 'destlinks', set('test1') ),
                'x'  => array {
                    item 0 => hash { field 'dest_link' => 'cdc-redirect/test1?unknown'; field 'dest_link_name' => 'Test test1 list'; };
                },
                'd' => 'single country no context',
            },
            {
                'dt' => newdt( 'destlinks', set( 'test1', 'test2' ) ),
                'x'  => array {
                    item 0 => hash { field 'dest_link' => 'cdc-redirect/test2?unknown'; field 'dest_link_name' => 'Test test2 list'; };
                    item 1 => hash { field 'dest_link' => 'cdc-redirect/test1?unknown'; field 'dest_link_name' => 'Test test1 list'; };
                },
                'd' => 'two countries no context',
            },
            {
                'dt' => newdt( 'destlinks', set('test1'), { 'hash' => 'testhash' } ),
                'x'  => array {
                    item 0 => hash { field 'dest_link' => 'cdc-redirect/test1?testhash'; field 'dest_link_name' => 'Test test1 list'; };
                },
                'd' => 'hash passed in context',
            },
        ];
        foreach my $test (@$destlinks) {
            is(
                $t->translate_dynamic_text( $test->{'dt'}, 'test' ),
                $test->{'x'},
                $test->{'d'}
            );
        }
    };

    tests 'unknown type' => sub {
        my $dt = newdt( 'unknown', 'foo' );
        my $ret;
        like(
            warning { $ret = $t->translate_dynamic_text( $dt, 'test' ); },
            qr/^Unknown dynamic text type unknown/,
            'throws warning about unknown type'
        );
        is( $ret, 'not yet implemented', 'returns missing text' );
    };
};

done_testing();