diff --git a/plugins/kernel_v2/config/vagrant.rb b/plugins/kernel_v2/config/vagrant.rb index 2e097d61b..0954d6a4a 100644 --- a/plugins/kernel_v2/config/vagrant.rb +++ b/plugins/kernel_v2/config/vagrant.rb @@ -7,7 +7,8 @@ module VagrantPlugins attr_accessor :sensitive attr_accessor :plugins - VALID_PLUGIN_KEYS = [:sources, :version, :entry_point].freeze + VALID_PLUGIN_KEYS = ["sources", "version", "entry_point"].map(&:freeze).freeze + INVALID_PLUGIN_FORMAT = :invalid_plugin_format def initialize @host = UNSET_VALUE @@ -43,13 +44,21 @@ module VagrantPlugins errors << I18n.t("vagrant.config.root.sensitive_bad_type") end - @plugins.each do |plugin_name, plugin_info| - invalid_keys = plugin_info.keys - VALID_PLUGIN_KEYS - if !invalid_keys.empty? - errors << I18n.t("vagrant.config.root.plugins_bad_key", - plugin_name: plugin_name, - plugin_key: invalid_keys.join(", ") - ) + if @plugins == INVALID_PLUGIN_FORMAT + errors << I18n.t("vagrant.config.root.plugins_invalid_format") + else + @plugins.each do |plugin_name, plugin_info| + if plugin_info.is_a?(Hash) + invalid_keys = plugin_info.keys - VALID_PLUGIN_KEYS + if !invalid_keys.empty? + errors << I18n.t("vagrant.config.root.plugins_bad_key", + plugin_name: plugin_name, + plugin_key: invalid_keys.join(", ") + ) + end + else + errors << I18n.t("vagrant.config.root.plugins_invalid_format") + end end end @@ -61,18 +70,26 @@ module VagrantPlugins end def format_plugins(val) - result = case val - when String - {val => {}} - when Array - Hash[val.map{|item| [item.to_s, {}]}] - else - val - end - result.keys.each do |key| - result[key] = Hash[result[key].map{|k,v| [k.to_sym, v]}] + case val + when String + {val => Vagrant::Util::HashWithIndifferentAccess.new} + when Array + val.inject(Vagrant::Util::HashWithIndifferentAccess.new) { |memo, item| + memo.merge(format_plugins(item)) + } + when Hash + Vagrant::Util::HashWithIndifferentAccess.new.tap { |h| + val.each_pair { |k, v| + if v.is_a?(Hash) + h[k] = Vagrant::Util::HashWithIndifferentAccess.new(v) + else + h[k] = v + end + } + } + else + INVALID_PLUGIN_FORMAT end - result end end end diff --git a/templates/locales/en.yml b/templates/locales/en.yml index 78717ba01..c5c3af4e0 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -1815,6 +1815,8 @@ en: sensitive_bad_type: |- Invalid type provided for `sensitive`. The sensitive option expects a string or an array of strings. + plugins_invalid_format: |- + Invalid type provided for `plugins`. plugins_bad_key: |- Invalid plugin configuration detected for `%{plugin_name}` plugin. diff --git a/test/unit/plugins/kernel_v2/config/vagrant_test.rb b/test/unit/plugins/kernel_v2/config/vagrant_test.rb index ece682f51..d2f55be2f 100644 --- a/test/unit/plugins/kernel_v2/config/vagrant_test.rb +++ b/test/unit/plugins/kernel_v2/config/vagrant_test.rb @@ -56,4 +56,54 @@ describe VagrantPlugins::Kernel_V2::VagrantConfig do subject.finalize! end end + + describe "#plugins" do + it "converts string into hash of plugins" do + subject.plugins = "vagrant-plugin" + subject.finalize! + expect(subject.plugins).to be_a(Hash) + end + + it "converts array of strings into hash of plugins" do + subject.plugins = ["vagrant-plugin", "vagrant-other-plugin"] + subject.finalize! + expect(subject.plugins).to be_a(Hash) + expect(subject.plugins.keys).to eq(["vagrant-plugin", "vagrant-other-plugin"]) + end + + it "does not convert hash" do + plugins = {"vagrant-plugin" => {}} + subject.plugins = plugins + subject.finalize + expect(subject.plugins).to eq(plugins) + end + + it "converts array of mixed strings and hashes" do + subject.plugins = ["vagrant-plugin", {"vagrant-other-plugin" => {:version => "1"}}] + subject.finalize! + expect(subject.plugins["vagrant-plugin"]).to eq({}) + expect(subject.plugins["vagrant-other-plugin"]).to eq({"version" => "1"}) + end + + it "generates a validation error when incorrect type is provided" do + subject.plugins = 0 + subject.finalize! + result = subject.validate(machine) + expect(result.values).not_to be_empty + end + + it "generates a validation error when invalid option is provided" do + subject.plugins = {"vagrant-plugin" => {"badkey" => true}} + subject.finalize! + result = subject.validate(machine) + expect(result.values).not_to be_empty + end + + it "generates a validation error when options are incorrect type" do + subject.plugins = {"vagrant-plugin" => 1} + subject.finalize! + result = subject.validate(machine) + expect(result.values).not_to be_empty + end + end end