File Coverage

blib/lib/Poet/t/Conf.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package Poet::t::Conf;
2             $Poet::t::Conf::VERSION = '0.16';
3 1     1   829 use Poet::Tools qw(read_file tempdir_simple write_file);
  0            
  0            
4             use IPC::System::Simple qw(run);
5             use Test::Class::Most parent => 'Poet::Test::Class';
6              
7             require Poet;
8              
9             my $conf_files = {
10             'global/first.cfg' => { a => 10, b => 6, c => 11, d => 12 },
11             'global/second.cfg' => { e => 20 },
12             'global/third-not-a-config' => { f => 30 },
13             'layer/personal.cfg' => { c => 40, g => '_${b}', h => 51 },
14             'layer/development.cfg' => { f => 30 },
15             'local.cfg' => { h => '__${e}', layer => 'personal' },
16             };
17              
18             my $expected_values = {
19             a => 10,
20             b => 6,
21             c => 40,
22             d => 12,
23             e => 20,
24             f => undef,
25             g => "_6",
26             h => "__20",
27             };
28              
29             sub test_global : Tests {
30             my $self = shift;
31             my $poet = $self->temp_env( conf_files => $conf_files );
32             my $conf = $poet->conf();
33             while ( my ( $key, $value ) = each(%$expected_values) ) {
34             is( $conf->get($key), $value, "$key = " . ( defined($value) ? $value : 'undef' ) );
35             }
36             }
37              
38             sub test_duplicate : Tests {
39             my $self = shift;
40             throws_ok(
41             sub {
42             $self->temp_env(
43             conf_files => { %$conf_files, 'global/fourth.cfg' => { j => 71, c => 72 } } );
44             },
45             qr/key 'c' defined in both '.*(first|fourth)\.cfg' and '.*(first|fourth)\.cfg'/,
46             'cannot define same key in multiple global config files'
47             );
48             }
49              
50             sub test_set_local : Tests {
51             my $self = shift;
52             my $poet = $self->temp_env( conf_files => { 'global/foo.cfg' => { a => 5, b => 6, c => 7 } } );
53             my $conf = $poet->conf();
54              
55             is( $conf->get('a'), 5, 'a = 5' );
56             is( $conf->get( 'b' => 0 ), 6, 'b = 6' );
57             is( $conf->get('c'), 7, 'c = 7' );
58              
59             {
60             my $lex = $conf->set_local( { a => 15, c => 17 } );
61             is( $conf->get('a'), 15, 'a = 15 (set_local)' );
62             is( $conf->get('b'), 6, 'b = 6 (set_local)' );
63             is( $conf->get('c'), 17, 'c = 17 (set_local)' );
64             {
65             my $lex = $conf->set_local( { c => 27 } );
66             is( $conf->get('c'), 27, 'c = 27 (set_local depth 2)' );
67              
68             my $lex2 = $conf->set_local( { c => 37 } );
69             $lex2 = 'shiny';
70             is( $conf->get('c'), 27, 'c = 27 (did not hold on to lexical)' );
71             }
72             is( $conf->get('c'), 17, 'c = 17 (set_local)' );
73             }
74              
75             is( $conf->get('a'), 5, 'a = 5 (restored)' );
76             is( $conf->get('b'), 6, 'b = 6 (restored)' );
77             is( $conf->get('c'), 7, 'c = 7 (restored)' );
78             }
79              
80             sub test_dot_notation : Tests {
81             my $self = shift;
82             my $conf_files = {
83             'layer/personal.cfg' => '
84             a:
85             b:
86             c: 1
87             d: 2
88             e:
89             f:
90             g: 3
91             h: 4
92             ',
93             'local.cfg' => '
94             layer: personal
95             a.b.c: 6
96             e:
97             f:
98             g: 7
99              
100             '
101             };
102             my $poet = $self->temp_env( conf_files => $conf_files );
103             my %expected_values = (
104             'a' => { 'b' => { c => 6, d => 2 } },
105             'a.b' => { c => 6, d => 2 },
106             'a.b.c' => 6,
107             'a.b.d' => 2,
108             'e' => { f => { g => 7 } },
109             'e.f' => { g => 7 },
110             'e.f.g' => 7,
111             'x.y.z' => undef
112             );
113             my $conf = $poet->conf();
114             my $check_expected = sub {
115             my $desc = shift;
116             foreach my $key ( sort( keys(%expected_values) ) ) {
117             my $value = $expected_values{$key};
118             cmp_deeply( $conf->get($key), $value, "$key - $desc" );
119             }
120             };
121              
122             $check_expected->('initial');
123             throws_ok( sub { $conf->get('a.b.c.z') },
124             qr/hash value expected for conf key 'a.b.c', got non-hash '6'/, "a.b.c.z" );
125              
126             $conf_files->{'layer/personal.cfg'} = { 'a' => { 'b' => 17 } };
127             throws_ok(
128             sub { $poet = $self->temp_env( conf_files => $conf_files ) },
129             qr/error assigning to 'a.b.c' in .*; 'a.b' already has non-hash value/,
130             "e.f: 17"
131             );
132              
133             {
134             my $lex = $conf->set_local( { 'a.b.c' => 16 } );
135             local $expected_values{'a'} = { 'b' => { c => 16, d => 2 } },
136             local $expected_values{'a.b'} = { c => 16, d => 2 };
137             local $expected_values{'a.b.c'} = 16;
138             $check_expected->('set_local');
139             }
140              
141             $check_expected->('after set_local');
142             }
143              
144             sub test_types : Tests {
145             my $self = shift;
146             my $truth = { c => 't', d => 'true', e => 'y', f => 'yes' };
147             my $falsity = { c => 'f', d => 'false', e => 'n', f => 'no' };
148             my $conf_files = {
149             'global.cfg' => {
150             scalar => 5,
151             list => [ 1, 2, 3 ],
152             hash => { size => 'large', flavor => 'chocolate' },
153             truth => $truth,
154             falsity => $falsity,
155             }
156             };
157              
158             my $poet = $self->temp_env( conf_files => $conf_files );
159             my $conf = $poet->conf();
160              
161             cmp_deeply( $conf->get_list('list'), [ 1, 2, 3 ], 'list ok' );
162             foreach my $key (qw(scalar hash)) {
163             throws_ok( sub { $conf->get_list($key) }, qr/list value expected/ );
164             }
165             cmp_deeply( $conf->get_hash('hash'), { size => 'large', flavor => 'chocolate' }, 'hash ok' );
166             foreach my $key (qw(scalar list)) {
167             throws_ok( sub { $conf->get_hash($key) }, qr/hash value expected/ );
168             }
169             foreach my $key (qw(c d e f)) {
170             is( $conf->get_boolean("truth.$key"), 1, "$key = true" );
171             is( $conf->get_boolean("falsity.$key"), 0, "$key = false" );
172             }
173             foreach my $key (qw(scalar list hash)) {
174             throws_ok( sub { $conf->get_boolean($key) }, qr/boolean value expected/ );
175             }
176             }
177              
178             sub test_layer_required : Tests {
179             my $self = shift;
180             throws_ok(
181             sub { $self->temp_env( conf_files => { 'local.cfg' => {} } ) },
182             qr/must specify layer/,
183             'no layer'
184             );
185             }
186              
187             sub test_interpolation : Tests {
188             my $self = shift;
189             my $poet = $self->temp_env(
190             conf => {
191             layer => 'development',
192             'a.b' => 'bar',
193             'c' => '/foo/${a.b}/baz',
194             'd' => '/foo/${huh}/baz',
195             'deep' => { 'e' => 5, 'f' => [ '${c}', ['${a.b}'] ] }
196             }
197             );
198             my $conf = $poet->conf();
199             is( $conf->get('c'), '/foo/bar/baz', 'substitution' );
200             throws_ok { $conf->get('d') } qr/could not get conf for 'huh'/, 'bad substitution';
201             cmp_deeply(
202             $conf->get('deep'),
203             {
204             e => 5,
205             f => [ '/foo/bar/baz', ['bar'] ]
206             },
207             'deep'
208             );
209              
210             }
211              
212             sub test_dynamic_conf : Tests {
213             my $self = shift;
214             my $poet = $self->temp_env();
215             write_file( $poet->conf_path("dynamic/foo.mc"), "<% 2+2 %>" );
216             ok( !-d $poet->data_path("conf/dynamic"), "data/conf/dynamic does not exist" );
217             run( $poet->conf_path("dynamic/gen.pl") );
218             ok( -d $poet->data_path("conf/dynamic"), "data/conf/dynamic exists" );
219             ok( -f $poet->data_path("conf/dynamic/foo"), "conf/dynamic/foo exists" );
220             is( read_file( $poet->data_path("conf/dynamic/foo") ), 4, "foo has correct content" );
221             ok( !-f $poet->data_path("conf/dynamic/gen.pl"), "conf/dynamic/gen.pl does not exist" );
222             }
223              
224             sub test_get_secure : Tests {
225             my $self = shift;
226             my $tempdir = tempdir_simple('poet-conf-XXXX');
227             my $secure_file = "$tempdir/supersecret.cfg";
228             write_file( $secure_file, "foo: 7\nbar: 8\n" );
229             my $poet = $self->temp_env(
230             conf_files => {
231             'local.cfg' => {
232             layer => 'development',
233             'foo' => 0,
234             'baz' => 9,
235             'conf.secure_conf_file' => $secure_file
236             }
237             }
238             );
239             my $conf = $poet->conf;
240              
241             is( $conf->get_secure('foo'), 7, "foo=0" );
242             is( $conf->get_secure('bar'), 8, "bar=8" );
243             is( $conf->get_secure('baz'), 9, "baz=9" );
244             is( $conf->get_secure('blargh'), undef, "blargh=undef" );
245              
246             is( $conf->get('bar'), undef, "bar=undef" );
247             ok( ( !grep { /bar/ } $conf->get_keys() ), "no bar in keys" );
248             }
249              
250             1;