config_files 0.1.6 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +94 -0
- data/.gitignore +2 -3
- data/.rubocop.yml +81 -0
- data/CHANGELOG.md +154 -0
- data/Gemfile +12 -1
- data/MULTI_RUBY_SETUP.md +158 -0
- data/README.md +246 -23
- data/Rakefile +26 -3
- data/TESTING.md +226 -0
- data/config_files.gemspec +12 -9
- data/docker/Dockerfile.test +32 -0
- data/lib/config_files/file_factory.rb +7 -3
- data/lib/config_files/loader_factory.rb +20 -11
- data/lib/config_files/loaders/base_parser.rb +133 -0
- data/lib/config_files/loaders/conf.rb +61 -0
- data/lib/config_files/loaders/default.rb +3 -1
- data/lib/config_files/loaders/ini.rb +48 -0
- data/lib/config_files/loaders/json.rb +3 -1
- data/lib/config_files/loaders/xml.rb +67 -0
- data/lib/config_files/loaders/yaml.rb +2 -0
- data/lib/config_files/loaders.rb +6 -1
- data/lib/config_files/version.rb +3 -1
- data/lib/config_files.rb +34 -18
- data/lib/meta.rb +3 -1
- data/scripts/install_rubies_asdf.sh +187 -0
- data/scripts/test_docker.sh +91 -0
- data/scripts/test_multiple_rubies.sh +290 -0
- data/test/comprehensive_multi_directory_test.rb +168 -0
- data/test/config/dummy.json +10 -0
- data/test/config/dummy.yml +6 -0
- data/test/config_files_test.rb +10 -8
- data/test/etc/dummy.conf +14 -2
- data/test/etc/dummy.ini +12 -0
- data/test/etc/dummy.xml +13 -0
- data/test/etc/dummy.yml +2 -2
- data/test/loader_factory_test.rb +10 -10
- data/test/loaders_test.rb +362 -0
- data/test/local/dummy.json +10 -0
- data/test/local/dummy.yml +6 -0
- data/test/mixed_format_test.rb +152 -0
- data/test/multi_directory_test.rb +126 -0
- data/test/test_helper.rb +3 -0
- metadata +49 -26
- data/Gemfile.lock +0 -34
data/test/loader_factory_test.rb
CHANGED
@@ -1,40 +1,40 @@
|
|
1
|
-
|
1
|
+
$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
2
|
require 'minitest/autorun'
|
3
3
|
require 'config_files'
|
4
4
|
class LoaderFactoryDummy
|
5
5
|
class << self
|
6
|
-
def call(
|
6
|
+
def call(_file_name, _options = {})
|
7
7
|
nil
|
8
8
|
end
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
class LoaderFactoryTest <
|
12
|
+
class LoaderFactoryTest < Minitest::Test
|
13
13
|
def file_locations
|
14
14
|
File.join(__dir__, 'etc')
|
15
15
|
end
|
16
16
|
|
17
17
|
def test_detect_yaml_file_type
|
18
|
-
assert_equal(::ConfigFiles::Loaders::Yaml, ::ConfigFiles::LoaderFactory.(File.join(file_locations,'dummy.yml')))
|
18
|
+
assert_equal(::ConfigFiles::Loaders::Yaml, ::ConfigFiles::LoaderFactory.call(File.join(file_locations, 'dummy.yml')))
|
19
19
|
end
|
20
20
|
|
21
21
|
def test_detect_json_file_type
|
22
|
-
assert_equal(::ConfigFiles::Loaders::Json, ::ConfigFiles::LoaderFactory.(File.join(file_locations,'dummy.json')))
|
22
|
+
assert_equal(::ConfigFiles::Loaders::Json, ::ConfigFiles::LoaderFactory.call(File.join(file_locations, 'dummy.json')))
|
23
23
|
end
|
24
24
|
|
25
25
|
def test_detect_unknown_file_type
|
26
|
-
assert_nil(::ConfigFiles::LoaderFactory.(File.join(file_locations,'dummy.wibble'), default_loader: nil))
|
26
|
+
assert_nil(::ConfigFiles::LoaderFactory.call(File.join(file_locations, 'dummy.wibble'), default_loader: nil))
|
27
27
|
end
|
28
28
|
|
29
29
|
def test_allow_addition_of_file_types_does_not_break_existing
|
30
|
-
assert_equal(::ConfigFiles::Loaders::Yaml, ::ConfigFiles::LoaderFactory.(File.join(file_locations,'dummy.yml'), loaders: {LoaderFactoryDummy=>['wibble']}))
|
30
|
+
assert_equal(::ConfigFiles::Loaders::Yaml, ::ConfigFiles::LoaderFactory.call(File.join(file_locations, 'dummy.yml'), loaders: { LoaderFactoryDummy => ['wibble'] }))
|
31
31
|
end
|
32
32
|
|
33
33
|
def test_allow_addition_of_file_types_breaks_existing_if_specified
|
34
|
-
assert_nil(::ConfigFiles::LoaderFactory.(File.join(file_locations,'dummy.yml'), loaders: {LoaderFactoryDummy=>['wibble']}, include_default: false, default_loader: nil))
|
34
|
+
assert_nil(::ConfigFiles::LoaderFactory.call(File.join(file_locations, 'dummy.yml'), loaders: { LoaderFactoryDummy => ['wibble'] }, include_default: false, default_loader: nil))
|
35
35
|
end
|
36
36
|
|
37
37
|
def test_addition_of_new_loaders
|
38
|
-
assert_equal(LoaderFactoryDummy, ::ConfigFiles::LoaderFactory.(File.join(file_locations,'dummy.wibble'), loaders: {LoaderFactoryDummy=>['wibble']}, include_default: false))
|
38
|
+
assert_equal(LoaderFactoryDummy, ::ConfigFiles::LoaderFactory.call(File.join(file_locations, 'dummy.wibble'), loaders: { LoaderFactoryDummy => ['wibble'] }, include_default: false))
|
39
39
|
end
|
40
|
-
end
|
40
|
+
end
|
@@ -0,0 +1,362 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
class LoadersTest < Minitest::Test
|
5
|
+
def setup
|
6
|
+
@temp_files = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def teardown
|
10
|
+
@temp_files.each(&:unlink)
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_temp_file(content, extension = '.tmp')
|
14
|
+
file = Tempfile.new(['test', extension])
|
15
|
+
file.write(content)
|
16
|
+
file.close
|
17
|
+
@temp_files << file
|
18
|
+
file.path
|
19
|
+
end
|
20
|
+
|
21
|
+
# CONF Parser Tests
|
22
|
+
def test_conf_parser_basic_key_value_pairs
|
23
|
+
content = <<~CONF
|
24
|
+
key1=value1
|
25
|
+
key2: value2
|
26
|
+
key3 value3
|
27
|
+
CONF
|
28
|
+
|
29
|
+
file_path = create_temp_file(content, '.conf')
|
30
|
+
result = ConfigFiles::Loaders::Conf.call(file_path)
|
31
|
+
|
32
|
+
assert_equal 'value1', result['key1']
|
33
|
+
assert_equal 'value2', result['key2']
|
34
|
+
assert_equal 'value3', result['key3']
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_conf_parser_sections
|
38
|
+
content = <<~CONF
|
39
|
+
global_key=global_value
|
40
|
+
|
41
|
+
[section1]
|
42
|
+
key1=value1
|
43
|
+
key2=value2
|
44
|
+
|
45
|
+
[section2]
|
46
|
+
key3=value3
|
47
|
+
CONF
|
48
|
+
|
49
|
+
file_path = create_temp_file(content, '.conf')
|
50
|
+
result = ConfigFiles::Loaders::Conf.call(file_path)
|
51
|
+
|
52
|
+
assert_equal 'global_value', result['global_key']
|
53
|
+
assert_equal 'value1', result['section1']['key1']
|
54
|
+
assert_equal 'value2', result['section1']['key2']
|
55
|
+
assert_equal 'value3', result['section2']['key3']
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_conf_parser_nested_keys
|
59
|
+
content = <<~CONF
|
60
|
+
server.host=localhost
|
61
|
+
server.port=8080
|
62
|
+
database.connection.host=db.example.com
|
63
|
+
|
64
|
+
[app]
|
65
|
+
cache.redis.host=redis.example.com
|
66
|
+
cache.redis.port=6379
|
67
|
+
CONF
|
68
|
+
|
69
|
+
file_path = create_temp_file(content, '.conf')
|
70
|
+
result = ConfigFiles::Loaders::Conf.call(file_path)
|
71
|
+
|
72
|
+
assert_equal 'localhost', result['server']['host']
|
73
|
+
assert_equal 8080, result['server']['port']
|
74
|
+
assert_equal 'db.example.com', result['database']['connection']['host']
|
75
|
+
assert_equal 'redis.example.com', result['app']['cache']['redis']['host']
|
76
|
+
assert_equal 6379, result['app']['cache']['redis']['port']
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_conf_parser_value_types
|
80
|
+
content = <<~CONF
|
81
|
+
string_value=hello world
|
82
|
+
quoted_string="quoted value"
|
83
|
+
single_quoted='single quoted'
|
84
|
+
integer_value=42
|
85
|
+
float_value=3.14
|
86
|
+
boolean_true=true
|
87
|
+
boolean_false=false
|
88
|
+
boolean_yes=yes
|
89
|
+
boolean_no=no
|
90
|
+
boolean_on=on
|
91
|
+
boolean_off=off
|
92
|
+
boolean_1=1
|
93
|
+
boolean_0=0
|
94
|
+
CONF
|
95
|
+
|
96
|
+
file_path = create_temp_file(content, '.conf')
|
97
|
+
result = ConfigFiles::Loaders::Conf.call(file_path)
|
98
|
+
|
99
|
+
assert_equal 'hello world', result['string_value']
|
100
|
+
assert_equal 'quoted value', result['quoted_string']
|
101
|
+
assert_equal 'single quoted', result['single_quoted']
|
102
|
+
assert_equal 42, result['integer_value']
|
103
|
+
assert_in_delta(3.14, result['float_value'])
|
104
|
+
assert result['boolean_true']
|
105
|
+
refute result['boolean_false']
|
106
|
+
assert result['boolean_yes']
|
107
|
+
refute result['boolean_no']
|
108
|
+
assert result['boolean_on']
|
109
|
+
refute result['boolean_off']
|
110
|
+
assert result['boolean_1']
|
111
|
+
refute result['boolean_0']
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_conf_parser_comments_and_empty_lines
|
115
|
+
content = <<~CONF
|
116
|
+
# This is a comment
|
117
|
+
key1=value1
|
118
|
+
|
119
|
+
# Another comment
|
120
|
+
key2=value2
|
121
|
+
|
122
|
+
[section]
|
123
|
+
# Section comment
|
124
|
+
key3=value3
|
125
|
+
CONF
|
126
|
+
|
127
|
+
file_path = create_temp_file(content, '.conf')
|
128
|
+
result = ConfigFiles::Loaders::Conf.call(file_path)
|
129
|
+
|
130
|
+
assert_equal 'value1', result['key1']
|
131
|
+
assert_equal 'value2', result['key2']
|
132
|
+
assert_equal 'value3', result['section']['key3']
|
133
|
+
end
|
134
|
+
|
135
|
+
# INI Parser Tests
|
136
|
+
def test_ini_parser_basic_key_value_pairs
|
137
|
+
content = <<~INI
|
138
|
+
key1=value1
|
139
|
+
key2=value2
|
140
|
+
INI
|
141
|
+
|
142
|
+
file_path = create_temp_file(content, '.ini')
|
143
|
+
result = ConfigFiles::Loaders::Ini.call(file_path)
|
144
|
+
|
145
|
+
assert_equal 'value1', result['key1']
|
146
|
+
assert_equal 'value2', result['key2']
|
147
|
+
end
|
148
|
+
|
149
|
+
def test_ini_parser_sections
|
150
|
+
content = <<~INI
|
151
|
+
global_key=global_value
|
152
|
+
|
153
|
+
[section1]
|
154
|
+
key1=value1
|
155
|
+
key2=value2
|
156
|
+
|
157
|
+
[section2]
|
158
|
+
key3=value3
|
159
|
+
INI
|
160
|
+
|
161
|
+
file_path = create_temp_file(content, '.ini')
|
162
|
+
result = ConfigFiles::Loaders::Ini.call(file_path)
|
163
|
+
|
164
|
+
assert_equal 'global_value', result['global_key']
|
165
|
+
assert_equal 'value1', result['section1']['key1']
|
166
|
+
assert_equal 'value2', result['section1']['key2']
|
167
|
+
assert_equal 'value3', result['section2']['key3']
|
168
|
+
end
|
169
|
+
|
170
|
+
def test_ini_parser_value_types
|
171
|
+
content = <<~INI
|
172
|
+
string_value=hello world
|
173
|
+
quoted_string="quoted value"
|
174
|
+
single_quoted='single quoted'
|
175
|
+
integer_value=42
|
176
|
+
float_value=3.14
|
177
|
+
boolean_true=true
|
178
|
+
boolean_false=false
|
179
|
+
boolean_yes=yes
|
180
|
+
boolean_no=no
|
181
|
+
boolean_on=on
|
182
|
+
boolean_off=off
|
183
|
+
boolean_1=1
|
184
|
+
boolean_0=0
|
185
|
+
INI
|
186
|
+
|
187
|
+
file_path = create_temp_file(content, '.ini')
|
188
|
+
result = ConfigFiles::Loaders::Ini.call(file_path)
|
189
|
+
|
190
|
+
assert_equal 'hello world', result['string_value']
|
191
|
+
assert_equal 'quoted value', result['quoted_string']
|
192
|
+
assert_equal 'single quoted', result['single_quoted']
|
193
|
+
assert_equal 42, result['integer_value']
|
194
|
+
assert_in_delta(3.14, result['float_value'])
|
195
|
+
assert result['boolean_true']
|
196
|
+
refute result['boolean_false']
|
197
|
+
assert result['boolean_yes']
|
198
|
+
refute result['boolean_no']
|
199
|
+
assert result['boolean_on']
|
200
|
+
refute result['boolean_off']
|
201
|
+
assert result['boolean_1']
|
202
|
+
refute result['boolean_0']
|
203
|
+
end
|
204
|
+
|
205
|
+
def test_ini_parser_comments
|
206
|
+
content = <<~INI
|
207
|
+
# Hash comment
|
208
|
+
; Semicolon comment
|
209
|
+
key1=value1
|
210
|
+
|
211
|
+
[section]
|
212
|
+
# Section comment
|
213
|
+
; Another section comment
|
214
|
+
key2=value2
|
215
|
+
INI
|
216
|
+
|
217
|
+
file_path = create_temp_file(content, '.ini')
|
218
|
+
result = ConfigFiles::Loaders::Ini.call(file_path)
|
219
|
+
|
220
|
+
assert_equal 'value1', result['key1']
|
221
|
+
assert_equal 'value2', result['section']['key2']
|
222
|
+
end
|
223
|
+
|
224
|
+
# XML Parser Tests
|
225
|
+
def test_xml_parser_basic_structure
|
226
|
+
content = <<~XML
|
227
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
228
|
+
<config>
|
229
|
+
<key1>value1</key1>
|
230
|
+
<key2>value2</key2>
|
231
|
+
</config>
|
232
|
+
XML
|
233
|
+
|
234
|
+
file_path = create_temp_file(content, '.xml')
|
235
|
+
result = ConfigFiles::Loaders::Xml.call(file_path)
|
236
|
+
|
237
|
+
assert_equal 'value1', result['key1']
|
238
|
+
assert_equal 'value2', result['key2']
|
239
|
+
end
|
240
|
+
|
241
|
+
def test_xml_parser_nested_elements
|
242
|
+
content = <<~XML
|
243
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
244
|
+
<config>
|
245
|
+
<database>
|
246
|
+
<host>localhost</host>
|
247
|
+
<port>5432</port>
|
248
|
+
</database>
|
249
|
+
<app>
|
250
|
+
<name>Test App</name>
|
251
|
+
<debug>true</debug>
|
252
|
+
</app>
|
253
|
+
</config>
|
254
|
+
XML
|
255
|
+
|
256
|
+
file_path = create_temp_file(content, '.xml')
|
257
|
+
result = ConfigFiles::Loaders::Xml.call(file_path)
|
258
|
+
|
259
|
+
assert_equal 'localhost', result['database']['host']
|
260
|
+
assert_equal 5432, result['database']['port']
|
261
|
+
assert_equal 'Test App', result['app']['name']
|
262
|
+
assert result['app']['debug']
|
263
|
+
end
|
264
|
+
|
265
|
+
def test_xml_parser_attributes
|
266
|
+
content = <<~XML
|
267
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
268
|
+
<config>
|
269
|
+
<app name="Test App" version="1.0">
|
270
|
+
<debug>false</debug>
|
271
|
+
</app>
|
272
|
+
</config>
|
273
|
+
XML
|
274
|
+
|
275
|
+
file_path = create_temp_file(content, '.xml')
|
276
|
+
result = ConfigFiles::Loaders::Xml.call(file_path)
|
277
|
+
|
278
|
+
assert_equal 'Test App', result['app']['@name']
|
279
|
+
assert_in_delta(1.0, result['app']['@version'])
|
280
|
+
refute result['app']['debug']
|
281
|
+
end
|
282
|
+
|
283
|
+
def test_xml_parser_multiple_elements_same_name
|
284
|
+
content = <<~XML
|
285
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
286
|
+
<config>
|
287
|
+
<item>value1</item>
|
288
|
+
<item>value2</item>
|
289
|
+
<item>value3</item>
|
290
|
+
</config>
|
291
|
+
XML
|
292
|
+
|
293
|
+
file_path = create_temp_file(content, '.xml')
|
294
|
+
result = ConfigFiles::Loaders::Xml.call(file_path)
|
295
|
+
|
296
|
+
assert_kind_of Array, result['item']
|
297
|
+
assert_equal 3, result['item'].length
|
298
|
+
assert_equal 'value1', result['item'][0]
|
299
|
+
assert_equal 'value2', result['item'][1]
|
300
|
+
assert_equal 'value3', result['item'][2]
|
301
|
+
end
|
302
|
+
|
303
|
+
def test_xml_parser_value_types
|
304
|
+
content = <<~XML
|
305
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
306
|
+
<config>
|
307
|
+
<string_value>hello world</string_value>
|
308
|
+
<integer_value>42</integer_value>
|
309
|
+
<float_value>3.14</float_value>
|
310
|
+
<boolean_true>true</boolean_true>
|
311
|
+
<boolean_false>false</boolean_false>
|
312
|
+
<empty_value></empty_value>
|
313
|
+
</config>
|
314
|
+
XML
|
315
|
+
|
316
|
+
file_path = create_temp_file(content, '.xml')
|
317
|
+
result = ConfigFiles::Loaders::Xml.call(file_path)
|
318
|
+
|
319
|
+
assert_equal 'hello world', result['string_value']
|
320
|
+
assert_equal 42, result['integer_value']
|
321
|
+
assert_in_delta(3.14, result['float_value'])
|
322
|
+
assert result['boolean_true']
|
323
|
+
refute result['boolean_false']
|
324
|
+
assert_nil result['empty_value']
|
325
|
+
end
|
326
|
+
|
327
|
+
# Test existing dummy files to ensure compatibility
|
328
|
+
def test_existing_dummy_files
|
329
|
+
conf_result = ConfigFiles::Loaders::Conf.call('test/etc/dummy.conf')
|
330
|
+
ini_result = ConfigFiles::Loaders::Ini.call('test/etc/dummy.ini')
|
331
|
+
xml_result = ConfigFiles::Loaders::Xml.call('test/etc/dummy.xml')
|
332
|
+
|
333
|
+
# CONF file assertions
|
334
|
+
assert_equal 'test2', conf_result['config_test']
|
335
|
+
assert_equal 'conf_file', conf_result['only_in_conf']
|
336
|
+
assert_equal 'myserver', conf_result['server']['name']
|
337
|
+
assert_equal 'nested_value', conf_result['nested']['config']['value']
|
338
|
+
assert_equal 'conf-db.example.com', conf_result['database']['host']
|
339
|
+
assert_equal 5433, conf_result['database']['port']
|
340
|
+
assert conf_result['database']['ssl']
|
341
|
+
assert_equal 'CONF App', conf_result['app']['name']
|
342
|
+
refute conf_result['app']['debug']
|
343
|
+
|
344
|
+
# INI file assertions
|
345
|
+
assert_equal 'ini_value', ini_result['global_setting']
|
346
|
+
assert_equal 'ini-db.example.com', ini_result['database']['host']
|
347
|
+
assert_equal 3306, ini_result['database']['port']
|
348
|
+
assert ini_result['database']['ssl']
|
349
|
+
assert_equal 'INI App', ini_result['app']['name']
|
350
|
+
refute ini_result['app']['debug']
|
351
|
+
assert_in_delta(2.0, ini_result['app']['version'])
|
352
|
+
|
353
|
+
# XML file assertions
|
354
|
+
assert_equal 'xml_value', xml_result['global_setting']
|
355
|
+
assert_equal 'xml-db.example.com', xml_result['database']['host']
|
356
|
+
assert_equal 5432, xml_result['database']['port']
|
357
|
+
assert xml_result['database']['ssl']
|
358
|
+
assert_equal 'XML App', xml_result['app']['@name']
|
359
|
+
refute xml_result['app']['debug']
|
360
|
+
assert_in_delta(3.0, xml_result['app']['version'])
|
361
|
+
end
|
362
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'config_files'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
class MixedFormatTest < Minitest::Test
|
7
|
+
def setup
|
8
|
+
# Create test directories and files with mixed formats
|
9
|
+
FileUtils.mkdir_p('test/format_test/dir1')
|
10
|
+
FileUtils.mkdir_p('test/format_test/dir2')
|
11
|
+
FileUtils.mkdir_p('test/format_test/dir3')
|
12
|
+
|
13
|
+
# dir1: YAML file
|
14
|
+
File.write('test/format_test/dir1/config.yml', <<~YAML)
|
15
|
+
database:
|
16
|
+
host: yaml-host
|
17
|
+
port: 5432
|
18
|
+
app:
|
19
|
+
name: yaml-app
|
20
|
+
debug: false
|
21
|
+
yaml_only: true
|
22
|
+
YAML
|
23
|
+
|
24
|
+
# dir2: JSON file
|
25
|
+
File.write('test/format_test/dir2/config.json', <<~JSON)
|
26
|
+
{
|
27
|
+
"database": {
|
28
|
+
"host": "json-host",
|
29
|
+
"username": "json-user"
|
30
|
+
},
|
31
|
+
"app": {
|
32
|
+
"name": "json-app",
|
33
|
+
"version": "1.0.0"
|
34
|
+
},
|
35
|
+
"json_only": true
|
36
|
+
}
|
37
|
+
JSON
|
38
|
+
|
39
|
+
# dir3: Both YAML and JSON files
|
40
|
+
File.write('test/format_test/dir3/config.yml', <<~YAML)
|
41
|
+
database:
|
42
|
+
host: final-yaml-host
|
43
|
+
password: secret
|
44
|
+
app:
|
45
|
+
debug: true
|
46
|
+
final_yaml: true
|
47
|
+
YAML
|
48
|
+
|
49
|
+
File.write('test/format_test/dir3/config.json', <<~JSON)
|
50
|
+
{
|
51
|
+
"database": {
|
52
|
+
"host": "final-json-host",
|
53
|
+
"timeout": 30
|
54
|
+
},
|
55
|
+
"app": {
|
56
|
+
"environment": "production"
|
57
|
+
},
|
58
|
+
"final_json": true
|
59
|
+
}
|
60
|
+
JSON
|
61
|
+
end
|
62
|
+
|
63
|
+
def teardown
|
64
|
+
FileUtils.rm_rf('test/format_test')
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_mixed_yaml_and_json_across_directories
|
68
|
+
# Test class that uses mixed format directories
|
69
|
+
mixed_class = Class.new do
|
70
|
+
include ConfigFiles
|
71
|
+
config_directories etc: ['test/format_test/dir1', 'test/format_test/dir2', 'test/format_test/dir3']
|
72
|
+
static_config_files :config
|
73
|
+
end
|
74
|
+
|
75
|
+
config = mixed_class.config
|
76
|
+
|
77
|
+
# Test that values from all formats are present
|
78
|
+
assert config.key?(:yaml_only), "Should have YAML-only value from dir1"
|
79
|
+
assert config.key?(:json_only), "Should have JSON-only value from dir2"
|
80
|
+
assert config.key?(:final_yaml), "Should have YAML value from dir3"
|
81
|
+
assert config.key?(:final_json), "Should have JSON value from dir3"
|
82
|
+
|
83
|
+
# Test deep merging across formats with dir1 taking precedence
|
84
|
+
assert config[:database], "Should have database config"
|
85
|
+
assert_equal 'yaml-host', config[:database][:host], "Host should be from dir1 (highest priority)"
|
86
|
+
assert_equal 5432, config[:database][:port], "Port should come from YAML in dir1"
|
87
|
+
assert_equal 'json-user', config[:database][:username], "Username should come from JSON in dir2"
|
88
|
+
assert_equal 'secret', config[:database][:password], "Password should come from YAML in dir3"
|
89
|
+
assert_equal 30, config[:database][:timeout], "Timeout should come from JSON in dir3"
|
90
|
+
|
91
|
+
# Test app config merging
|
92
|
+
assert config[:app], "Should have app config"
|
93
|
+
assert_equal 'yaml-app', config[:app][:name], "Name should be from dir1 (highest priority)"
|
94
|
+
refute config[:app][:debug], "Debug should be from dir1 (highest priority)"
|
95
|
+
assert_equal '1.0.0', config[:app][:version], "Version should come from JSON in dir2"
|
96
|
+
assert_equal 'production', config[:app][:environment], "Environment should come from JSON in dir3"
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_multiple_files_same_directory_same_format
|
100
|
+
# Test when a directory has multiple files of the same format
|
101
|
+
FileUtils.mkdir_p('test/format_test/multi')
|
102
|
+
|
103
|
+
File.write('test/format_test/multi/config.yml', <<~YAML)
|
104
|
+
from_yml: true
|
105
|
+
shared: yml_value
|
106
|
+
YAML
|
107
|
+
|
108
|
+
File.write('test/format_test/multi/config.json', <<~JSON)
|
109
|
+
{
|
110
|
+
"from_json": true,
|
111
|
+
"shared": "json_value"
|
112
|
+
}
|
113
|
+
JSON
|
114
|
+
|
115
|
+
multi_class = Class.new do
|
116
|
+
include ConfigFiles
|
117
|
+
config_directories etc: ['test/format_test/multi']
|
118
|
+
static_config_files :config
|
119
|
+
end
|
120
|
+
|
121
|
+
config = multi_class.config
|
122
|
+
|
123
|
+
# Both formats should be loaded and merged
|
124
|
+
assert config.key?(:from_yml), "Should have YAML values"
|
125
|
+
assert config.key?(:from_json), "Should have JSON values"
|
126
|
+
|
127
|
+
# YAML should override JSON (alphabetical order: config.yml comes after config.json)
|
128
|
+
assert_equal 'yml_value', config[:shared], "YAML should override JSON for same key"
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_file_processing_order_within_directory
|
132
|
+
# Test that files are processed in a predictable order within each directory
|
133
|
+
FileUtils.mkdir_p('test/format_test/order')
|
134
|
+
|
135
|
+
# Create files that will be processed in alphabetical order
|
136
|
+
File.write('test/format_test/order/config.json', '{"order": "json", "source": "json"}')
|
137
|
+
File.write('test/format_test/order/config.yml', "order: yaml\nsource: yaml")
|
138
|
+
File.write('test/format_test/order/config.conf', ":order: conf\n:source: conf")
|
139
|
+
|
140
|
+
order_class = Class.new do
|
141
|
+
include ConfigFiles
|
142
|
+
config_directories etc: ['test/format_test/order']
|
143
|
+
static_config_files :config
|
144
|
+
end
|
145
|
+
|
146
|
+
config = order_class.config
|
147
|
+
|
148
|
+
# The last file alphabetically should win (yml comes after json and conf)
|
149
|
+
assert_equal 'yaml', config[:order]
|
150
|
+
assert_equal 'yaml', config[:source]
|
151
|
+
end
|
152
|
+
end
|