# encoding: utf-8 require 'spec_helper' require 'fedux_org_stdlib/app_config' RSpec.describe AppConfig do context 'options' do it 'creates readers and writers' do config_klass = Class.new(AppConfig) do option :opt1, nil def _class_name 'TestConfig' end def _module_name 'MyApplication' end end config = config_klass.new expect(config.opt1).to be_nil config.opt1 = 'blub' expect(config.opt1).to eq 'blub' end it 'creates readers' do config_klass = Class.new(AppConfig) do option_reader :opt1, nil def _class_name 'TestConfig' end def _module_name 'MyApplication' end end config = config_klass.new expect(config.opt1).to be_nil silence :stderr do expect do config.opt1 = 'blub' end.to raise_error NoMethodError end end it 'checks for reserved key words' do expect do Class.new(AppConfig) do option_reader :_config_file, nil def _class_name 'TestConfig' end def _module_name 'MyApplication' end end end.to raise_error FeduxOrgStdlib::AppConfig::Exceptions::OptionNameForbidden end it 'output default values' do config_klass = Class.new(AppConfig) do option_reader :opt1, 'foobar' def _class_name 'TestConfig' end def _module_name 'MyApplication' end end write_file '~/.tests.yaml', <<-EOS.strip_heredoc --- opt1: hello world EOS config = config_klass.new expect(config.defaults.opt1).to eq 'foobar' expect(config.opt1).to eq 'hello world' end it 'uses the first file found' do config_klass = Class.new(AppConfig) do option_reader :opt1, 'foobar' option_reader :opt2, 'foobar' def _class_name 'TestConfig' end def _module_name 'MyApplication' end end write_file '~/.config/my_application/tests.yaml', <<-EOS.strip_heredoc --- opt1: hello world config EOS write_file '~/.tests.yaml', <<-EOS.strip_heredoc --- opt1: hello world home opt2: hello world home EOS config = config_klass.new(merge_files: false) expect(config.opt1).to eq 'hello world config' expect(config.opt2).to eq 'foobar' end it 'merges files on request' do config_klass = Class.new(AppConfig) do option_reader :opt1, 'foobar' option_reader :opt2, 'foobar' def _class_name 'TestConfig' end def _module_name 'MyApplication' end end write_file '~/.config/my_application/tests.yaml', <<-EOS.strip_heredoc --- opt1: hello world config EOS write_file '~/.tests.yaml', <<-EOS.strip_heredoc --- opt1: hello world home opt2: hello world home EOS config = config_klass.new(merge_files: true) expect(config.opt1).to eq 'hello world config' expect(config.opt2).to eq 'hello world home' end end context '#lock' do it 'raises error if config is locked and one tries to modify a config option' do config_klass = Class.new(AppConfig) do option :opt1, nil def _class_name 'TestConfig' end def _module_name 'MyApplication' end end config = config_klass.new config.lock expect { config.opt1 = 1 }.to raise_error FeduxOrgStdlib::AppConfig::Exceptions::ConfigLocked end end context '#preferred_configuration_file' do it 'has a default configuration file which is the preferred place to store the configuration' do config_klass = Class.new(AppConfig) do def _class_name 'TestConfig' end def _module_name 'MyApplication' end end config = config_klass.new expect(config.preferred_configuration_file).to eq File.expand_path('~/.config/my_application/tests.yaml') end it 'works with nested module names' do config_klass = Class.new(AppConfig) do def _class_name 'TestConfig' end def _module_name 'MyApplication::MySub' end end config = config_klass.new expect(config.preferred_configuration_file).to eq File.expand_path('~/.config/my_application/my_sub/tests.yaml') end end context 'config files' do it 'looks at ~/.test.yaml' do write_file '.tests.yaml', <<-EOS.strip_heredoc --- opt1: hello world EOS config_klass = Class.new(AppConfig) do option_reader :opt1, nil def _class_name 'TestConfig' end def _module_name 'MyApplication' end end config = config_klass.new expect(config.opt1).to eq 'hello world' end it 'looks at ~/.config/my_application/tests.yaml' do write_file '.config/my_application/tests.yaml', <<-EOS.strip_heredoc --- opt1: hello world EOS config_klass = Class.new(AppConfig) do option_reader :opt1, nil def _class_name 'TestConfig' end def _module_name 'MyApplication' end end config = config_klass.new expect(config.opt1).to eq 'hello world' end it 'looks at ~/.my_application/tests.yaml' do write_file '.my_application/tests.yaml', <<-EOS.strip_heredoc --- opt1: hello world EOS config_klass = Class.new(AppConfig) do option_reader :opt1, nil def _class_name 'TestConfig' end def _module_name 'MyApplication' end end config = config_klass.new expect(config.opt1).to eq 'hello world' end it 'looks at ~/.tests.yaml' do write_file '.tests.yaml', <<-EOS.strip_heredoc --- opt1: hello world EOS config_klass = Class.new(AppConfig) do option_reader :opt1, nil def _class_name 'TestConfig' end def _module_name 'MyApplication' end end config = config_klass.new expect(config.opt1).to eq 'hello world' end it 'looks at ~/.testsrc' do write_file '.testsrc', <<-EOS.strip_heredoc --- opt1: hello world EOS config_klass = Class.new(AppConfig) do option_reader :opt1, nil def _class_name 'TestConfig' end def _module_name 'MyApplication' end end config = config_klass.new expect(config.opt1).to eq 'hello world' end it 'loads yaml files with the following data types' do write_file '.testsrc', <<-EOS.strip_heredoc --- opt1: hello world opt2: :test opt3: 1 opt4: true opt5: false opt6: - a - b opt7: name: berni EOS config_klass = Class.new(AppConfig) do option_reader :opt1, nil option_reader :opt2, nil option_reader :opt3, nil option_reader :opt4, nil option_reader :opt5, nil option_reader :opt6, nil option_reader :opt7, nil def _class_name 'TestConfig' end def _module_name 'MyApplication' end end config = config_klass.new expect(config.opt1).to eq 'hello world' end it 'raises error on invalid yaml file' do write_file '.testsrc', random_binary_string(100) config_klass = Class.new(AppConfig) do def _class_name 'TestConfig' end def _module_name 'MyApplication' end end expect { config_klass.new }.to raise_error FeduxOrgStdlib::AppConfig::Exceptions::ConfigFileNotReadable end it 'returns an empty config if data file cannot be transformed to hash' do write_file '.testsrc', <<-EOS.strip_heredoc --- - hello - world EOS config_klass = Class.new(AppConfig) do def _class_name 'TestConfig' end def _module_name 'MyApplication' end end result = capture :stderr do config_klass.new end expect(result).to include 'There seems' end end context '#to_s' do it 'outputs a list of variables' do config_klass = Class.new(AppConfig) do option :opt1, 'test1' option :opt2, 'test2' option :opt3, opt1: 'test1', opt2: 'test2' def _class_name 'TestConfig' end def _module_name 'MyApplication' end end config = config_klass.new expect(config.to_s).to eq <<-EOS.strip_heredoc.chomp option | value ------ + -------------------------------------------------------------------------------- opt1 | "test1" opt2 | "test2" opt3 | "opt1: test1", "opt2: test2" EOS end it 'outputs is undefined for blank values (nil, '', ...)' do config_klass = Class.new(AppConfig) do option :opt1, nil option :opt2, '' option :opt3, 'asdf' option :opt4, false def _class_name 'TestConfig' end def _module_name 'MyApplication' end end config = config_klass.new expect(config.to_s).to eq <<-EOS.strip_heredoc.chomp option | value ------ + -------------------------------------------------------------------------------- opt1 | "is undefined" opt2 | "is undefined" opt3 | "asdf" opt4 | "false" EOS end end context '#reload' do it 're-reads it' do config_klass = Class.new(AppConfig) do option :opt1, 'test1' def _class_name 'TestConfig' end def _module_name 'MyApplication' end end write_file 'tests.yaml', <<-EOS.strip_heredoc --- opt1: test2 EOS config = in_current_dir do config_klass.new end expect(config.opt1).to eq 'test2' write_file 'tests.yaml', <<-EOS.strip_heredoc --- opt1: test3 EOS config.reload expect(config.opt1).to eq 'test3' end end context '#redetect' do it 'looks for config file again and re-reads it' do config_klass = Class.new(AppConfig) do option :opt1, 'test1' def _class_name 'TestConfig' end def _module_name 'MyApplication' end end write_file 'tests.yaml', <<-EOS.strip_heredoc --- opt1: test2 EOS config = in_current_dir do config_klass.new end expect(config.opt1).to eq 'test2' write_file '~/.config/my_application/tests.yaml', <<-EOS.strip_heredoc --- opt1: test3 EOS config.redetect expect(config.opt1).to eq 'test3' end end context '#known_options' do it 'outputs a list of known options' do config_klass = Class.new(AppConfig) do option :opt1, 'test1' option :opt2, 'test2' option :opt3, opt1: 'test1', opt2: 'test2' def _class_name 'TestConfig' end def _module_name 'MyApplication' end end config = config_klass.new expect(config.known_options).to include :opt1, :opt2, :opt3 expect(config.class.known_options).to eq config.known_options end end context '#to_h' do it 'dumps configuration to hash' do config_klass = Class.new(AppConfig) do option :opt1, 'test1' option :opt2, [ 'test2', 'test2', ] option :opt3, { test3: 'value3' } def _class_name 'TestConfig' end def _module_name 'MyApplication' end end config = config_klass.new expect(config.to_h).to eq( opt1: 'test1', opt2: %w( test2 test2 ), opt3: { test3: 'value3' } ) end it 'filters keys by symbols' do config_klass = Class.new(AppConfig) do option :opt1, 'test1' option :opt2, [ 'test2', 'test2', ] option :opt3, { test3: 'value3' } def _class_name 'TestConfig' end def _module_name 'MyApplication' end end config = config_klass.new expect(config.to_h(keys: [:opt1])).to eq( opt1: 'test1' ) end it 'filters keys by strings' do config_klass = Class.new(AppConfig) do option :opt1, 'test1' option :opt2, [ 'test2', 'test2', ] option :opt3, { test3: 'value3' } def _class_name 'TestConfig' end def _module_name 'MyApplication' end end config = config_klass.new expect(config.to_h(keys: ['opt1'])).to eq( opt1: 'test1' ) end it 'filters keys if nil' do config_klass = Class.new(AppConfig) do option :opt1, 'test1' option :opt2, [] option :opt3, {} option :opt4, nil def _class_name 'TestConfig' end def _module_name 'MyApplication' end end config = config_klass.new expect(config.to_h(remove_blank: true)).to eq( opt1: 'test1' ) end end context '#to_yaml' do it 'dumps configuration to yaml' do config_klass = Class.new(AppConfig) do option :opt1, 'test1' option :opt2, [ 'test2', 'test2', ] option :opt3, { test3: 'value3' } def _class_name 'TestConfig' end def _module_name 'MyApplication' end end config = config_klass.new expect(config.to_yaml).to eq <<-EOS.strip_heredoc --- opt1: test1 opt2: - test2 - test2 opt3: test3: value3 EOS end it 'filters keys' do config_klass = Class.new(AppConfig) do option :opt1, 'test1' option :opt2, [ 'test2', 'test2', ] option :opt3, { test3: 'value3' } def _class_name 'TestConfig' end def _module_name 'MyApplication' end end config = config_klass.new expect( config.to_yaml(keys: [:opt1]) ).to eq <<-EOS.strip_heredoc --- opt1: test1 EOS end end end