From d39abc2ae7ccbfde5325c14654616fd8cc79f411 Mon Sep 17 00:00:00 2001 From: Justin Martin Date: Tue, 6 Oct 2015 02:34:07 -0700 Subject: [PATCH] [Environment Variables] Add support for scheme environment variables --- .rubocop_todo.yml | 20 +- CHANGELOG.md | 4 + lib/xcodeproj/constants.rb | 2 +- lib/xcodeproj/scheme/environment_variables.rb | 117 +++++++++ lib/xcodeproj/scheme/launch_action.rb | 22 ++ lib/xcodeproj/scheme/test_action.rb | 23 ++ .../xcschemes/SharedSchemes.xcscheme | 30 ++- spec/plist_helper_spec.rb | 2 +- spec/scheme/environment_variables_spec.rb | 230 ++++++++++++++++++ spec/scheme/launch_action_spec.rb | 59 +++++ spec/scheme/test_action_spec.rb | 60 +++++ spec/scheme_spec.rb | 8 + 12 files changed, 557 insertions(+), 20 deletions(-) create mode 100644 lib/xcodeproj/scheme/environment_variables.rb create mode 100644 spec/scheme/environment_variables_spec.rb diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 220b740a3..713e6b6ec 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,35 +1,23 @@ -# This configuration was generated by `rubocop --auto-gen-config` -# on 2015-03-06 13:49:50 +0100 using RuboCop version 0.28.0. +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2015-10-25 15:59:02 -0700 using RuboCop version 0.34.2. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 499 +# Offense count: 804 # Configuration parameters: AllowURI, URISchemes. Metrics/LineLength: Max: 186 -# Offense count: 66 -# Configuration parameters: CountComments. -Metrics/MethodLength: - Max: 46 - # Offense count: 2 # Configuration parameters: CountKeywordArgs. Metrics/ParameterLists: Max: 7 -# Offense count: 9 -Metrics/PerceivedComplexity: - Max: 16 - # Offense count: 94 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. Style/DotPosition: Enabled: false - -# Offense count: 1 -Style/DoubleNegation: - Enabled: false diff --git a/CHANGELOG.md b/CHANGELOG.md index 982149f78..2ca312a60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ ##### Enhancements +* Add accessors for working with Environment Variables in xcscheme files + [Justin Martin](https://github.com/justinseanmartin) + [Xcodeproj#326](https://github.com/CocoaPods/Xcodeproj/pull/326) + * Add method to create new variant groups (groups for localized versions of the same file) [Tim Bodeit](https://github.com/timbodeit) [Xcodeproj#315](https://github.com/CocoaPods/Xcodeproj/pull/315) diff --git a/lib/xcodeproj/constants.rb b/lib/xcodeproj/constants.rb index d08d925cb..431f390d7 100644 --- a/lib/xcodeproj/constants.rb +++ b/lib/xcodeproj/constants.rb @@ -8,7 +8,7 @@ module Constants # @return [String] The last known OS X SDK (stable). # - LAST_KNOWN_OSX_SDK = '10.11' + LAST_KNOWN_OSX_SDK = '10.11' # @return [String] The last known tvOS SDK (stable). LAST_KNOWN_TVOS_SDK = '9.0' diff --git a/lib/xcodeproj/scheme/environment_variables.rb b/lib/xcodeproj/scheme/environment_variables.rb new file mode 100644 index 000000000..f6858a9ec --- /dev/null +++ b/lib/xcodeproj/scheme/environment_variables.rb @@ -0,0 +1,117 @@ +require 'xcodeproj/scheme/xml_element_wrapper' + +module Xcodeproj + class XCScheme + VARIABLES_NODE = 'EnvironmentVariables' + VARIABLE_NODE = 'EnvironmentVariable' + + # This class wraps the EnvironmentVariables node of a .xcscheme XML file. This + # is just a container of EnvironmentVariable objects. It can either appear on a + # LaunchAction or TestAction scheme group. + # + class EnvironmentVariables < XMLElementWrapper + # @param [REXML::Element,Array{EnvironmentVariable},Array{Hash{String => String}}] node_or_target + # The 'EnvironmentVariables' XML node that this object represents. + # If nil, it will create a default XML node to use. + # + def initialize(node_or_target = nil) + create_xml_element_with_fallback(node_or_target, VARIABLES_NODE) do + @all_variables = [] + node_or_target.each { |var| add_variable(var) } unless node_or_target.nil? + end + end + + # @return [Array{EnvironmentVariable}] + # The key value pairs currently set in @xml_element + # + def all_variables + @all_variables ||= @xml_element.get_elements(VARIABLE_NODE).map { |variable| EnvironmentVariable.new(variable) } + end + + # @param [EnvironmentVariable,Hash{String => String}] variable + # The key value pairs currently set in @xml_element + # + # @return [Array{EnvironmentVariable}] + # The new set of environment variables after addition + # + def add_variable(variable) + env_var = variable.is_a?(EnvironmentVariable) ? variable : EnvironmentVariable.new(variable) + all_variables.each { |existing_var| remove_variable(existing_var) if existing_var.key == env_var.key } + @xml_element.add_element(env_var.xml_element) + @all_variables << env_var + end + + # @param [EnvironmentVariable,Hash{String => String}] variable + # The key value pairs currently set in @xml_element + # + # @return [Array{EnvironmentVariable}] + # The new set of environment variables after removal + # + def remove_variable(variable) + env_var = variable.is_a?(EnvironmentVariable) ? variable : all_variables.select { |var| var.key == variable[:key] }[0] + raise "Unexpected parameter type: #{env_var.class}" unless env_var.is_a?(EnvironmentVariable) + @xml_element.delete_element(env_var.xml_element) + @all_variables -= [env_var] + end + + # @param [EnvironmentVariable,Hash{String => String}] variable + # The key value pairs currently set in @xml_element + # + def to_a + all_variables.map(&:to_h) + end + end + + # This class wraps the EnvironmentVariable node of a .xcscheme XML file. + # Environment variables are accessible via the NSDictionary returned from + # [[NSProcessInfo processInfo] environment] in your app code. + # + class EnvironmentVariable < XMLElementWrapper + # @param [REXML::Element,EnvironmentVariable,Hash{String => String}] value + # The 'EnvironmentVariable' XML node that this object represents. + # If nil, it will create a default XML node to use. If a hash, it + # must contain keys 'key' and 'value', and optionally have 'enabled'. + # If not supplied, it will default to being enabled. + # + def initialize(value) + create_xml_element_with_fallback(value, VARIABLE_NODE) do + raise "Must pass a Hash with 'key' and 'value'!" unless value.is_a?(Hash) && value.key?(:key) && value.key?(:value) + + @xml_element.attributes['key'] = value[:key] + @xml_element.attributes['value'] = value[:value] + @xml_element.attributes['isEnabled'] = value.key?(:enabled) ? bool_to_string(value[:enabled]) : bool_to_string(true) + end + end + + def key + @xml_element.attributes['key'] + end + + def key=(key) + @xml_element.attributes['key'] = key + end + + def value + @xml_element.attributes['value'] + end + + def value=(value) + @xml_element.attributes['value'] = value + end + + def enabled + string_to_bool(@xml_element.attributes['isEnabled']) + end + + def enabled=(enabled) + @xml_element.attributes['isEnabled'] = bool_to_string(enabled) + end + + # @return [Hash{:key => String, :value => String, :enabled => Boolean}] + # The environment variable XML node with attributes converted to Hash keys + def to_h + { :key => key, :value => value, :enabled => enabled } + end + end + end +end diff --git a/lib/xcodeproj/scheme/launch_action.rb b/lib/xcodeproj/scheme/launch_action.rb index 8427f3382..6e51502c9 100644 --- a/lib/xcodeproj/scheme/launch_action.rb +++ b/lib/xcodeproj/scheme/launch_action.rb @@ -62,6 +62,28 @@ def buildable_product_runnable=(runnable) @xml_element.add_element(runnable.xml_element) if runnable end + # @return [EnvironmentVariables] + # Returns the set of environment variables that are currently set at test runtime + # NOTE: If this creates a new node, it will not automatically be added to the xml document + # + def environment_variables + env_vars_nodes = @xml_element.get_elements(XCScheme::VARIABLES_NODE) + raise 'Unexpected number of EnvironmentVariables nodes found!' if env_vars_nodes.count > 1 + + env_vars_nodes.count == 0 ? nil : EnvironmentVariables.new(env_vars_nodes[0]) + end + + # @param [EnvironmentVariables] env_vars + # Overwrites the set of environment variables that should be set at test runtime + # + def environment_variables=(env_vars) + @xml_element.get_elements(XCScheme::VARIABLES_NODE).each { |node| node.parent.delete_element(node) } + + raise "Unexpected parameter type: #{env_vars.class}" unless env_vars.nil? || env_vars.is_a?(EnvironmentVariables) + @xml_element.add_element(env_vars.xml_element) unless env_vars.nil? + environment_variables + end + # @todo handle 'AdditionalOptions' tag end end diff --git a/lib/xcodeproj/scheme/test_action.rb b/lib/xcodeproj/scheme/test_action.rb index f339a1360..01566c999 100644 --- a/lib/xcodeproj/scheme/test_action.rb +++ b/lib/xcodeproj/scheme/test_action.rb @@ -1,4 +1,5 @@ require 'xcodeproj/scheme/abstract_scheme_action' +require 'xcodeproj/scheme/environment_variables' module Xcodeproj class XCScheme @@ -84,6 +85,28 @@ def add_macro_expansion(macro_expansion) @xml_element.add_element(macro_expansion.xml_element) end + # @return [EnvironmentVariables] + # Returns the set of environment variables that are currently set at test runtime + # NOTE: If this creates a new node, it will not automatically be added to the xml document + # + def environment_variables + env_vars_nodes = @xml_element.get_elements(XCScheme::VARIABLES_NODE) + raise 'Unexpected number of EnvironmentVariables nodes found!' if env_vars_nodes.count > 1 + + env_vars_nodes.count == 0 ? nil : EnvironmentVariables.new(env_vars_nodes[0]) + end + + # @param [EnvironmentVariables] env_vars + # Overwrites the set of environment variables that should be set at test runtime + # + def environment_variables=(env_vars) + @xml_element.get_elements(XCScheme::VARIABLES_NODE).each { |node| node.parent.delete_element(node) } + + raise "Unexpected parameter type: #{env_vars.class}" unless env_vars.nil? || env_vars.is_a?(EnvironmentVariables) + @xml_element.add_element(env_vars.xml_element) unless env_vars.nil? + environment_variables + end + #-------------------------------------------------------------------------# class TestableReference < XMLElementWrapper diff --git a/spec/fixtures/SharedSchemes/SharedSchemes.xcodeproj/xcshareddata/xcschemes/SharedSchemes.xcscheme b/spec/fixtures/SharedSchemes/SharedSchemes.xcodeproj/xcshareddata/xcschemes/SharedSchemes.xcscheme index aa4abb0b3..15a103895 100644 --- a/spec/fixtures/SharedSchemes/SharedSchemes.xcodeproj/xcshareddata/xcschemes/SharedSchemes.xcscheme +++ b/spec/fixtures/SharedSchemes/SharedSchemes.xcodeproj/xcshareddata/xcschemes/SharedSchemes.xcscheme @@ -38,6 +38,18 @@ ReferencedContainer = "container:SharedSchemes.xcodeproj"> + + + + + + - + + + + + + + @@ -66,7 +91,8 @@ useCustomWorkingDirectory = "NO" buildConfiguration = "Release" debugDocumentVersioning = "YES"> - + { 'a hash' => 'in a hash' }, + 'hash' => { 'a hash' => 'in a hash' }, 'string' => 'string', 'true_bool' => '1', 'false_bool' => '0', diff --git a/spec/scheme/environment_variables_spec.rb b/spec/scheme/environment_variables_spec.rb new file mode 100644 index 000000000..0a34a069a --- /dev/null +++ b/spec/scheme/environment_variables_spec.rb @@ -0,0 +1,230 @@ +require File.expand_path('../../spec_helper', __FILE__) + +module Xcodeproj + @xml_formatter = REXML::Formatters::Pretty.new(0) + @xml_formatter.compact = true + + def self.xml_for_object(object) + xml_out = '' + @xml_formatter.write(object.xml_element, xml_out) + xml_out.lines.each(&:strip!).join('') + end + + describe XCScheme::EnvironmentVariables do + describe '#initialize' do + describe 'creates a new EnvironmentVariable object' do + it 'when passed nothing' do + subject = XCScheme::EnvironmentVariables.new + Xcodeproj.xml_for_object(subject).should == '' + end + + it 'when passed an array of hashes with key and value' do + subject = XCScheme::EnvironmentVariables.new([{ :key => 'key', :value => 'value' }]) + Xcodeproj.xml_for_object(subject).should == + "" + end + + it 'when passed an existing EnvironmentVariable XML node' do + subject = XCScheme::EnvironmentVariables.new([{ :key => 'key', :value => 'value' }]) + copy = XCScheme::EnvironmentVariables.new(subject.xml_element) + subject.should.not.be.same_as copy + Xcodeproj.xml_for_object(copy).should == + "" + end + + it 'when passed an array of XML nodes' do + subject = XCScheme::EnvironmentVariables.new([{ :key => 'key', :value => 'value' }]) + copy = XCScheme::EnvironmentVariables.new(subject.all_variables) + Xcodeproj.xml_for_object(copy).should == + "" + end + end + end + + describe '#all_variables' do + it 'returns an empty array' do + subject = XCScheme::EnvironmentVariables.new + subject.all_variables.should == [] + end + + it 'returns all items, regardless of enabled state' do + subject = XCScheme::EnvironmentVariables.new([{ :key => 'key1', :value => 'value1' }, + { :key => 'key2', :value => 'value2', :enabled => false }]) + subject.all_variables.count.should == 2 + subject.all_variables.each { |var| var.should.is_a? XCScheme::EnvironmentVariable } + subject.all_variables[0].to_h.should == { :key => 'key1', :value => 'value1', :enabled => true } + subject.all_variables[1].to_h.should == { :key => 'key2', :value => 'value2', :enabled => false } + end + end + + describe '#add_variable' do + it 'adds a new environment variable by Hash' do + subject = XCScheme::EnvironmentVariables.new + subject.add_variable(:key => 'key1', :value => 'value1') + + subject.all_variables.count.should == 1 + subject.all_variables[0].to_h.should == { :key => 'key1', :value => 'value1', :enabled => true } + Xcodeproj.xml_for_object(subject).should == + "" + end + + it 'adds a new variable by object using the same object' do + subject = XCScheme::EnvironmentVariables.new + new_var = XCScheme::EnvironmentVariable.new(:key => 'key1', :value => 'value1') + subject.add_variable(new_var) + + subject.all_variables.count.should == 1 + subject.all_variables[0].to_h.should == { :key => 'key1', :value => 'value1', :enabled => true } + subject.all_variables[0].should.equal?(new_var) + end + + it 'adds a new variable by node using the same xml_element' do + subject = XCScheme::EnvironmentVariables.new + new_var = XCScheme::EnvironmentVariable.new(:key => 'key1', :value => 'value1') + subject.add_variable(new_var.xml_element) + + subject.all_variables.count.should == 1 + subject.all_variables[0].to_h.should == { :key => 'key1', :value => 'value1', :enabled => true } + subject.all_variables[0].xml_element.should.equal?(new_var.xml_element) + end + + it 'merges in a new entry if a matching key does not exist' do + subject = XCScheme::EnvironmentVariables.new([:key => 'key1', :value => 'value1']) + subject.add_variable(:key => 'key2', :value => 'value2') + subject.to_a.should == [{ :key => 'key1', :value => 'value1', :enabled => true }, + { :key => 'key2', :value => 'value2', :enabled => true }] + end + + it 'updates an existing variable value if one already exists with that key' do + subject = XCScheme::EnvironmentVariables.new([:key => 'key1', :value => 'value1']) + subject.add_variable(:key => 'key1', :value => 'value3') + subject.to_a.should == [:key => 'key1', :value => 'value3', :enabled => true] + end + + it 'updates an existing variable enabled state if one already exists with that key' do + subject = XCScheme::EnvironmentVariables.new([{ :key => 'key1', :value => 'value1' }, + { :key => 'key2', :value => 'value2', :enabled => false }]) + subject.add_variable(:key => 'key1', :value => 'value1', :enabled => false) + subject.add_variable(:key => 'key2', :value => 'value2') + + subject.to_a.should == [{ :key => 'key1', :value => 'value1', :enabled => false }, + { :key => 'key2', :value => 'value2', :enabled => true }] + end + end + + describe '#remove_variable' do + it 'returns the new set of environment variables after removal' do + subject = XCScheme::EnvironmentVariables.new([{ :key => 'key1', :value => 'value1' }, + { :key => 'key2', :value => 'value2' }]) + subject.remove_variable(:key => 'key1')[0].to_h.should == { :key => 'key2', :value => 'value2', :enabled => true } + subject.to_a.should == [:key => 'key2', :value => 'value2', :enabled => true] + Xcodeproj.xml_for_object(subject).should == + "" + end + + it 'removes an existing entry with same EnvironmentVariable object' do + new_var = XCScheme::EnvironmentVariable.new(:key => 'key1', :value => 'value1') + subject = XCScheme::EnvironmentVariables.new([new_var]) + subject.remove_variable(new_var) + subject.to_a.should == [] + Xcodeproj.xml_for_object(subject).should == '' + end + + it 'removes an existing entry with matching EnvironmentVariable object' do + subject = XCScheme::EnvironmentVariables.new([:key => 'key1', :value => 'value1']) + subject.remove_variable(:key => 'key1') + subject.to_a.should == [] + end + + it 'does nothing if the the EnvironmentVariable isn\'t in all' do + subject = XCScheme::EnvironmentVariables.new([:key => 'key1', :value => 'value1']) + new_var = XCScheme::EnvironmentVariable.new(:key => 'key2', :value => 'value2') + subject.remove_variable(new_var) + subject.to_a.should == [:key => 'key1', :value => 'value1', :enabled => true] + end + + it 'does nothing if the variable does not exist' do + subject = XCScheme::EnvironmentVariables.new([:key => 'key1', :value => 'value1']) + new_var = XCScheme::EnvironmentVariable.new(:key => 'key2', :value => 'value2') + subject.remove_variable(new_var) + subject.to_a.should == [:key => 'key1', :value => 'value1', :enabled => true] + end + + it 'does nothing if the enabled state does not match' do + subject = XCScheme::EnvironmentVariables.new([:key => 'key1', :value => 'value1']) + new_var = XCScheme::EnvironmentVariable.new(:key => 'key1', :value => 'value2') + new_var2 = XCScheme::EnvironmentVariable.new(:key => 'key1', :value => 'value1', :enabled => true) + subject.remove_variable(new_var) + subject.remove_variable(new_var2) + subject.to_a.should == [:key => 'key1', :value => 'value1', :enabled => true] + end + end + end + + describe XCScheme::EnvironmentVariable do + describe '#initialize' do + describe 'raises an initialization error nil' do + init_exception = /Must pass a Hash with 'key' and 'value'!/ + + it 'when passed nil' do + lambda { XCScheme::EnvironmentVariable.new(nil) }.should.raise(RuntimeError).message + .should.match(init_exception) + end + + it 'when Hash is empty' do + lambda { XCScheme::EnvironmentVariable.new({}) }.should.raise(RuntimeError).message + .should.match(init_exception) + end + + it 'when Hash is missing key' do + lambda { XCScheme::EnvironmentVariable.new(:value => 'value') }.should.raise(RuntimeError) + .message.should.match(init_exception) + end + + it 'when Hash is missing value' do + lambda { XCScheme::EnvironmentVariable.new(:key => 'key') }.should.raise(RuntimeError) + .message.should.match(init_exception) + end + end + + describe 'creates a new EnvironmentVariable object' do + it 'when passed an array of hashes with key and value' do + subject = XCScheme::EnvironmentVariable.new(:key => 'key', :value => 'value') + Xcodeproj.xml_for_object(subject).should == "" + end + + it 'when passed an array of hashes with key, value and enabled state' do + subject = XCScheme::EnvironmentVariable.new(:key => 'key', :value => 'value', :enabled => false) + Xcodeproj.xml_for_object(subject).should == "" + end + + it 'when passed an XML node' do + var = XCScheme::EnvironmentVariable.new(:key => 'copykey', :value => 'copyvalue') + subject = XCScheme::EnvironmentVariable.new(var.xml_element) + Xcodeproj.xml_for_object(subject).should == "" + Xcodeproj.xml_for_object(subject).should == Xcodeproj.xml_for_object(var) + subject.should.not.equal?(var) + end + end + + describe 'EnvironmentVariable accessors return values from the XML' do + subject = XCScheme::EnvironmentVariable.new(:key => 'key', :value => 'value', :enabled => false) + subject.key.should == 'key' + subject.value.should == 'value' + subject.enabled.should == false + end + + describe 'EnvironmentVariable modifiers mutate the XML' do + subject = XCScheme::EnvironmentVariable.new(:key => 'key', :value => 'value') + Xcodeproj.xml_for_object(subject).should == "" + before_modifiers = subject.xml_element + + subject.key = 'key2' + subject.value = 'value2' + subject.enabled = false + Xcodeproj.xml_for_object(subject).should == "" + subject.should.equal?(before_modifiers) + end + end + end +end diff --git a/spec/scheme/launch_action_spec.rb b/spec/scheme/launch_action_spec.rb index 78da97463..70237f0e5 100644 --- a/spec/scheme/launch_action_spec.rb +++ b/spec/scheme/launch_action_spec.rb @@ -55,6 +55,65 @@ module Xcodeproj @sut.xml_element.elements['BuildableProductRunnable'].should == bpr.xml_element end end + + describe '#environment_variables' do + vars_node_name = XCScheme::VARIABLES_NODE + var_node_name = XCScheme::VARIABLE_NODE + + it 'starts as nil if no xml exists' do + @sut.xml_element.elements[vars_node_name].should.equal nil + @sut.environment_variables.should.equal nil + end + + it 'picks up an existing node if exists in the XML' do + env_vars_xml = @sut.xml_element.add_element(vars_node_name) + env_vars_xml.add_element(var_node_name, 'isEnabled' => 'YES', 'key' => 'a', 'value' => '1') + env_vars_xml.add_element(var_node_name, 'isEnabled' => 'NO', 'key' => 'b', 'value' => '2') + + # Reload content from XML + @sut = XCScheme::LaunchAction.new(@sut.xml_element) + + @sut.environment_variables.to_a.should == [{ :key => 'a', :value => '1', :enabled => true }, + { :key => 'b', :value => '2', :enabled => false }] + end + + it 'reflects direct changes to xml' do + @sut.environment_variables = XCScheme::EnvironmentVariables.new([{ :key => 'a', :value => '1', :enabled => false }, + { :key => 'b', :value => '2', :enabled => true }, + { :key => 'c', :value => '3', :enabled => true }]) + node_to_delete = @sut.environment_variables.xml_element.elements["#{var_node_name}[@key='b']"] + @sut.environment_variables.xml_element.delete(node_to_delete) + @sut.environment_variables.to_a.should == [{ :key => 'a', :value => '1', :enabled => false }, + { :key => 'c', :value => '3', :enabled => true }] + end + + it 'can be assigned nil' do + @sut.xml_element.get_elements(vars_node_name).count.should == 0 + + @sut.environment_variables = XCScheme::EnvironmentVariables.new + @sut.environment_variables.should.not.equal nil + @sut.xml_element.get_elements(vars_node_name).count.should == 1 + + @sut.environment_variables = nil + @sut.environment_variables.should.equal nil + @sut.xml_element.get_elements(vars_node_name).count.should == 0 + end + + it 'assigning an EnvironmentVariables object updates the xml' do + env_var = Xcodeproj::XCScheme::EnvironmentVariables.new([{ :key => 'a', :value => '1' }]) + env_var.xml_element.elements.count.should == 1 + + @sut.environment_variables = env_var + @sut.environment_variables.to_a.should == [{ :key => 'a', :value => '1', :enabled => true }] + @sut.environment_variables.xml_element.should == env_var.xml_element + + xml_out = '' + xml_formatter = REXML::Formatters::Pretty.new(0) + xml_formatter.compact = true + xml_formatter.write(@sut.environment_variables.xml_element, xml_out) + xml_out.should == "\n\n" + end + end end end end diff --git a/spec/scheme/test_action_spec.rb b/spec/scheme/test_action_spec.rb index 48c376855..984302c56 100644 --- a/spec/scheme/test_action_spec.rb +++ b/spec/scheme/test_action_spec.rb @@ -83,6 +83,7 @@ module Xcodeproj it '#add_macro_expansion' do project = Xcodeproj::Project.new('/foo/bar/baz.xcodeproj') + @sut.xml_element.add_element('Testables') target1 = project.new_target(:application, 'FooApp', :ios) macro1 = XCScheme::MacroExpansion.new(target1) @@ -96,6 +97,65 @@ module Xcodeproj @sut.xml_element.elements['MacroExpansion[1]'].should == macro1.xml_element @sut.xml_element.elements['MacroExpansion[2]'].should == macro2.xml_element end + + describe '#environment_variables' do + vars_node_name = XCScheme::VARIABLES_NODE + var_node_name = XCScheme::VARIABLE_NODE + + it 'starts as nil if no xml exists' do + @sut.xml_element.elements[vars_node_name].should.equal nil + @sut.environment_variables.should.equal nil + end + + it 'picks up an existing node if exists in the XML' do + env_vars_xml = @sut.xml_element.add_element(vars_node_name) + env_vars_xml.add_element(var_node_name, 'isEnabled' => 'YES', 'key' => 'a', 'value' => '1') + env_vars_xml.add_element(var_node_name, 'isEnabled' => 'NO', 'key' => 'b', 'value' => '2') + + # Reload content from XML + @sut = XCScheme::TestAction.new(@sut.xml_element) + + @sut.environment_variables.to_a.should == [{ :key => 'a', :value => '1', :enabled => true }, + { :key => 'b', :value => '2', :enabled => false }] + end + + it 'reflects direct changes to xml' do + @sut.environment_variables = XCScheme::EnvironmentVariables.new([{ :key => 'a', :value => '1', :enabled => false }, + { :key => 'b', :value => '2', :enabled => true }, + { :key => 'c', :value => '3', :enabled => true }]) + node_to_delete = @sut.environment_variables.xml_element.elements["#{var_node_name}[@key='b']"] + @sut.environment_variables.xml_element.delete(node_to_delete) + @sut.environment_variables.to_a.should == [{ :key => 'a', :value => '1', :enabled => false }, + { :key => 'c', :value => '3', :enabled => true }] + end + + it 'can be assigned nil' do + @sut.xml_element.get_elements(vars_node_name).count.should == 0 + + @sut.environment_variables = XCScheme::EnvironmentVariables.new + @sut.environment_variables.should.not.equal nil + @sut.xml_element.get_elements(vars_node_name).count.should == 1 + + @sut.environment_variables = nil + @sut.environment_variables.should.equal nil + @sut.xml_element.get_elements(vars_node_name).count.should == 0 + end + + it 'assigning an EnvironmentVariables object updates the xml' do + env_var = Xcodeproj::XCScheme::EnvironmentVariables.new([{ :key => 'a', :value => '1' }]) + env_var.xml_element.elements.count.should == 1 + + @sut.environment_variables = env_var + @sut.environment_variables.to_a.should == [{ :key => 'a', :value => '1', :enabled => true }] + @sut.environment_variables.xml_element.should == env_var.xml_element + + xml_out = '' + xml_formatter = REXML::Formatters::Pretty.new(0) + xml_formatter.compact = true + xml_formatter.write(@sut.environment_variables.xml_element, xml_out) + xml_out.should == "\n\n" + end + end end describe XCScheme::TestAction::TestableReference do diff --git a/spec/scheme_spec.rb b/spec/scheme_spec.rb index 905c46e46..faa22d033 100644 --- a/spec/scheme_spec.rb +++ b/spec/scheme_spec.rb @@ -55,6 +55,10 @@ module ProjectSpecs ref.target_uuid.should == '632143E8175736EE0038D40D' ref.buildable_name.should == 'SharedSchemes.app' ref.target_referenced_container.should == 'container:SharedSchemes.xcodeproj' + + @scheme.test_action.environment_variables.to_a.should == + [{ :key => 'testkey', :value => 'testval', :enabled => true }, + { :key => 'testkeydisabled', :value => 'testvaldisabled', :enabled => false }] end it 'Properly map the scheme\'s LaunchAction' do @@ -69,6 +73,10 @@ module ProjectSpecs ref.target_uuid.should == '632143E8175736EE0038D40D' ref.buildable_name.should == 'SharedSchemes.app' ref.target_referenced_container.should == 'container:SharedSchemes.xcodeproj' + + @scheme.launch_action.environment_variables.to_a.should == + [{ :key => 'launchkey', :value => 'launchval', :enabled => true }, + { :key => 'launchkeydisabled', :value => 'launchvaldisabled', :enabled => false }] end it 'Properly map the scheme\'s ProfileAction' do