Skip to content
This repository was archived by the owner on Nov 30, 2024. It is now read-only.

Load spec files in the order that files and dirs were specified in the CLI. #2253

Merged
merged 1 commit into from
Jun 1, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ Enhancements:
by using `bundle exec`. (Myron Marston, #2240)
* HTML Formatter uses exception presenter to get failure message
for consistency with other formatters. (@mrageh, #2222)
* Load spec files in the order of the directories or files passed
at the command line, making it easy to make some specs run before
others in a one-off manner. For example, `rspec spec/unit
spec/acceptance --order defined` will run unit specs before acceptance
specs. (Myron Marston, #2253)

Bug Fixes:

Expand Down
9 changes: 5 additions & 4 deletions lib/rspec/core/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1782,7 +1782,7 @@ def get_files_to_run(paths)
files = FlatMap.flat_map(paths_to_check(paths)) do |path|
path = path.gsub(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
File.directory?(path) ? gather_directories(path) : extract_location(path)
end.sort.uniq
end.uniq

return files unless only_failures?
relative_files = files.map { |f| Metadata.relative_path(File.expand_path f) }
Expand All @@ -1802,11 +1802,12 @@ def pattern_might_load_specs_from_vendored_dirs?
def gather_directories(path)
include_files = get_matching_files(path, pattern)
exclude_files = get_matching_files(path, exclude_pattern)
(include_files - exclude_files).sort.uniq
(include_files - exclude_files).uniq
end

def get_matching_files(path, pattern)
Dir[file_glob_from(path, pattern)].map { |file| File.expand_path(file) }
raw_files = Dir[file_glob_from(path, pattern)]
raw_files.map { |file| File.expand_path(file) }.sort
end

def file_glob_from(path, pattern)
Expand Down Expand Up @@ -1846,7 +1847,7 @@ def extract_location(path)
end

return [] if path == default_path
path
File.expand_path(path)
end

def command
Expand Down
101 changes: 57 additions & 44 deletions spec/rspec/core/configuration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ def stub_expectation_adapters

it 'attempts to load the provided file names' do
assign_files_or_directories_to_run "path/to/some/file.rb"
expect(config.files_to_run).to eq(["path/to/some/file.rb"])
expect(config.files_to_run).to contain_files("path/to/some/file.rb")
end

it 'does not attempt to load a file at the `default_path`' do
Expand Down Expand Up @@ -554,58 +554,71 @@ def loaded_files
end
end

def specify_consistent_ordering_of_files_to_run
allow(File).to receive(:directory?).and_call_original
allow(File).to receive(:directory?).with('a') { true }
globbed_files = nil
allow(Dir).to receive(:[]).with(/^\{?a/) { globbed_files }
allow(Dir).to receive(:[]).with(a_string_starting_with(Dir.getwd)) { [] }

orderings = [
%w[ a/1.rb a/2.rb a/3.rb ],
%w[ a/2.rb a/1.rb a/3.rb ],
%w[ a/3.rb a/2.rb a/1.rb ]
].map do |files|
globbed_files = files
yield
config.files_to_run
end
it 'loads files in passed directories in alphabetical order to avoid OS-specific file-globbing non-determinism' do
define_dirs "spec/unit" => [
["spec/unit/b_spec.rb", "spec/unit/a_spec.rb"],
["spec/unit/a_spec.rb", "spec/unit/b_spec.rb"]
]

expect(orderings.uniq.size).to eq(1)
expect(assign_files_or_directories_to_run "spec/unit").to match [
file_at("spec/unit/a_spec.rb"),
file_at("spec/unit/b_spec.rb")
]
expect(assign_files_or_directories_to_run "spec/unit").to match [
file_at("spec/unit/a_spec.rb"),
file_at("spec/unit/b_spec.rb")
]
end

context 'when the given directories match the pattern' do
it 'orders the files in a consistent ordering, regardless of the underlying OS ordering' do
specify_consistent_ordering_of_files_to_run do
config.pattern = 'a/*.rb'
assign_files_or_directories_to_run 'a'
end
end
end
it 'respects the user-specified order of files and directories passed at the command line' do
define_dirs "spec/b" => [["spec/b/1_spec.rb", "spec/b/2_spec.rb"]],
"spec/c" => [["spec/c/1_spec.rb", "spec/c/2_spec.rb"]]

context 'when the pattern is given relative to the given directories' do
it 'orders the files in a consistent ordering, regardless of the underlying OS ordering' do
specify_consistent_ordering_of_files_to_run do
config.pattern = '*.rb'
assign_files_or_directories_to_run 'a'
end
end
expect(assign_files_or_directories_to_run "spec/b", "spec/a1_spec.rb", "spec/c", "spec/a2_spec.rb").to match [
file_at("spec/b/1_spec.rb"), file_at("spec/b/2_spec.rb"),
file_at("spec/a1_spec.rb"),
file_at("spec/c/1_spec.rb"), file_at("spec/c/2_spec.rb"),
file_at("spec/a2_spec.rb")
]
end

context 'when given multiple file paths' do
it 'orders the files in a consistent ordering, regardless of the given order' do
allow(File).to receive(:directory?) { false } # fake it into thinking these a full file paths
it 'deduplicates spec files that are listed individually and present in a passed dir' do
define_dirs "spec/unit" => [[
"spec/unit/a_spec.rb",
"spec/unit/b_spec.rb",
"spec/unit/c_spec.rb"
]]

expect(assign_files_or_directories_to_run "spec/unit/b_spec.rb", "spec/unit").to match [
file_at("spec/unit/b_spec.rb"),
file_at("spec/unit/a_spec.rb"),
file_at("spec/unit/c_spec.rb")
]

expect(assign_files_or_directories_to_run "spec/unit", "spec/unit/b_spec.rb").to match [
file_at("spec/unit/a_spec.rb"),
file_at("spec/unit/b_spec.rb"),
file_at("spec/unit/c_spec.rb")
]
end

files = ['a/b/c_spec.rb', 'c/b/a_spec.rb']
assign_files_or_directories_to_run(*files)
ordering_1 = config.files_to_run
def define_dirs(dirs_hash)
allow(File).to receive(:directory?) do |path|
!path.end_with?(".rb")
end

assign_files_or_directories_to_run(*files.reverse)
ordering_2 = config.files_to_run
allow(Dir).to receive(:[]).and_return([])

expect(ordering_1).to eq(ordering_2)
dirs_hash.each do |dir, sequential_glob_return_values|
allow(Dir).to receive(:[]).with(
a_string_including(dir, config.pattern)
).and_return(*sequential_glob_return_values)
end
end

def file_at(relative_path)
eq(relative_path).or eq(File.expand_path(relative_path))
end
end

describe "#pattern" do
Expand Down Expand Up @@ -819,10 +832,10 @@ def specify_consistent_ordering_of_files_to_run

it "allows file names with brackets" do
assign_files_or_directories_to_run "./path/to/a_[1:2]spec.rb"
expect(config.files_to_run).to eq(["./path/to/a_[1:2]spec.rb"])
expect(config.files_to_run).to contain_files("./path/to/a_[1:2]spec.rb")

assign_files_or_directories_to_run "./path/to/a_spec.rb[foo]"
expect(config.files_to_run).to eq(["./path/to/a_spec.rb[foo]"])
expect(config.files_to_run).to contain_files("./path/to/a_spec.rb[foo]")
end

context "with an example id" do
Expand Down
4 changes: 2 additions & 2 deletions spec/rspec/core/rake_task_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def specify_consistent_ordering_of_files_to_run(pattern, file_searcher)
context "with SPEC env var set" do
it "sets files to run" do
with_env_vars 'SPEC' => 'path/to/file' do
expect(loaded_files).to eq(["path/to/file"])
expect(loaded_files).to contain_files("path/to/file")
end
end

Expand Down Expand Up @@ -346,7 +346,7 @@ def self.it_configures_rspec_load_path(description, path_template)
it "loads the files from the FileList" do
task.pattern = FileList["spec/rspec/core/resources/**/*_spec.rb"]

expect(loaded_files).to contain_exactly(
expect(loaded_files).to contain_files(
"spec/rspec/core/resources/a_spec.rb",
"spec/rspec/core/resources/acceptance/foo_spec.rb"
)
Expand Down