use Test;
use lib 'lib';
use Noise::Simplex::Native;

# The RAII model relies on the closures returned by create-noise2d /
# create-noise3d capturing `self` strongly. Without that, dropping the
# Simplex binding and forcing GC would free the native ctx out from
# under the closure, and the next sample call would segfault. This
# test exercises exactly that scenario.

plan 4;

my &n2d;
my &n3d;
my $reference;

{
    my $s = Noise::Simplex::Native::Simplex.new(seed => 12345);
    &n2d = $s.create-noise2d;
    &n3d = $s.create-noise3d;
    # Cache reference values while $s is in scope.
    $reference = (n2d(0.5, 0.5), n3d(0.1, 0.2, 0.3));
    # $s leaves scope here. The closures must keep it alive.
}

# Force GC pressure by allocating a lot.
my @junk;
@junk.push: ('x' x 1024) for ^4096;
@junk = ();

# After the original Simplex binding is dead and GC has been pushed,
# the closures should still produce identical output. If the ctx had
# been freed, MoarVM would either segfault or return garbage.
my $a = n2d(0.5, 0.5);
my $b = n3d(0.1, 0.2, 0.3);

ok $a.defined, 'closure still callable after Simplex binding dropped (2D)';
ok $b.defined, 'closure still callable after Simplex binding dropped (3D)';
is $a, $reference[0], '2D output unchanged after binding drop';
is $b, $reference[1], '3D output unchanged after binding drop';

done-testing;
