Config-Abstraction

 view release on metacpan or  search on metacpan

t/edge_cases.t  view on Meta::CPAN

	my $dir = tempdir(CLEANUP => 1);
	_write_file($dir, 'base.toml',  qq{host = "base_host"\nport = 5432\n});
	_write_file($dir, 'local.toml', qq{host = "local_host"\n});

	my $cfg = Config::Abstraction->new(
		data        => {},
		config_dirs => [$dir],
		env_prefix  => $ENV_PREFIX,
	);
	is($cfg->get('host'), 'local_host', 'local.toml host overrides base.toml host');
	is($cfg->get('port'), 5432,         'base.toml port survives when local.toml does not mention it');
};

subtest 'TOML: data constructor has lower precedence than base.toml' => sub {
	plan skip_all => 'TOML::Tiny not installed' unless eval { require TOML::Tiny; 1 };

	my $dir = tempdir(CLEANUP => 1);
	_write_file($dir, 'base.toml', qq{host = "toml_host"\n});

	my $cfg = Config::Abstraction->new(
		data        => { host => 'data_host', extra => 'kept' },
		config_dirs => [$dir],
		env_prefix  => $ENV_PREFIX,
	);
	is($cfg->get('host'),  'toml_host', 'base.toml overrides data constructor value');
	is($cfg->get('extra'), 'kept',      'data key not in base.toml survives');
};

subtest 'TOML: TOML boolean and array types are loaded without corruption' => sub {
	# TOML::Tiny returns Perl values: booleans as JSON::PP::Boolean objects,
	# arrays as arrayrefs.  Verify they arrive intact.
	plan skip_all => 'TOML::Tiny not installed' unless eval { require TOML::Tiny; 1 };

	my $dir = tempdir(CLEANUP => 1);
	_write_file($dir, 'base.toml', qq{debug = true\ntags = ["web", "api"]\n});

	my $cfg = Config::Abstraction->new(
		data        => {},
		config_dirs => [$dir],
		env_prefix  => $ENV_PREFIX,
	);
	ok($cfg->get('debug'), 'TOML boolean true is truthy');
	my $tags = $cfg->get('tags');
	ok(ref($tags) eq 'ARRAY', 'TOML array is loaded as arrayref');
	is($tags->[0], 'web', 'first TOML array element is correct');
	is($tags->[1], 'api', 'second TOML array element is correct');
};

subtest 'TOML: malformed TOML file is skipped with a carp warning' => sub {
	# A TOML file with syntax errors should emit a carp and be skipped,
	# not abort construction.  data values must survive.
	plan skip_all => 'TOML::Tiny not installed' unless eval { require TOML::Tiny; 1 };

	my $dir = tempdir(CLEANUP => 1);
	_write_file($dir, 'base.toml', qq{host = "unclosed string\n});

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

	my $cfg = Config::Abstraction->new(
		data        => { fallback => 'alive' },
		config_dirs => [$dir],
		env_prefix  => $ENV_PREFIX,
	);
	ok(@warnings > 0, 'malformed TOML emits at least one carp warning');
	ok(defined($cfg), 'construction succeeds despite malformed base.toml');
	is($cfg->get('fallback'), 'alive', 'data values survive a malformed TOML file');
};

subtest 'TOML: config_file with .toml extension is loaded via extensionless chain' => sub {
	# When config_file points to a .toml file, the all-parsers chain
	# should try TOML::Tiny and succeed.
	plan skip_all => 'TOML::Tiny not installed' unless eval { require TOML::Tiny; 1 };

	my $dir = tempdir(CLEANUP => 1);
	_write_file($dir, 'myapp.toml', qq{[server]\nhost = "explicit_host"\nport = 9000\n});

	my $cfg = Config::Abstraction->new(
		config_file => 'myapp.toml',
		config_dirs => [$dir],
		env_prefix  => $ENV_PREFIX,
	);
	ok(defined($cfg), 'config_file pointing to a .toml file is loaded');
	is($cfg->get('server.host'), 'explicit_host', 'TOML section key accessible via dotted notation from config_file');
	is($cfg->get('server.port'), 9000,             'TOML section integer accessible from config_file');
};

# ---------------------------------------------------------------------------
# validators option - per-key value validation
# ---------------------------------------------------------------------------

subtest 'validators: type integer accepts valid integer strings' => sub {
	my $cfg = Config::Abstraction->new(
		data        => { port => 8080 },
		config_dirs => [],
		env_prefix  => $ENV_PREFIX,
		validators  => { 'port' => 'integer' },
	);
	ok(defined($cfg), 'construction succeeds for valid integer');
	is($cfg->get('port'), 8080, 'value unchanged after integer validation');
};

subtest 'validators: type integer rejects non-integer string' => sub {
	dies_ok {
		Config::Abstraction->new(
			data        => { port => '80.5' },
			config_dirs => [],
			env_prefix  => $ENV_PREFIX,
			validators  => { 'port' => 'integer' },
		);
	} 'construction croaks for float value failing integer type';
	like($@, qr/must be an integer/, 'error message names the type');
};

subtest 'validators: type integer rejects undef' => sub {
	dies_ok {
		Config::Abstraction->new(
			data        => { port => undef },
			config_dirs => [],
			env_prefix  => $ENV_PREFIX,
			validators  => { 'port' => 'integer' },
		);
	} 'undef value fails integer validation';
};

subtest 'validators: type number accepts integer and float' => sub {
	for my $val (42, 3.14, -1, '0.001', '1e5') {



( run in 3.813 seconds using v1.01-cache-2.11-cpan-14f38c9f855 )