Data-HashMap

 view release on metacpan or  search on metacpan

t/11-ttl.t  view on Meta::CPAN

    my $v = hm_ii_get $m, 42;
    ok(!defined $v, 'TTL: get after expiry returns undef');
    {
        my $e = hm_ii_exists $m, 42;
        ok(!$e, 'TTL: exists after expiry returns false');
    }
}

# ---- Expired entry is tombstoned (size decreases) ----

{
    my $m = Data::HashMap::II->new(0, 1);
    hm_ii_put $m, 1, 10;
    hm_ii_put $m, 2, 20;
    is(hm_ii_size $m, 2, 'TTL: size = 2 before expiry');

    sleep 2;

    # Trigger lazy expiry
    hm_ii_get $m, 1;
    hm_ii_get $m, 2;
    is(hm_ii_size $m, 0, 'TTL: size = 0 after expired gets');
}

# ---- Remove on expired entry returns false ----

{
    my $m = Data::HashMap::II->new(0, 1);
    hm_ii_put $m, 1, 10;
    ok(hm_ii_remove $m, 1, 'TTL: remove before expiry returns true');

    hm_ii_put $m, 2, 20;
    sleep 2;
    {
        my $r = hm_ii_remove $m, 2;
        ok(!$r, 'TTL: remove after expiry returns false');
    }
    is(hm_ii_size $m, 0, 'TTL: size = 0 after expired remove');
}

# ---- Non-expired entries returned normally ----

{
    my $m = Data::HashMap::II->new(0, 60);
    hm_ii_put $m, 1, 10;
    hm_ii_put $m, 2, 20;
    is(hm_ii_get $m, 1, 10, 'TTL 60s: non-expired get returns value');
    is(hm_ii_get $m, 2, 20, 'TTL 60s: non-expired get returns value');
}

# ---- Put refreshes TTL on update ----

{
    my $m = Data::HashMap::II->new(0, 3);
    hm_ii_put $m, 1, 10;
    sleep 1;
    # Re-put refreshes TTL
    hm_ii_put $m, 1, 20;
    sleep 2;
    # 3 seconds since original put, but only 2 since refresh (TTL=3)
    is(hm_ii_get $m, 1, 20, 'TTL: put refresh keeps entry alive');
}

# ---- Iteration skips expired entries ----

{
    my $m = Data::HashMap::II->new(0, 1);
    hm_ii_put $m, 1, 10;
    hm_ii_put $m, 2, 20;

    my @k = sort { $a <=> $b } (hm_ii_keys $m);
    is_deeply(\@k, [1, 2], 'TTL iteration: before expiry, all keys');

    sleep 2;

    @k = hm_ii_keys $m;
    is(scalar(@k), 0, 'TTL iteration: after expiry, no keys');

    my @v = hm_ii_values $m;
    is(scalar(@v), 0, 'TTL iteration: after expiry, no values');

    my @items = hm_ii_items $m;
    is(scalar(@items), 0, 'TTL iteration: after expiry, no items');
}

# ---- Counter ops on expired key treat as new key ----

{
    my $m = Data::HashMap::II->new(0, 1);
    hm_ii_put $m, 1, 100;
    sleep 2;

    # incr on expired key should create new with value 1
    is(hm_ii_incr $m, 1, 1, 'TTL counter: incr on expired key returns 1 (new key)');
}

# ---- SS variant TTL ----

{
    my $m = Data::HashMap::SS->new(0, 1);
    hm_ss_put $m, "hello", "world";
    is(hm_ss_get $m, "hello", "world", 'SS TTL: before expiry');

    sleep 2;

    my $v = hm_ss_get $m, "hello";
    ok(!defined $v, 'SS TTL: after expiry returns undef');
}

# ---- SI variant TTL with counters ----

{
    my $m = Data::HashMap::SI->new(0, 1);
    hm_si_put $m, "x", 42;
    sleep 2;

    my $v = hm_si_get $m, "x";
    ok(!defined $v, 'SI TTL: expired get returns undef');

    is(hm_si_incr $m, "x", 1, 'SI TTL: incr on expired key returns 1');
}



( run in 1.541 second using v1.01-cache-2.11-cpan-39bf76dae61 )