use strict;
use warnings;
use Test::More;
use Scalar::Util qw(weaken);
use DBIx::Fast;

# Regression test for the reference-cycle / memory leak (rank 2):
#  - the HandleError closure on the DBI handle captures $self strongly, and
#  - DBIx::Fast::Base holds an un-weakened $dbix back-reference.
# Both create a cycle so a DBIx::Fast handle is never freed. We assert the
# object IS reclaimed when its last strong reference goes out of scope, using
# the standard weaken-and-check idiom (no Devel::Cycle dependency required).

eval "use DBD::SQLite 1.74";
plan skip_all => "DBD::SQLite 1.74 required" if $@;

sub make_db {
    DBIx::Fast->new(
        dsn        => 'dbi:SQLite:dbname=:memory:',
        driver     => 'SQLite',
        RaiseError => 1,
        PrintError => 0,
    );
}

subtest 'bare handle is freed on scope exit (HandleError closure cycle)' => sub {
    my $weak;
    {
        my $db = make_db();
        $weak = $db;
        weaken($weak);
        ok(defined $weak, 'object alive inside its scope');
    }
    ok(!defined $weak,
       'DBIx::Fast reclaimed after scope - HandleError closure does not retain it');
};

subtest 'handle is freed after using schema/transaction/tracker subsystems' => sub {
    my $weak;
    {
        my $db = make_db();
        $db->schema;       # DBIx::Fast::Schema      holds $dbix
        $db->transaction;  # DBIx::Fast::Transaction holds $dbix
        $db->tracker;      # DBIx::Fast::Profiler    holds $dbix
        $weak = $db;
        weaken($weak);
    }
    ok(!defined $weak,
       'DBIx::Fast reclaimed after subsystems used - no $dbix back-ref cycle');
};

done_testing;
