Date-Cmp
view release on metacpan or search on metacpan
t/extended_tests.t view on Meta::CPAN
# but year() differs (so line 557's inequality fires).
# =========================================================================
{
package OffYear::DateTime;
use overload '""' => sub { $_[0]->{str_year} }, fallback => 1;
sub new {
my ($class, %a) = @_;
bless { str_year => $a{str_year}, real_year => $a{real_year} }, $class;
}
sub year { $_[0]->{real_year} }
}
# =========================================================================
# 1. BEF left qualifier â pure-digit right, trailing number < right
# Target: lib/Date/Cmp.pm lines 294-297
#
# Strategy: left = 'bef 5' (1-digit trailing, so fast-paths 1 and 2 both
# fail â they require 3-4 consecutive digits). right = '100' (pure
# integer, 3-digit so fast-path 1 inner check also fails). The BEF
# handler fires; $left =~ /\s(\d+)$/ captures 5, which is < 100 â -1.
#
# NOTE â lines 305-307 (BEF left, 4-digit right via /(\d{4})/ match) are
# DEAD CODE: for left to reach line 305 it must have a 4-digit year, but
# fast-path 1 would have already returned for any differing 4-digit pair.
# When fast-path 1 ties, $1 == $ryear and the < check at line 306 is
# always false. These lines cannot be reached by any real input.
# =========================================================================
subtest 'BEF left, 1-digit trailing number < pure-digit right (lines 294-297)' => sub {
# 'bef 5': no 3-4 digit sequence â all fast-paths skipped.
# '100': 3-digit integer that passes char check.
is(datecmp('bef 5', '100'), $LT,
'bef 5 < 100 via BEF handler trailing-number comparison');
returns_ok(datecmp('bef 5', '100'), { type => 'integer' },
'return value is a defined integer');
diag 'lines 294-297 exercised: $1 (5) < $right (100) â return -1'
if $ENV{TEST_VERBOSE};
};
# =========================================================================
# 2. Lowercase 'bet' on right side fires first-digit tie-break
# Target: lib/Date/Cmp.pm lines 341-348
#
# Strategy: the /^bet/ check at line 343 is case-SENSITIVE (lowercase
# only). left = '100 and 1900': fast-path 1 extracts 1900 (4-digit),
# right = 'bet 200 and 1900' also has 1900 as its 4-digit â fast-path 1
# ties. Fast-path 2 also ties on '1900'. Body: line 341 captures the
# first \d{3,4} from left (= '100'), line 344 captures the first \d{3,4}
# from right (= '200'). 100 != 200 â return -1.
# =========================================================================
subtest 'lowercase "bet" right â first-match tie-break (lines 341-348)' => sub {
# Fast-paths tie on trailing 1900; first-match extraction differs (100 vs 200).
is(datecmp('100 and 1900', 'bet 200 and 1900'), $LT,
'100 (left first-digit) < 200 (right first-digit) via bet path');
# Uppercase BET is handled by the separate range handler (line 361),
# NOT by this branch â confirm the two paths stay independent.
is(datecmp('1900', 'BET 1900 AND 1900', sub {}), $EQ,
'uppercase BET with same endpoints == 0 (handled by range handler)');
returns_ok(datecmp('100 and 1900', 'bet 200 and 1900'), { type => 'integer' },
'return value is a defined integer');
diag 'lines 341-348 exercised: lowercase bet, start(100) != end(200) â -1'
if $ENV{TEST_VERBOSE};
};
# =========================================================================
# 3. BEF right qualifier â left is a pure-digit string
# Target: lib/Date/Cmp.pm lines 454-455
#
# Strategy: left = '1939' (pure digits). right = 'bef 1939'. Fast-paths
# 1 and 2 both extract 1939 â tie. Right-side handler: /^bef/i fires,
# $left =~ /^\d+$/ is TRUE, /\s(\d+)$/ extracts 1939 â return $left<=>$1.
#
# NOTE â line 455 returns 0 here because the years are equal. A non-zero
# result from line 455 requires $left to differ from the trailing number in
# right, but fast-path 2 would have already returned for any such pair.
# Line 455 only ever returns 0 in practice.
# =========================================================================
subtest 'BEF right qualifier with pure-digit left (lines 454-455)' => sub {
is(datecmp('1939', 'bef 1939'), $EQ,
'1939 == bef 1939 (same year, fast-paths tie, BEF handler fires)');
# Verify with a full "bef day-month year" string too.
is(datecmp('1939', 'bef 5 Jun 1939'), $EQ,
'1939 == bef 5 Jun 1939 (trailing 1939 extracted)');
returns_ok(datecmp('1939', 'bef 1939'), { type => 'integer' },
'return value is a defined integer');
diag 'lines 454-455 exercised: $left (1939) <=> $1 (1939) = 0'
if $ENV{TEST_VERBOSE};
};
# =========================================================================
# 4. Inverted right-side range (from > to) â STDERR path
# Target: lib/Date/Cmp.pm lines 494-500
#
# Strategy: right = '1902-1900' parses to from=1902, to=1900; from > to
# â STDERR message + return 0. Fast-paths skip the range string because
# fast-path 1 excludes /^\d{3,4}\-\d{3,4}$/ right-forms and fast-path 2
# excludes strings containing a dash.
# =========================================================================
subtest 'inverted right-side range (from > to) returns 0 (lines 494-500)' => sub {
is(silence_stderr { datecmp('1901', '1902-1900') }, $EQ,
'inverted RHS range 1902-1900 returns 0');
# Symmetric â also works with BET form when from > to (requires
# case-sensitive Bet ... and ... format for the range regex).
# Plain inverted dash form is enough to hit lines 494-500.
returns_ok(silence_stderr { datecmp('1901', '1902-1900') }, { type => 'integer' },
'return value is a defined integer');
diag 'lines 494-500 exercised: from(1902) > to(1900) â STDERR + return 0'
if $ENV{TEST_VERBOSE};
};
t/extended_tests.t view on Meta::CPAN
'year equal to start of range also returns an integer');
diag "MockDFG calls: ${\$mock->call_count()}" if $ENV{TEST_VERBOSE};
};
# =========================================================================
# 6. Left-side BET range, DFG fails right, NO year suffix â die
# Target: lib/Date/Cmp.pm lines 390-394
#
# Strategy: same BET left as above but right = 'strange text' which has
# no trailing [\s\/]\d{4} sequence. After DFG failure the /[\s\/](\d{4})$/
# check at line 377 fails â STDERR + die "Date parse failure: right = ...".
# =========================================================================
subtest 'BET left range, DFG fails right, no year suffix â die (lines 390-394)' => sub {
{
my $mock = MockDFG->new();
local $Date::Cmp::dfg = $mock;
$mock->enqueue([]); # DFG failure for right
throws_ok {
silence_stderr { datecmp('BET 1820 AND 1830', 'strange text') }
} qr/Date parse failure.*right/,
'right with no year suffix after DFG failure â die';
}
{
my $mock = MockDFG->new();
local $Date::Cmp::dfg = $mock;
$mock->enqueue([]);
throws_ok {
silence_stderr { datecmp('BET 1820 AND 1830', 'some stuff') }
} qr/Date parse failure/,
'any right with no extractable year â die (lines 390-394)';
}
diag 'lines 390-394 exercised: DFG fail + no year suffix â die'
if $ENV{TEST_VERBOSE};
};
# =========================================================================
# 7. Right-side range with from==to, left is a DateTime ref
# Target: lib/Date/Cmp.pm line 491
#
# Strategy: left = '1 Feb 1900' is a complex date that goes through DFG
# (MockDFG returns Fake::DateTime(1900)). right = '1900-1900' triggers
# the from==to branch (line 485) and then the ref($left) check (line 490)
# â return $left->year() <=> $from = 0.
#
# Fast-paths are bypassed: the dash in right disables FP2; the pattern
# /^\d{3,4}\-\d{3,4}$/ match in right disables FP1.
# =========================================================================
subtest 'right range from==to with DateTime left (line 491)' => sub {
{
my $mock = MockDFG->new();
local $Date::Cmp::dfg = $mock;
$mock->enqueue([ Fake::DateTime->new(year => 1900) ]);
my $complaint;
is(datecmp('1 Feb 1900', '1900-1900', sub { $complaint = $_[0] }),
$EQ, 'DateTime left <=> same-endpoint RHS range = 0 (line 491)');
like($complaint, qr/from == to/,
'complain callback fires for same-endpoint range');
}
{
# Without complain: same result, no crash.
my $mock = MockDFG->new();
local $Date::Cmp::dfg = $mock;
$mock->enqueue([ Fake::DateTime->new(year => 1901) ]);
is(datecmp('1 Feb 1901', '1901-1901'), $EQ,
'DateTime year 1901 vs same-endpoint range 1901-1901 = 0');
}
returns_ok(
do {
my $mock = MockDFG->new();
local $Date::Cmp::dfg = $mock;
$mock->enqueue([ Fake::DateTime->new(year => 1900) ]);
datecmp('1 Feb 1900', '1900-1900');
},
{ type => 'integer' },
'return value is a defined integer'
);
diag 'line 491 exercised: ref($left)->year() <=> from when from==to'
if $ENV{TEST_VERBOSE};
};
# =========================================================================
# 8. ref($left), DFG fails right, extracted year != left->year()
# Target: lib/Date/Cmp.pm lines 556-558
#
# Strategy: MockDFG returns an OffYear::DateTime for left ('1 Feb 1892').
# OffYear::DateTime stringifies to '1892' (so line 532's tie-check sees
# 1892 == 1892 and does NOT return early), but year() returns 1895.
# For right ('5/27/1892') MockDFG returns failure; the /[\s\/](\d{4})$/
# suffix extracts 1892. Then: ref($left) is TRUE, $left->year() (1895)
# != $year (1892) â return 1895 <=> 1892 = 1.
#
# Fast-paths are bypassed: both strings contain 1892 as their 4-digit
# year so FP1 and FP2 both tie.
#
# DEAD CODE note â lines 561-562 ("if($left != $year) { return $left<=>
# $year }") require left to be a plain non-ref value that differs from
# the suffix year, while fast-path 2 would have already returned for any
# such pair. These lines cannot be reached with real inputs and should
# be removed.
# =========================================================================
subtest 'ref(left), DFG fails right, year differs â compare (lines 556-558)' => sub {
my $mock = MockDFG->new();
local $Date::Cmp::dfg = $mock;
# OffYear::DateTime: str='1892' (tie at line 532), year()=1895 (differs
# from right's suffix year 1892 â fires line 557 inequality).
$mock->enqueue([ OffYear::DateTime->new(str_year => '1892', real_year => 1895) ]);
# Second DFG call (for right '5/27/1892') exhausts the queue â failure.
is(datecmp('1 Feb 1892', '5/27/1892'), $GT,
'ref(left)->year()(1895) > suffix-year(1892) â GT (lines 556-558)');
returns_ok(
do {
my $mock2 = MockDFG->new();
local $Date::Cmp::dfg = $mock2;
$mock2->enqueue([ OffYear::DateTime->new(str_year => '1892', real_year => 1895) ]);
datecmp('1 Feb 1892', '5/27/1892');
},
{ type => 'integer' },
'return value is a defined integer'
);
( run in 1.088 second using v1.01-cache-2.11-cpan-9789f410c06 )