1use strict;
2use warnings;
3use Test::More;
4use Test::Fatal;
5use Carp 'croak';
6
7use Dancer2::Core::Runner;
8use Dancer2::FileUtils qw/dirname path/;
9use File::Spec;
10use File::Temp;
11
12# undefine ENV vars used as defaults for app environment in these tests
13local $ENV{DANCER_ENVIRONMENT};
14local $ENV{PLACK_ENV};
15
16my $runner = Dancer2::Core::Runner->new();
17my $location = File::Spec->rel2abs( path( dirname(__FILE__), 'config' ) );
18my $location2 = File::Spec->rel2abs( path( dirname(__FILE__), 'config2' ) );
19
20{
21
22    package Prod;
23    use Moo;
24    with 'Dancer2::Core::Role::ConfigReader';
25
26    sub name {'Prod'}
27
28    sub _build_environment    {'production'}
29    sub _build_location       {$location}
30    sub _build_default_config {$runner->config}
31
32    package Dev;
33    use Moo;
34    with 'Dancer2::Core::Role::ConfigReader';
35
36    sub _build_environment    {'development'}
37    sub _build_location       {$location};
38    sub _build_default_config {$runner->config}
39
40    package Failure;
41    use Moo;
42    with 'Dancer2::Core::Role::ConfigReader';
43
44    sub _build_environment    {'failure'}
45    sub _build_location       {$location}
46    sub _build_default_config {$runner->config}
47
48    package Staging;
49    use Moo;
50    with 'Dancer2::Core::Role::ConfigReader';
51
52    sub _build_environment    {'staging'}
53    sub _build_location       {$location}
54    sub _build_default_config {$runner->config}
55
56    package Merging;
57    use Moo;
58    with 'Dancer2::Core::Role::ConfigReader';
59
60    sub name {'Merging'}
61
62    sub _build_environment    {'merging'}
63    sub _build_location       {$location}
64    sub _build_default_config {$runner->config}
65
66    package LocalConfig;
67    use Moo;
68    with 'Dancer2::Core::Role::ConfigReader';
69
70    sub name {'LocalConfig'}
71
72    sub _build_environment    {'lconfig'}
73    sub _build_location       {$location2}
74    sub _build_default_config {$runner->config}
75
76}
77
78my $d = Dev->new();
79is_deeply $d->config_files,
80  [ path( $location, 'config.yml' ), ],
81  "config_files() only sees existing files";
82
83my $f = Prod->new;
84is $f->does('Dancer2::Core::Role::ConfigReader'), 1,
85  "role Dancer2::Core::Role::ConfigReader is consumed";
86
87is_deeply $f->config_files,
88  [ path( $location, 'config.yml' ),
89    path( $location, 'environments', 'production.yml' ),
90  ],
91  "config_files() works";
92
93my $j = Staging->new;
94is_deeply $j->config_files,
95  [ path( $location, 'config.yml' ),
96    path( $location, 'environments', 'staging.json' ),
97  ],
98  "config_files() does JSON too!";
99
100note "bad YAML file";
101my $fail = Failure->new;
102is $fail->environment, 'failure';
103
104is_deeply $fail->config_files,
105  [ path( $location, 'config.yml' ),
106    path( $location, 'environments', 'failure.yml' ),
107  ],
108  "config_files() works";
109
110like(
111    exception { $fail->config },
112    qr{Unable to parse the configuration file}, 'Configuration file parsing failure',
113);
114
115note "config merging";
116my $m = Merging->new;
117
118# Check the 'application' top-level key; its the only key that
119# is currently a HoH in the test configurations
120is_deeply $m->config->{application},
121  { some_feature    => 'bar',
122    another_setting => 'baz',
123  },
124  "full merging of configuration hashes";
125
126{
127    my $l = LocalConfig->new;
128
129    is_deeply $l->config_files,
130      [ path( $location2, 'config.yml' ),
131        path( $location2, 'config_local.yml' ),
132        path( $location2, 'environments', 'lconfig.yml' ),
133        path( $location2, 'environments', 'lconfig_local.yml' ),
134      ],
135      "config_files() with local config works";
136
137    is_deeply $l->config->{application},
138      { feature_1 => 'foo',
139        feature_2 => 'alpha',
140        feature_3 => 'replacement',
141        feature_4 => 'blat',
142        feature_5 => 'beta',
143        feature_6 => 'bar',
144        feature_7 => 'baz',
145        feature_8 => 'goober',
146      },
147      "full merging of local configuration hashes";
148
149}
150
151note "config parsing";
152
153is $f->config->{show_errors}, 0;
154is $f->config->{main},        1;
155is $f->config->{charset},     'utf-8', "normalized UTF-8 to utf-8";
156
157ok( $f->has_setting('charset') );
158ok( !$f->has_setting('foobarbaz') );
159
160note "default values";
161is $f->setting('apphandler'),   'Standalone';
162
163like(
164    exception { $f->_normalize_config( { charset => 'BOGUS' } ) },
165    qr{Charset defined in configuration is wrong : couldn't identify 'BOGUS'},
166    'Configuration file charset failure',
167);
168
169{
170
171    package Foo;
172    use Carp 'croak';
173    sub foo { croak "foo" }
174}
175
176is $f->setting('traces'), 0;
177unlike( exception { Foo->foo() }, qr{Foo::foo}, "traces are not enabled", );
178
179$f->setting( traces => 1 );
180like( exception { Foo->foo() }, qr{Foo::foo}, "traces are enabled", );
181
182{
183    my $tmpdir = File::Temp::tempdir( CLEANUP => 1, TMPDIR => 1 );
184    $ENV{DANCER_CONFDIR} = $tmpdir;
185    my $f = Prod->new;
186    is $f->config_location, $tmpdir;
187}
188
189done_testing;
190