diff --git a/Changelog.md b/Changelog.md index 028c246975..2e26b72581 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,13 @@ +### 3.2.2 / 2015-03-11 +[Full Changelog](http://github.com/rspec/rspec-core/compare/v3.2.1...v3.2.2) + +Bug Fixes: + +* Fix regression in 3.2.0 that allowed tag-filtered examples to + run even if there was a location filter applied to the spec + file that was intended to limit the file to other examples. + (#1894, Myron Marston) + ### 3.2.1 / 2015-02-23 [Full Changelog](http://github.com/rspec/rspec-core/compare/v3.2.0...v3.2.1) diff --git a/lib/rspec/core/filter_manager.rb b/lib/rspec/core/filter_manager.rb index b3e3217e20..1926e725f5 100644 --- a/lib/rspec/core/filter_manager.rb +++ b/lib/rspec/core/filter_manager.rb @@ -31,8 +31,13 @@ def prune(examples) if inclusions.standalone? examples.select { |e| include?(e) } else - locations = inclusions.fetch(:locations) { Hash.new([]) } - examples.select { |e| priority_include?(e, locations) || (!exclude?(e) && include?(e)) } + locations, other_inclusions = inclusions.partition_locations + + examples.select do |e| + priority_include?(e, locations) do + !exclude?(e) && other_inclusions.include_example?(e) + end + end end end @@ -83,7 +88,7 @@ def prune_conditionally_filtered_examples(examples) # defined in the same file as the location filters. Excluded specs in # other files should still be excluded. def priority_include?(example, locations) - return false if locations[example.metadata[:absolute_file_path]].empty? + return yield if locations[example.metadata[:absolute_file_path]].empty? MetadataFilter.filter_applies?(:locations, locations, example.metadata) end end @@ -104,8 +109,8 @@ def self.build [exclusions, inclusions] end - def initialize(*args, &block) - @rules = Hash.new(*args, &block) + def initialize(rules={}) + @rules = rules end def add(updated) @@ -173,6 +178,13 @@ def use(*args) apply_standalone_filter(*args) || super end + def partition_locations + locations = @rules.fetch(:locations) { Hash.new([]) } + other_inclusions = self.class.new(@rules.dup.tap { |r| r.delete(:locations) }) + + return locations, other_inclusions + end + def include_example?(example) @rules.empty? || super end diff --git a/lib/rspec/core/version.rb b/lib/rspec/core/version.rb index 825edcffbc..095c8588ab 100644 --- a/lib/rspec/core/version.rb +++ b/lib/rspec/core/version.rb @@ -3,7 +3,7 @@ module Core # Version information for RSpec Core. module Version # Current version of RSpec Core, in semantic versioning format. - STRING = '3.2.1' + STRING = '3.2.2' end end end diff --git a/spec/integration/filtering_spec.rb b/spec/integration/filtering_spec.rb index 46feb427a7..800ff90c7c 100644 --- a/spec/integration/filtering_spec.rb +++ b/spec/integration/filtering_spec.rb @@ -122,5 +122,27 @@ def run_rerun_command_for_failing_spec expect(last_cmd_stdout).to match(/3 examples, 0 failures/) expect(last_cmd_stdout).not_to match(/fails/) end + + it 'applies command line tag filters only to files that lack a line number filter' do + write_file_formatted "spec/file_1_spec.rb", """ + RSpec.describe 'File 1' do + it('is selected by line') { } + it('is not selected', :tag) { } + end + """ + + write_file_formatted "spec/file_2_spec.rb", """ + RSpec.describe 'File 2' do + it('is not selected') { } + it('is selected by tag', :tag) { } + end + """ + + run_command "spec/file_1_spec.rb:2 spec/file_2_spec.rb --tag tag -fd" + expect(last_cmd_stdout).to include( + "2 examples, 0 failures", + "is selected by line", "is selected by tag" + ).and exclude("not selected") + end end end diff --git a/spec/rspec/core/filter_manager_spec.rb b/spec/rspec/core/filter_manager_spec.rb index 676a6ba3f4..7482246266 100644 --- a/spec/rspec/core/filter_manager_spec.rb +++ b/spec/rspec/core/filter_manager_spec.rb @@ -114,6 +114,25 @@ def example_with(*args) expect(filter_manager.prune([included, excluded])).to eq([included]) end + it "still applies inclusion filters to examples from files with no location filters" do + group = RSpec.describe("group") + included_via_location = group.example("inc via location"); line = __LINE__ + excluded_via_location = group.example("exc via location", :foo) + + included_via_tag, excluded_via_tag = instance_eval <<-EOS, "some/other_spec.rb", 1 + group = RSpec.describe("group") + [group.example("inc via tag", :foo), group.example("exc via tag")] + EOS + + filter_manager.add_location(__FILE__, [line]) + filter_manager.include_with_low_priority :foo => true + + expect(filter_manager.prune([ + included_via_location, excluded_via_location, + included_via_tag, excluded_via_tag + ]).map(&:description)).to eq([included_via_location, included_via_tag].map(&:description)) + end + it "prefers location to exclusion filter on entire group" do # We way want to change this behaviour in future, see: # https://github.com/rspec/rspec-core/issues/779 diff --git a/spec/support/aruba_support.rb b/spec/support/aruba_support.rb index 662ddbb97d..333b4a2adb 100644 --- a/spec/support/aruba_support.rb +++ b/spec/support/aruba_support.rb @@ -13,6 +13,8 @@ module ArubaLoader attr_reader :last_cmd_stdout, :last_cmd_stderr def run_command(cmd) + RSpec.configuration.color = true + temp_stdout = StringIO.new temp_stderr = StringIO.new RSpec::Core::Metadata.instance_variable_set(:@relative_path_regex, nil) @@ -22,6 +24,7 @@ def run_command(cmd) end ensure RSpec.reset + RSpec.configuration.color = true RSpec::Core::Metadata.instance_variable_set(:@relative_path_regex, nil) # Ensure it gets cached with a proper value -- if we leave it set to nil,