#!/usr/bin/perl
BEGIN
{
use
open
':std'
=>
':utf8'
;
my
%old
=
%ENV
;
my
@rem
=
qw( LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE LC_TIME )
;
no
warnings
'uninitialized'
;
for
(
@rem
)
{
delete
(
$ENV
{
$_
} );
next
if
(
$_
eq
'LC_NAME'
||
$_
eq
'LC_TYPE'
);
}
our
$DEBUG
=
exists
(
$ENV
{AUTHOR_TESTING} ) ?
$ENV
{AUTHOR_TESTING} : 0;
};
BEGIN { use_ok(
'Module::Generic::Number'
) || BAIL_OUT(
"Unable to load Module::Generic::Number"
); }
POSIX::setlocale(
&POSIX::LC_ALL
,
'C.UTF-8'
)
if
(
$DEBUG
);
my
$curr_locale
= POSIX::setlocale(
&POSIX::LC_ALL
);
diag(
"Current locale is '$curr_locale'"
)
if
(
$DEBUG
);
my
$lconv
= POSIX::localeconv();
$lconv
=
$Module::Generic::Number::DEFAULT
if
( !
$curr_locale
);
my
(
$sep_space
,
$tho_sep
,
$dec_sep
,
$grouping
,
$n
);
if
( !
scalar
(
keys
(
%$lconv
) ) || [
split
(/\./,
$curr_locale
)]->[0] eq
'C'
)
{
diag(
"No locale could be found for language \""
, (
$ENV
{LANG} //
''
),
"\""
);
$tho_sep
=
','
;
$dec_sep
=
'.'
;
$grouping
= 3;
$n
= Module::Generic::Number->new( 10,
precision
=> 2,
thousand
=>
$tho_sep
,
decimal
=>
$dec_sep
,
grouping
=>
$grouping
,
debug
=>
$DEBUG
);
}
else
{
$tho_sep
= CORE::
length
(
$lconv
->{thousands_sep} //
''
)
?
$lconv
->{thousands_sep}
:
$lconv
->{mon_thousands_sep};
$dec_sep
= CORE::
length
(
$lconv
->{decimal_point} //
''
)
?
$lconv
->{decimal_point}
:
$lconv
->{mon_decimal_point};
$grouping
= CORE::
length
(
$lconv
->{grouping} //
''
)
? [
unpack
(
"C*"
,
$lconv
->{grouping} )]->[0]
: [
unpack
(
"C*"
,
$lconv
->{mon_grouping} )]->[0];
$grouping
//= 0;
$n
= Module::Generic::Number->new( 10,
precision
=> 2,
debug
=>
$DEBUG
);
}
$sep_space
=
int
(
$lconv
->{p_sep_by_space} // 0 ) > 0 ?
qr/[[:blank:]\h]+/
:
''
;
if
( !
defined
(
$n
) )
{
diag(
"Error: '"
, Module::Generic::Number->error,
"'"
);
BAIL_OUT( Module::Generic::Number->error );
}
my
$new_loc
=
$n
->lang;
my
$n2
=
$n
->clone;
is(
$n2
->locale,
$new_loc
,
"Locale is kept with cloning"
);
$n2
->symbol(
'€'
);
no
warnings;
my
$n_fail
= Module::Generic::Number->new(
'USD One'
);
is(
$n_fail
,
undef
,
'Invalid number'
);
SKIP:
{
my
(
@paths
) = File::Which::which(
'locale'
);
my
@ok_langs
;
foreach
my
$p
(
@paths
)
{
(
@ok_langs
) =
eval
{
qx( $p -a )
;
};
last
if
( !$@ );
}
if
( !
scalar
(
@ok_langs
) || !
scalar
(
grep
( /^fr_FR/,
@ok_langs
) ) )
{
skip(
'Unsupported language'
, 4 );
}
my
$n_loc
= Module::Generic::Number->new( 100, {
lang
=>
'fr_FR'
,
precede
=> 1,
precision
=> 2,
thousand
=>
' '
,
decimal
=>
','
,
debug
=> 0 });
isa_ok(
$n_loc
,
'Module::Generic::Number'
,
'Object with locale language string'
);
is(
$n_loc
->precision, 2,
'French precision => 2'
);
like(
$n_loc
->thousand,
qr/[[:blank:]\h]+/
,
'French thousand separator => space'
);
is(
$n_loc
->decimal,
','
,
'French decimal separator => comma'
);
};
isa_ok(
$n
,
'Module::Generic::Number'
,
'Number Class Object'
);
isa_ok(
$n2
,
'Module::Generic::Number'
,
'Cloning object'
);
is(
"$n"
, 10,
'Stringification'
);
isa_ok( (
$n
/ 2 ),
'Module::Generic::Number'
,
'Product blessed in Module::Generic::Number'
);
is( 4 -
$n
, -6,
'Subtracting with swap'
);
is(
$n
* 20, 200,
'Multiplication'
);
is( (
$n
+ 100 ) / 2, 55,
'Division'
);
is(
$n
+ 100, 110,
'Addition'
);
is(
$n
- 2, 8,
'Subtracting'
);
is(
$n
% 3, 1,
'Modulus with remainder'
);
is(
$n
% 2, 0,
'Modulus without remainder'
);
is(
$n
*= 3, 30,
'Multiplication assignment'
);
is(
$n
/= 5, 6,
'Division assignment'
);
is(
$n
+= 2, 8,
'Addition assignment'
);
is(
$n
-= 4, 4,
'Subtraction assignment'
);
is(
$n
%= 2, 0,
'Modulus assignment'
);
is( (
$n
+ 2 ) ** 3, 8,
'Exponent'
);
$n
+= 2;
is(
$n
**= 3, 8,
'Exponent assignment'
);
is(
$n
& 11, 8,
'Bitwise AND'
);
is(
$n
| 11, 11,
'Bitwise OR'
);
is(
$n
^ 11, 3,
'Bitwise XOR'
);
is(
$n
<< 2, 32,
'Bitwise shift left'
);
is(
$n
>> 2, 2,
'Bitwise shift right'
);
is(
$n
<<= 2, 32,
'Bitwise shift left assignment'
);
is(
$n
>>= -2, 128,
'Bitwise shift right assignment'
);
is(
$n
x 2, 128128,
'String multiplication'
);
is(
$n
x= 2, 128128,
'String multiplication assignment'
);
is(
$n
.= 4, 1281284,
'String concatenation with numbers'
);
ok(
$n
< 1281285,
'Lower than'
);
ok( 10 <
$n
,
'Lower than (bis)'
);
ok(
$n
lt 1281285,
'Lower than (lt)'
);
ok(
$n
<= 1281284,
'Lower than or equal'
);
ok(
$n
le 1281284,
'Lower than or equal (le)'
);
ok( !(
$n
<= 1281283 ),
'Not lower than or equal'
);
ok(
$n
> 10,
'Higher than'
);
ok(
$n
gt 10,
'Higher than (gt)'
);
ok(
$n
>= 1281284,
'Higher than or equal'
);
ok(
$n
ge 1281284,
'Higher than or equal (ge)'
);
is( 10 <=>
$n
, -1,
'Numerical comparison lower'
);
is( 1281284 <=>
$n
, 0,
'Numerical comparison equal'
);
is( 1281285 <=>
$n
, 1,
'Numerical comparison higher'
);
ok( 1281284 ==
$n
,
'Equal'
);
ok(
$n
!=
'Hello'
,
'Not equal string'
);
ok(
$n
!=
$n2
,
'Not equal number'
);
ok(
$n
eq 1281284,
'Equal as string'
);
ok(
$n
ne
$n2
,
'Not equal as string'
);
my
$bool
=
$n
!=
'Bonjour'
;
is( ++
$n
, 1281285,
'Incrementing'
);
is(
$n
++, 1281286,
'Incrementing (bis)'
);
is(
$n
--, 1281285,
'Decrementing'
);
is( --
$n
, 1281284,
'Decrementing (bis)'
);
isa_ok(
$n
,
'Module::Generic::Number'
,
'Class object check'
);
is(
$n
. 2, 12812842,
'Concatenation'
);
isa_ok(
$n
,
'Module::Generic::Number'
,
'Class object check (bis)'
);
isa_ok(
$n
,
'Module::Generic::Number'
,
'Number regexp check after concatenation'
);
is(
$n
.=
'X'
,
'1281284X'
,
'String concatenation with non-number'
);
isa_ok(
$n
,
'Module::Generic::Scalar'
,
'Regexp check after concatenation and class -> Module::Generic::Scalar'
);
is(
$n2
->decimal,
$dec_sep
,
"Decimal separator -> '"
. (
defined
(
$dec_sep
) ?
$dec_sep
: '
undef
' ) . "'
" );
is( (
$n2
->thousand //
''
), (
$tho_sep
//
''
),
"Thousand separator -> '"
. (
defined
(
$tho_sep
) ?
$tho_sep
: '
undef
' ) . "'
" );
is( (
$n2
->grouping //
''
), (
$grouping
//
''
),
"Grouping digit -> '"
. (
defined
(
$grouping
) ?
$grouping
: '
undef
' ) . "'
" );
is(
$n2
->precision, 2,
"Precision -> '2'"
);
is(
$n2
->currency,
'€'
,
"Currency symbol -> '€'"
);
isa_ok(
$n2
->currency,
'Module::Generic::Scalar'
,
'Returns property as string object'
);
diag(
"Number to unformat is '$n'"
)
if
(
$DEBUG
);
my
$n3
=
$n2
->unformat(
$n
);
isa_ok(
$n3
,
'Module::Generic::Number'
,
'Unformat result in new object using unformat()'
);
diag(
"Error unformating $n: "
,
$n2
->error )
if
( !
defined
(
$n3
) &&
$DEBUG
);
is(
$n3
, 1281284,
'Unformat resulting value'
);
is(
$n3
->precision, 2,
'New object precision'
);
$dec_sep
=
''
if
( !
defined
(
$dec_sep
) );
$tho_sep
=
''
if
( !
defined
(
$tho_sep
) );
is(
$n3
->
format
,
"1${tho_sep}281${tho_sep}284${dec_sep}00"
,
"Formatting number using format() -> 1${tho_sep}281${tho_sep}284${dec_sep}00"
);
is(
$n3
->currency,
'€'
,
"Currency symbol -> '€'"
);
my
$n_money
=
$n3
->format_money;
if
(
$n3
->precede )
{
like(
"$n_money"
,
qr/€${sep_space}1${tho_sep}281${tho_sep}284${dec_sep}00/
,
'Formatting money using format_money()'
);
}
else
{
like(
"$n_money"
,
qr/1${tho_sep}281${tho_sep}284${dec_sep}00${sep_space}€/
,
'Formatting money using format_money()'
);
}
isa_ok(
$n_money
,
'Module::Generic::Scalar'
,
'Returns string object upon formatting'
);
$n3
*= -1;
is(
$n3
, -1281284,
'Negative number'
);
like(
$n3
->format_negative(
'(x)'
),
qr/\(1${tho_sep}281${tho_sep}284${dec_sep}00\)/
,
"Formatting negative number => (1${tho_sep}281${tho_sep}284${dec_sep}00)"
);
my
$n4
=
$n3
->
abs
;
is(
$n4
, 1281284,
'abs'
);
is(
$n4
->atan, POSIX::atan(
$n4
),
'atan'
);
is(
$n4
->
atan2
(12), CORE::
atan2
(
$n4
, 12 ),
'atan2'
);
my
$n5
=
$n4
->cbrt;
is(
$n5
, POSIX::cbrt(
$n4
),
'cbrt'
);
is(
$n5
->ceil, POSIX::ceil(
$n5
),
'ceil'
);
is(
$n5
->floor, POSIX::floor(
$n5
),
'floor'
);
is(
$n4
->
cos
, CORE::
cos
(
$n4
),
'cos'
);
is(
$n4
->clone( 3 )->
exp
, POSIX::
exp
( 3 ),
'exp'
);
is(
$n5
->
int
, CORE::
int
(
$n5
),
'int'
);
ok( !
$n5
->is_negative,
'Not negative'
);
ok(
$n3
->is_negative,
'Is Negative'
);
ok(
$n5
->is_positive,
'Is positive'
);
ok( !
$n3
->is_positive,
'Is not positive'
);
is(
$n4
->
log
, CORE::
log
(
$n4
),
'log'
);
is(
$n4
->log2, POSIX::log2(
$n4
),
'log2'
);
is(
$n4
->log10, POSIX::log10(
$n4
),
'log10'
);
is(
$n4
->max( 1281285 ), 1281285,
'max'
);
is(
$n4
->min( 1281285 ), 1281284,
'min'
);
is(
$n4
->mod( 3 ), 2,
'mod'
);
is(
$n4
->
oct
, 10,
'oct'
);
is(
$n4
->clone( 3.14159265358979323846 )->round( 4 ), 3.1416,
'Rounding'
);
is(
$n4
->
sin
, CORE::
sin
(
$n4
),
'sin'
);
is(
$n4
->
sqrt
, CORE::
sqrt
(
$n4
),
'sqrt'
);
is(
$n4
->tan, POSIX::tan(
$n4
),
'tan'
);
my
$pie
=
$n4
->clone( 3.14159265358979323846 );
is(
$pie
->
length
, CORE::
length
(
$pie
),
'Number length'
);
ok(
$n4
->is_finite,
'Is finite number'
);
ok(
$n4
->clone( 3.14159265358979323846 )->is_float,
'Is float'
);
ok(
$n4
->is_int,
'Is integer'
);
ok( !
$n4
->is_nan,
'Is NaN'
);
ok(
$n4
->is_positive,
'Is positive number'
);
ok( !
$n4
->is_negative,
'Is negative number'
);
ok(
$n4
->is_normal,
'Is normal number'
);
my
$inf
= Module::Generic::Number->new( 9**9**9,
debug
=> 3 );
isa_ok(
$inf
,
'Module::Generic::Infinity'
,
'Infinity Class'
);
is(
"$inf"
,
"Inf"
,
'Infinity stringified'
);
ok(
$inf
->is_infinite,
'Is infinite'
);
ok( !
$inf
->is_normal,
'Is not normal number'
);
is(
$inf
* 10,
'Inf'
,
'Infinity overloaded'
);
$inf
*= -10;
is(
$inf
,
'-Inf'
,
'Negative infinity overloaded'
);
ok(
$inf
->is_negative,
'Is negative infinity'
);
$inf
++;
my
$inf_p
=
$inf
->clone(
'Inf'
);
is(
$inf_p
+
$inf
,
'NaN'
,
'Infinity to NaN'
);
isa_ok(
$inf_p
+
$inf
,
'Module::Generic::Nan'
,
'Infinity to NaN'
);
isa_ok(
$inf
** 9 / 1000 -
$inf
,
'Module::Generic::Nan'
,
'Infinity multiple operations'
);
isa_ok(
$inf
** 9 / 1000,
'Module::Generic::Infinity'
,
'Infinity multiple operations (bis)'
);
my
$v
=
$inf
->
abs
;
isa_ok(
$inf
->
abs
->max(10)->floor,
'Module::Generic::Infinity'
,
'Infinity chaining'
);
my
$nan
= Module::Generic::Number->new(
'NaN'
);
isa_ok(
$nan
,
'Module::Generic::Nan'
,
'NaN Class'
);
is(
"$nan"
,
"NaN"
,
'NaN stringified'
);
ok(
$nan
->is_nan,
'NaN is NaN'
);
ok( !
$nan
->is_normal,
'NaN is not normal number'
);
is(
$nan
->min( 10 ), 10,
'NaN with min'
);
is(
$nan
->max( 10 ), 10,
'NaN with max'
);
is(
$nan
* 10,
'NaN'
,
'NaN overloaded'
);
$n4
->debug(
$DEBUG
);
is(
$n4
->format_bytes,
"1${dec_sep}22M"
,
'Formatting as bytes'
);
is(
$n4
->format_hex,
'0x138D04'
,
'Formatting as hexadecimal -> 0x138D04'
);
is(
$n4
->format_binary,
'100111000110100000100'
,
'Formatting as binary'
);
is(
$n4
->from_hex(
$n4
->format_hex ), 1281284,
'Converting from hex'
);
is(
$n4
->from_binary(
$n4
->format_binary ), 1281284,
'Converting from binary'
);
isa_ok( Module::Generic::Number->new( 0 )->as_boolean,
'Module::Generic::Boolean'
,
'Number to boolean object'
);
ok( !Module::Generic::Number->new( 0 )->as_boolean,
'Number to false boolean'
);
ok( Module::Generic::Number->new( 2 )->as_boolean,
'Number to true boolean'
);
ok( Module::Generic::Number->new( 2 )->as_boolean == 1,
'Number to boolean, checking value'
);
is( Module::Generic::Number->new( 74 )->
chr
,
'J'
,
'Number to character'
);
my
$n6
= Module::Generic::Number->new( 10 );
my
$s6
=
$n6
->as_scalar;
isa_ok(
$s6
,
'Module::Generic::Scalar'
,
'as_scalar'
);
ok(
$n6
eq
"10"
,
"stringified value"
);
my
$a
=
$n6
->as_array;
isa_ok(
$a
,
'Module::Generic::Array'
,
'as_array => Module::Generic::Array'
);
is(
$a
->[0], 10,
'as_array'
);
done_testing();