Data-IntervalTree-Shared

 view release on metacpan or  search on metacpan

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

    for my $r (@all) {
        is $r->{lo}, $iv[$r->{id}][0], "result id $r->{id} has the producer's lo" if $r->{id} <= 5;
    }
    # a point stab is exactly overlaps(p, p), also on the read-only view
    my @a = sort { $a <=> $b } map { $_->{id} } $ro->stab(321);
    my @b = sort { $a <=> $b } map { $_->{id} } $ro->overlaps(321, 321);
    is_deeply \@a, \@b, 'stab($p) == overlaps($p, $p) via read-only view';
    # argument validation still runs (no lock needed for this check either)
    like exception(sub { $ro->overlaps(10, 5) }), qr/lo.*>.*hi/, 'overlaps lo>hi still croaks read-only';

    my $st = $ro->stats;
    is $st->{frozen},   1, 'stats.frozen set';
    is $st->{readonly}, 1, 'stats.readonly set';
    is $st->{dirty},    0, 'stats.dirty is 0 read-only';
    is $st->{count}, scalar(@iv), 'stats.count read-only';
    is $st->{capacity}, 1000, 'stats.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->add(1, 2) }), qr/read-only/, 'add on read-only view croaks';
    like exception(sub { $ro->build }),     qr/read-only/, 'build 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 $view1 = Data::IntervalTree::Shared->new_readonly($path);
    my $view2 = Data::IntervalTree::Shared->new_readonly($path);
    my @res1 = $view1->stab(500);
    my @res2 = $view2->stab(500);
    ok @res1 && @res2, 'two read-only views query the same file';
    is_deeply [sort { $a <=> $b } map { $_->{id} } @res1],
              [sort { $a <=> $b } map { $_->{id} } @res2],
              'both views see identical results';
}

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

# ---- new_readonly rejects a non-frozen file ----
{
    my $u = "$dir/unsealed.it";
    { my $it = Data::IntervalTree::Shared->new($u, 100); $it->add(1, 2, 1); }
    like exception(sub { Data::IntervalTree::Shared->new_readonly($u) }),
         qr/not frozen/, 'new_readonly on an unsealed file croaks';
}

# ---- new_readonly error paths ----
like exception(sub { Data::IntervalTree::Shared->new_readonly("$dir/does-not-exist.it") }),
     qr/open|No such/, 'new_readonly on a missing path croaks';
like exception(sub { Data::IntervalTree::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 0.734 second using v1.01-cache-2.11-cpan-54e63673c56 )