Data-RadixTree-Shared

 view release on metacpan or  search on metacpan

t/03-frozen.t  view on Meta::CPAN

    is $ro->longest_prefix("10.0.0.5"), 300, 'longest_prefix full chain via read-only view';
    is $ro->longest_prefix("10.0.9"),   200, 'longest_prefix backs off to "10.0" via read-only view';
    is $ro->longest_prefix("10.5"),     100, 'longest_prefix backs off to "10" via read-only view';
    is $ro->longest_prefix("foobarx"),    2, 'longest_prefix over a split edge via read-only view';
    is $ro->longest_prefix("foo"),        1, 'longest_prefix exact match via read-only view';
    ok !defined($ro->longest_prefix("zzz")), 'longest_prefix with no stored prefix is undef via read-only view';

    is $ro->count, $nkeys, 'count works read-only (lock-free)';
    is $ro->size,  $nkeys, 'size alias works read-only';

    my $st = $ro->stats;
    is ref($st), 'HASH', 'stats returns a hashref read-only';
    is $st->{frozen},   1, 'stats.frozen set';
    is $st->{readonly}, 1, 'stats.readonly set';
    is $st->{keys}, $nkeys, 'stats.keys matches read-only';
    cmp_ok $st->{nodes_capacity}, '>=', 2, 'stats nodes_capacity present read-only';
    cmp_ok $st->{nodes_used}, '<=', $st->{nodes_capacity}, 'stats nodes_used within capacity read-only';
    cmp_ok $st->{arena_capacity}, '>=', 1, 'stats arena_capacity present read-only';
    cmp_ok $st->{arena_used}, '<=', $st->{arena_capacity}, 'stats arena_used within capacity read-only';

    is $ro->path, $path, 'path readable read-only';
    is $ro->memfd, -1, 'memfd readable read-only (file-backed => -1)';
    eval { $ro->sync };
    ok !$@, 'sync on read-only view is a silent no-op';

    like exception(sub { $ro->insert("new-key", 1) }), qr/read-only/, 'insert on read-only view croaks';
    like exception(sub { $ro->delete("foo") }),        qr/read-only/, 'delete on read-only view croaks';
    like exception(sub { $ro->clear }),                qr/read-only/, 'clear on read-only view croaks';
    like exception(sub { $ro->freeze }),               qr/read-only/, 'freeze on read-only view croaks';
}

# ---- two independent read-only views of the same file, concurrently ----
{
    my $a = Data::RadixTree::Shared->new_readonly($path);
    my $b = Data::RadixTree::Shared->new_readonly($path);
    ok $a->lookup("foo") && $b->lookup("foo"), 'two read-only views query the same file';
    is $a->longest_prefix("10.0.0.9"), $b->longest_prefix("10.0.0.9"),
        'two read-only views agree on longest_prefix';
}

# ---- refuse a read-write reopen of a sealed file ----
like exception(sub { Data::RadixTree::Shared->new($path, 4096, 65536) }),
     qr/frozen|read-only/, 'read-write reopen of a sealed file is refused';

# ---- new_readonly rejects a non-frozen file ----
{
    my $u = "$dir/unsealed.rdx";
    { my $t = Data::RadixTree::Shared->new($u, 4096, 65536); $t->insert("q", 1); }
    like exception(sub { Data::RadixTree::Shared->new_readonly($u) }),
         qr/not frozen/, 'new_readonly on an unsealed file croaks';
}

# ---- new_readonly error paths ----
like exception(sub { Data::RadixTree::Shared->new_readonly("$dir/does-not-exist.rdx") }),
     qr/open|No such/, 'new_readonly on a missing path croaks';
like exception(sub { Data::RadixTree::Shared->new_readonly(undef) }),
     qr/required/, 'new_readonly requires a path';

done_testing;

# minimal exception helper (avoid a Test::Fatal dependency)
sub exception {
    my $code = shift;
    my $err;
    { local $@; eval { $code->(); 1 } or $err = $@; }
    return $err;
}



( run in 1.070 second using v1.01-cache-2.11-cpan-54e63673c56 )