Config-Abstraction

 view release on metacpan or  search on metacpan

t/extended_tests.t  view on Meta::CPAN

	Test::Without::Module->unimport('XML::Simple');
};

# ===========================================================================
# AUTOLOAD croak when mid-path value is not a HASH (line 1351 false branch)
# ===========================================================================

# The condition `(ref($val) eq 'HASH') && exists $val->{$part}` in AUTOLOAD
# fires its else/croak when $val is NOT a hashref at some point in traversal.
# This covers the left-hand-side false branch: ref($val) ne 'HASH'.
subtest 'AUTOLOAD - croaks when intermediate key is a scalar (non-HASH)' => sub {
	my $cfg = Config::Abstraction->new(
		data        => { foo => 'bar' },
		config_dirs => [],
		sep_char    => $SEP_US,
	);
	# foo is a scalar; foo_baz tries to traverse foo→baz but foo is not HASH
	my $died = 0;
	eval { $cfg->foo_baz() };
	if($@) {
		$died = 1;
		like($@, qr/No such config key/i, 'AUTOLOAD croak message mentions key name');
	}
	ok($died, 'AUTOLOAD croaks when intermediate path value is not a HASH ref');
};

# ===========================================================================
# _parse_config_string() with logger set -- error path logs via $logger->warn
# ===========================================================================

# When _parse_config_string encounters a parse error AND a logger is attached,
# the ternary at line 1319 takes the logger->warn path instead of Carp::carp.
subtest '_parse_config_string() - parse error with logger emits logger->warn' => sub {
	my ($logger, $log_ref) = _make_spy_logger();

	# Create proxy with the spy logger already blessed (bypasses Log::Abstraction wrap)
	my $proxy = Config::Abstraction::ExtTestProxy->new(
		data        => { dummy => 1 },
		config_dirs => [],
	);
	$proxy->{'logger'} = $logger;    # directly inject spy logger

	# Malformed YAML: unclosed bracket causes YAML::XS::Load to throw
	my $result;
	_silenced(sub {
		$result = $proxy->test_parse_string("{bad yaml: [unclosed", 'remote.yaml', 'test-label');
	});
	ok(!defined($result), '_parse_config_string returns undef on YAML parse error');

	my @warns = grep { $_->[0] eq 'warn' && $_->[1] =~ /test-label/ } @{$log_ref};
	ok(scalar(@warns) > 0, 'logger->warn called for parse error in _parse_config_string')
		or diag('log: ' . join('; ', map { "$_->[0]: $_->[1]" } @{$log_ref}));
};

# ===========================================================================
# Access guard -- Illegal Operation croak (line 444-445)
# ===========================================================================

# Calling _load_config() (or _parse_config_string, _load_remote_dir) directly
# from a non-subclass caller should croak with 'Illegal Operation'.
# The UNIVERSAL::isa guard at line 444 checks (caller)[0] against __PACKAGE__.
subtest '_load_config() - illegal direct call from outside class croaks' => sub {
	my $cfg = Config::Abstraction->new(
		data        => { dummy => 1 },
		config_dirs => [],
	);
	# Direct call from package main (not a subclass) must croak
	my $died = 0;
	eval { $cfg->_load_config() };
	if($@) {
		$died = 1;
		like($@, qr/Illegal Operation/i, 'croak message mentions Illegal Operation');
	}
	ok($died, '_load_config() croaks when called from outside the class hierarchy');
};

# ===========================================================================
# XML base file failure WITHOUT logger -- Carp::carp path (line 536)
# ===========================================================================

# When a base.xml file exists but is malformed AND no logger is set, the module
# falls through to Carp::carp (line 536) instead of calling $logger->notice.
# The `if($logger)` at line 533 is FALSE in this case.
subtest '_load_config() - malformed base.xml without logger emits carp' => sub {
	my $dir = tempdir(CLEANUP => 1);
	# Valid XML header but unclosed tag: XML::Simple/XML::PP will throw
	_write_file($dir, 'base.xml', "<?xml version=\"1.0\"?><config><unclosed>\n");

	my @carps;
	local $SIG{__WARN__} = sub { push @carps, $_[0] };

	my $cfg = Config::Abstraction->new(
		data        => { fallback => 'yes' },
		config_dirs => [$dir],
		# no logger: the if($logger) at line 533 is false → Carp::carp fires
	);
	ok(defined($cfg), 'object created despite malformed base.xml without logger');
	pass('no crash when malformed base.xml without logger (Carp::carp path)');
};

# ===========================================================================
# _load_remote_dir() -- File::Slurp::Remote absent, logger set (line 1206)
# ===========================================================================

# When File::Slurp::Remote is not installed, _load_remote_dir emits a warning.
# With a logger set, the ternary `$logger ? $logger->warn(...) : Carp::carp(...)`
# at line 1206 must take the logger->warn path.
subtest '_load_remote_dir() - logger->warn when File::Slurp::Remote absent' => sub {
	Test::Without::Module->import('File::Slurp::Remote');

	my ($logger, $log_ref) = _make_spy_logger();

	my $proxy = Config::Abstraction::ExtTestProxy->new(
		data        => { dummy => 1 },
		config_dirs => [],
	);
	$proxy->{'logger'} = $logger;    # inject spy logger

	my %merged;
	_silenced(sub {
		$proxy->test_load_remote_dir('remotehost', '/etc/myapp', \%merged);



( run in 4.951 seconds using v1.01-cache-2.11-cpan-364913b4093 )