Config-Abstraction

 view release on metacpan or  search on metacpan

t/extended_tests.t  view on Meta::CPAN

	);
	ok(defined($cfg), 'object created with SCRIPT_NAME set (line 596 A=TRUE)');
	diag('script_name from SCRIPT_NAME: ' . ($cfg ? 'ok' : 'n/a')) if $ENV{TEST_VERBOSE};
	pass('line 596 A=TRUE covered: SCRIPT_NAME used instead of $0');
};

# ===========================================================================
# Pass both config_file AND file alias: the //= at line 359 sees LHS already
# defined, so it does NOT overwrite config_file.  This covers the //= B=FALSE
# (defined LHS) condition path.
# ===========================================================================

subtest 'new() - explicit config_file not clobbered by file alias (line 359 //= defined)' => sub {
	my $dir = tempdir(CLEANUP => 1);
	_write_file($dir, 'real.yaml', "result: correct\n");
	_write_file($dir, 'alias.yaml', "result: wrong\n");

	my $cfg = Config::Abstraction->new(
		config_file => 'real.yaml',
		file        => 'alias.yaml',   # alias: ignored because config_file already set
		config_dirs => [$dir],
	);
	ok(defined($cfg), 'object created when both config_file and file are supplied');
	is($cfg->get('result'), 'correct',
		'config_file wins over file alias (line 359 //= B=FALSE: LHS already defined)');
};

# ===========================================================================
# AUTOLOAD resolves from config when $self->{data} is undef (line 1339 A=FALSE)
# All existing AUTOLOAD tests use data=>{...}, so $self->{data} is always truthy
# (A=TRUE path).  Creating an object without data=> makes $self->{data} undef,
# forcing the || to fall through to $self->{'config'} (A=FALSE, B=TRUE).
# ===========================================================================

subtest 'AUTOLOAD - uses config hash when data attribute is undef (line 1339 A=FALSE)' => sub {
	my $dir = tempdir(CLEANUP => 1);
	# No data=> arg: $self->{data} will be undef after construction
	_write_file($dir, 'base.yaml', "mykey: autoload_val\n");

	my $cfg = Config::Abstraction->new(
		config_dirs => [$dir],
		sep_char    => '_',
	);
	ok(defined($cfg), 'object created from yaml without data arg');

	# AUTOLOAD: $self->{data} is undef → falls through to $self->{"config"}
	my $val;
	eval { $val = $cfg->mykey() };
	ok(!$@, 'AUTOLOAD call succeeds on object without data attribute') or diag("error: $@");
	is($val, 'autoload_val', 'AUTOLOAD resolves from config (line 1339 A=FALSE, B=TRUE)');
};

# ===========================================================================
# Config::Abstract hidden via local %INC + Test::Without::Module:
# - line 701 FALSE: _load_driver('Config::Abstract') returns 0
# - line 719 condition A=FALSE,B=TRUE: $data is truthy (scalar from YAML) but
#   NOT a HASH ref, which is the one sub-condition path not yet covered.
#
# Content "just a plain string" is parsed by YAML::XS as a truthy scalar.
# XMLin at line 697 fails (not XML) so $data stays as that truthy scalar.
# With Config::Abstract blocked, line 701 is FALSE → $data unchanged → line 719:
#   !$data    = FALSE (data truthy)
#   ref ne HASH = TRUE (ref is "")
# This is the previously-uncovered A=FALSE,B=TRUE condition path.
# ===========================================================================

subtest '_load_config() - 701 FALSE + 719 A=FALSE,B=TRUE via Config::Abstract hidden' => sub {
	# Remove Config::Abstract from the %INC cache so that the eval "require"
	# inside _load_driver will search @INC (where Test::Without::Module blocks it).
	# 'local %INC' restores the cache after the subtest exits.
	local %INC = %INC;
	delete $INC{'Config/Abstract.pm'};
	Test::Without::Module->import('Config::Abstract');

	my $dir = tempdir(CLEANUP => 1);
	# "just a plain string" → YAML returns a truthy scalar (not HASH).
	# XMLin at line 697 throws on non-XML → eval catches it, $data unchanged.
	# Config::Abstract hidden → line 701 FALSE → $data stays truthy scalar.
	_write_file($dir, 'plain.cfg', "just a plain string\n");

	my $cfg;
	_silenced(sub {
		$cfg = Config::Abstraction->new(
			config_file => 'plain.cfg',
			config_dirs => [$dir],
			data        => { fallback => 'ca_hidden' },
		);
	});
	# $cfg is defined because the data=> fallback provides config keys.
	ok(defined($cfg), 'object created: data fallback present when Config::Abstract hidden');
	is($cfg->get('fallback'), 'ca_hidden',
		'fallback data intact: Config::Abstract was skipped (line 701 FALSE)');
	pass('line 719 condition A=FALSE B=TRUE covered: data was truthy non-HASH scalar');

	Test::Without::Module->unimport('Config::Abstract');
};

# ===========================================================================
# Config::Abstract->new throws: line 708 TRUE + line 709
# The inner eval at line 705 catches the die, setting $err. Line 708 TRUE
# fires, line 709 undef-s $data.  Normally Config::Abstract never throws on
# an existing readable file, so we monkey-patch its constructor to force it.
# ===========================================================================

subtest '_load_config() - line 708 TRUE: Config::Abstract->new throws in inner eval' => sub {
	my $dir = tempdir(CLEANUP => 1);
	# Content that falls through to the Config::Abstract block:
	# YAML parses as scalar (non-HASH), XMLin fails (not XML), INI fails (no sections).
	_write_file($dir, 'throws.cfg', "just a plain string\n");

	my $cfg;
	_silenced(sub {
		no warnings 'redefine', 'once';
		local *Config::Abstract::new = sub { die "forced Config::Abstract error\n" };
		$cfg = Config::Abstraction->new(
			config_file => 'throws.cfg',
			config_dirs => [$dir],
			data        => { fallback => 'throws_test' },
		);
	});
	ok(defined($cfg), 'object survives when Config::Abstract->new throws (708 TRUE)');



( run in 1.297 second using v1.01-cache-2.11-cpan-800906f7e73 )