1use strict;
2use warnings;
3use utf8;
4
5use File::Spec;
6use Test::More;
7
8use DateTime::Locale;
9
10my @locale_ids   = sort DateTime::Locale->ids();
11my %locale_names = map { $_ => 1 } DateTime::Locale->names;
12my %locale_ids   = map { $_ => 1 } DateTime::Locale->ids;
13
14plan tests =>
15      5                               # starting
16    + 1                               # one test for root locale
17    + ( ( @locale_ids - 1 ) * 21 )    # tests for each other local
18    + 56                              # check_root
19    + 24                              # check_en
20    + 66                              # check_en_GB
21    + 23                              # check_en_US
22    + 11                              # check_es_ES
23    + 5                               # check_en_US_POSIX
24    + 2                               # check_af
25    + 9                               # check_DT_Lang
26    ;
27
28{
29    ok( @locale_ids >= 240,     'Coverage looks complete' );
30    ok( $locale_names{English}, "Locale name 'English' found" );
31    ok( $locale_ids{ar_JO},     "Locale id 'ar_JO' found" );
32
33    eval { DateTime::Locale->load('Does not exist') };
34    like( $@, qr/invalid/i,
35        'invalid locale name/id to load() causes an error' );
36
37    # this type of locale id should work
38    my $l = DateTime::Locale->load('en_US.LATIN-1');
39    is( $l->id, 'en_US', 'id is en_US' );
40}
41
42# testing the basics for all ids
43{
44    for my $locale_id (@locale_ids) {
45        my $locale = eval { DateTime::Locale->load($locale_id) };
46
47        isa_ok( $locale, 'DateTime::Locale::Base' );
48
49        next if $locale_id eq 'root';
50
51        ok( $locale_ids{ $locale->id() },
52            "'$locale_id':  Has a valid locale id" );
53
54        ok( length $locale->name(), "'$locale_id':  Has a locale name" );
55        ok(
56            length $locale->native_name(),
57            "'$locale_id':  Has a native locale name"
58        );
59
60        for my $test (
61            {
62                locale_method => 'month_format_wide',
63                count         => 12,
64            }, {
65                locale_method => 'month_format_abbreviated',
66                count         => 12,
67            }, {
68                locale_method => 'day_format_wide',
69                count         => 7,
70            }, {
71                locale_method => 'day_format_abbreviated',
72                count         => 7,
73            }, {
74                locale_method => 'quarter_format_wide',
75                count         => 4,
76            }, {
77                locale_method => 'quarter_format_abbreviated',
78                count         => 4,
79            }, {
80                locale_method => 'am_pm_abbreviated',
81                count         => 2,
82            }, {
83                locale_method => 'era_wide',
84                count         => 2,
85            }, {
86                locale_method => 'era_abbreviated',
87                count         => 2,
88            },
89            ) {
90            check_array( locale => $locale, %$test );
91        }
92
93        # We can't actually expect these to be unique.
94        is( scalar @{ $locale->day_format_narrow() }, 7,
95            'day_format_narrow() returns 7 items' );
96        is( scalar @{ $locale->month_format_narrow() }, 12,
97            'month_format_narrow() returns 12 items' );
98        is( scalar @{ $locale->day_stand_alone_narrow() }, 7,
99            'day_stand_alone_narrow() returns 7 items' );
100        is( scalar @{ $locale->month_stand_alone_narrow() }, 12,
101            'month_stand_alone_narrow() returns 12 items' );
102
103        check_formats( $locale_id, $locale, 'date_formats', 'date_format' );
104        check_formats( $locale_id, $locale, 'time_formats', 'time_format' );
105    }
106}
107
108check_root();
109check_en();
110check_en_GB();
111check_en_US();
112check_es_ES();
113check_en_US_POSIX();
114check_af();
115check_DT_Lang();
116
117sub check_array {
118    my %test = @_;
119
120    my $locale_method = $test{locale_method};
121
122    my %unique = map { $_ => 1 } @{ $test{locale}->$locale_method() };
123
124    my $locale_id = $test{locale}->id();
125
126TODO:
127    {
128        local $TODO
129            = 'The ii locale does not have unique abbreviated days for some reason'
130            if $test{locale}->id() =~ /^ii/
131                && $locale_method eq 'day_format_abbreviated';
132
133        is(
134            keys %unique, $test{count},
135            qq{'$locale_id': '$locale_method' contains $test{count} unique items}
136        );
137    }
138}
139
140sub check_formats {
141    my ( $locale_id, $locale, $hash_func, $item_func ) = @_;
142
143    my %unique = map { $_ => 1 } values %{ $locale->$hash_func() };
144
145    ok( keys %unique >= 1,
146        "'$locale_id': '$hash_func' contains at least 1 unique item" );
147
148    foreach my $length (qw( full long medium short )) {
149        my $method = $item_func . q{_} . $length;
150
151        my $val = $locale->$method();
152
153        if ( defined $val ) {
154            delete $unique{$val};
155        }
156        else {
157            Test::More::diag("$locale_id returned undef for $method()");
158        }
159    }
160
161    is(
162        keys %unique, 0,
163        "'$locale_id':  Data returned by '$hash_func' and '$item_func patterns' matches"
164    );
165}
166
167sub check_root {
168    my $locale = DateTime::Locale->load('root');
169
170    my %tests = (
171        day_format_wide => [qw( 2 3 4 5 6 7 1 )],
172
173        day_format_abbreviated => [qw( 2 3 4 5 6 7 1 )],
174
175        day_format_narrow => [qw( 2 3 4 5 6 7 1 )],
176
177        day_stand_alone_wide => [qw( 2 3 4 5 6 7 1 )],
178
179        day_stand_alone_abbreviated => [qw( 2 3 4 5 6 7 1 )],
180
181        day_stand_alone_narrow => [qw( 2 3 4 5 6 7 1 )],
182
183        month_format_wide => [qw( 1 2 3 4 5 6 7 8 9 10 11 12 )],
184
185        month_format_abbreviated => [qw( 1 2 3 4 5 6 7 8 9 10 11 12 )],
186
187        month_format_narrow => [qw( 1 2 3 4 5 6 7 8 9 10 11 12 )],
188
189        month_stand_alone_wide => [qw( 1 2 3 4 5 6 7 8 9 10 11 12 )],
190
191        month_stand_alone_abbreviated => [qw( 1 2 3 4 5 6 7 8 9 10 11 12 )],
192
193        month_stand_alone_narrow => [qw( 1 2 3 4 5 6 7 8 9 10 11 12 )],
194
195        quarter_format_wide => [qw( Q1 Q2 Q3 Q4 )],
196
197        quarter_format_abbreviated => [qw( Q1 Q2 Q3 Q4 )],
198
199        quarter_format_narrow => [qw( 1 2 3 4 )],
200
201        quarter_stand_alone_wide => [qw( Q1 Q2 Q3 Q4 )],
202
203        quarter_stand_alone_abbreviated => [qw( Q1 Q2 Q3 Q4 )],
204
205        quarter_stand_alone_narrow => [qw( 1 2 3 4 )],
206
207        era_wide => [qw( BCE CE )],
208
209        era_abbreviated => [qw( BCE CE )],
210
211        era_narrow => [qw( BCE CE )],
212
213        am_pm_abbreviated => [qw( AM PM )],
214
215        datetime_format_full   => 'EEEE, y MMMM dd HH:mm:ss zzzz',
216        datetime_format_long   => 'y MMMM d HH:mm:ss z',
217        datetime_format_medium => 'y MMM d HH:mm:ss',
218        datetime_format_short  => 'yyyy-MM-dd HH:mm',
219
220        datetime_format_default => 'y MMM d HH:mm:ss',
221
222        glibc_datetime_format => '%a %b %e %H:%M:%S %Y',
223        glibc_date_format     => '%m/%d/%y',
224        glibc_time_format     => '%H:%M:%S',
225
226        first_day_of_week => 1,
227
228        prefers_24_hour_time => 1,
229    );
230
231    test_data( $locale, %tests );
232
233    my %formats = (
234        d      => 'd',
235        EEEd   => 'd EEE',
236        hm     => 'h:mm a',
237        Hm     => 'H:mm',
238        hms    => 'h:mm:ss a',
239        Hms    => 'H:mm:ss',
240        M      => 'L',
241        Md     => 'M-d',
242        MEd    => 'E, M-d',
243        MMM    => 'LLL',
244        MMMd   => 'MMM d',
245        MMMEd  => 'E MMM d',
246        MMMMd  => 'MMMM d',
247        MMMMEd => 'E MMMM d',
248        ms     => 'mm:ss',
249        y      => 'y',
250        yM     => 'y-M',
251        yMEd   => 'EEE, y-M-d',
252        yMMM   => 'y MMM',
253        yMMMEd => 'EEE, y MMM d',
254        yMMMM  => 'y MMMM',
255        yQ     => 'y Q',
256        yQQQ   => 'y QQQ',
257    );
258
259    test_formats( $locale, %formats );
260}
261
262sub check_en {
263    my $locale = DateTime::Locale->load('en');
264
265    my %tests = (
266        en_data(),
267
268        name => 'English',
269    );
270
271    test_data( $locale, %tests );
272}
273
274sub check_en_GB {
275    my $locale = DateTime::Locale->load('en_GB');
276
277    my %tests = (
278        en_data(),
279
280        first_day_of_week => 7,
281
282        name             => 'English United Kingdom',
283        native_name      => 'English United Kingdom',
284        language         => 'English',
285        native_language  => 'English',
286        territory        => 'United Kingdom',
287        native_territory => 'United Kingdom',
288        variant          => undef,
289        native_variant   => undef,
290
291        language_id  => 'en',
292        territory_id => 'GB',
293        variant_id   => undef,
294
295        glibc_datetime_format => '%a %d %b %Y %T %Z',
296        glibc_date_format     => '%d/%m/%y',
297        glibc_time_format     => '%T',
298
299        datetime_format_default => 'd MMM y HH:mm:ss',
300    );
301
302    test_data( $locale, %tests );
303
304    my %formats = (
305        Md       => 'd/M',
306        MEd      => 'E, d/M',
307        MMdd     => 'dd/MM',
308        MMMEd    => 'E d MMM',
309        MMMMd    => 'd MMMM',
310        yMEd     => 'EEE, d/M/yyyy',
311        yyMMM    => 'MMM yy',
312        yyyyMM   => 'MM/yyyy',
313        yyyyMMMM => 'MMMM y',
314
315        # from en
316        d      => 'd',
317        EEEd   => 'd EEE',
318        hm     => 'h:mm a',
319        Hm     => 'H:mm',
320        Hms    => 'H:mm:ss',
321        M      => 'L',
322        MMM    => 'LLL',
323        MMMd   => 'MMM d',
324        MMMMEd => 'E, MMMM d',
325        ms     => 'mm:ss',
326        y      => 'y',
327        yM     => 'M/yyyy',
328        yMMM   => 'MMM y',
329        yMMMEd => 'EEE, MMM d, y',
330        yMMMM  => 'MMMM y',
331        yQ     => 'Q yyyy',
332        yQQQ   => 'QQQ y',
333
334        # from root
335        hms => 'h:mm:ss a',
336    );
337
338    test_formats( $locale, %formats );
339}
340
341sub check_en_US {
342    my $locale = DateTime::Locale->load('en_US');
343
344    my %tests = (
345        en_data(),
346
347        first_day_of_week => 7,
348    );
349
350    test_data( $locale, %tests );
351}
352
353sub en_data {
354    return (
355        day_format_wide =>
356            [qw( Monday Tuesday Wednesday Thursday Friday Saturday Sunday )],
357
358        day_format_abbreviated => [qw( Mon Tue Wed Thu Fri Sat Sun )],
359
360        day_format_narrow => [qw( M T W T F S S )],
361
362        day_stand_alone_wide =>
363            [qw( Monday Tuesday Wednesday Thursday Friday Saturday Sunday )],
364
365        day_stand_alone_abbreviated => [qw( Mon Tue Wed Thu Fri Sat Sun )],
366
367        day_stand_alone_narrow => [qw( M T W T F S S )],
368
369        month_format_wide => [
370            qw( January February March April May June
371                July August September October November December )
372        ],
373
374        month_format_abbreviated =>
375            [qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec )],
376
377        month_format_narrow => [qw( J F M A M J J A S O N D )],
378
379        month_stand_alone_wide => [
380            qw( January February March April May June
381                July August September October November December )
382        ],
383
384        month_stand_alone_abbreviated =>
385            [qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec )],
386
387        month_stand_alone_narrow => [qw( J F M A M J J A S O N D )],
388
389        quarter_format_wide =>
390            [ '1st quarter', '2nd quarter', '3rd quarter', '4th quarter' ],
391
392        quarter_format_abbreviated => [qw( Q1 Q2 Q3 Q4 )],
393
394        quarter_format_narrow => [qw( 1 2 3 4 )],
395
396        quarter_stand_alone_wide =>
397            [ '1st quarter', '2nd quarter', '3rd quarter', '4th quarter' ],
398
399        quarter_stand_alone_abbreviated => [qw( Q1 Q2 Q3 Q4 )],
400
401        quarter_stand_alone_narrow => [qw( 1 2 3 4 )],
402
403        era_wide => [ 'Before Christ', 'Anno Domini' ],
404
405        era_abbreviated => [qw( BC AD )],
406
407        era_narrow => [qw( B A )],
408
409        am_pm_abbreviated => [qw( AM PM )],
410
411        first_day_of_week => 1,
412    );
413}
414
415sub test_data {
416    my $locale = shift;
417    my %tests  = @_;
418
419    for my $k ( sort keys %tests ) {
420        my $desc = "$k for " . $locale->id();
421        if ( ref $tests{$k} ) {
422            is_deeply( $locale->$k(), $tests{$k}, $desc );
423        }
424        else {
425            is( $locale->$k(), $tests{$k}, $desc );
426        }
427    }
428}
429
430sub test_formats {
431    my $locale  = shift;
432    my %formats = @_;
433
434    for my $name ( keys %formats ) {
435        is(
436            $locale->format_for($name), $formats{$name},
437            "Format for $name with " . $locale->id()
438        );
439    }
440
441    is_deeply(
442        [ $locale->available_formats() ],
443        [ sort keys %formats ],
444        "Available formats for " . $locale->id() . " match what is expected"
445    );
446}
447
448sub check_es_ES {
449    my $locale = DateTime::Locale->load('es_ES');
450
451    is( $locale->name(),            'Spanish Spain',    'name()' );
452    is( $locale->native_name(),     'español España', 'native_name()' );
453    is( $locale->language(),        'Spanish',          'language()' );
454    is( $locale->native_language(), 'español',         'native_language()' );
455    is( $locale->territory(),       'Spain',            'territory()' );
456    is( $locale->native_territory(), 'España', 'native_territory()' );
457    is( $locale->variant(),          undef,     'variant()' );
458    is( $locale->native_variant(),   undef,     'native_variant()' );
459
460    is( $locale->language_id(),  'es',  'language_id()' );
461    is( $locale->territory_id(), 'ES',  'territory_id()' );
462    is( $locale->variant_id(),   undef, 'variant_id()' );
463}
464
465sub check_af {
466    my $locale = DateTime::Locale->load('af');
467
468    is_deeply(
469        $locale->month_format_abbreviated(),
470        [qw( Jan Feb Mar Apr Mei Jun Jul Aug Sep Okt Nov Des )],
471        'month abbreviations for af use non-draft form'
472    );
473
474    is_deeply(
475        $locale->month_format_narrow(),
476        [ 1 .. 12 ],
477        'month narrows for af use draft form because that is the only form available'
478    );
479}
480
481sub check_en_US_POSIX {
482    my $locale = DateTime::Locale->load('en_US_POSIX');
483
484    is( $locale->variant(),        'Computer', 'variant()' );
485    is( $locale->native_variant(), 'Computer', 'native_variant()' );
486
487    is( $locale->language_id(),  'en',    'language_id()' );
488    is( $locale->territory_id(), 'US',    'territory_id()' );
489    is( $locale->variant_id(),   'POSIX', 'variant_id()' );
490}
491
492sub check_DT_Lang {
493    foreach my $old (
494        qw ( Austrian TigrinyaEthiopian TigrinyaEritrean
495        Brazilian Portuguese
496        Afar Sidama Tigre )
497        ) {
498        ok( DateTime::Locale->load($old),
499            "backwards compatibility for $old" );
500    }
501
502    foreach my $old (qw ( Gedeo )) {
503    SKIP:
504        {
505            skip
506                'No CLDR XML data for some African languages included in DT::Language',
507                1
508                unless $locale_names{$old};
509
510            ok( DateTime::Locale->load($old),
511                "backwards compatibility for $old" );
512        }
513    }
514}
515
516