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

Add a warning when doc string is not a string #2922

Merged
merged 3 commits into from
Dec 12, 2021
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
10 changes: 10 additions & 0 deletions lib/rspec/core/example_group.rb
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@ def self.define_example_method(name, extra_options={})
idempotently_define_singleton_method(name) do |*all_args, &block|
desc, *args = *all_args

unless NilClass === desc || String === desc
RSpec.warning "`#{desc.inspect}` is used as example doc string. Use a string instead"
end

options = Metadata.build_hash_from(args)
options.update(:skip => RSpec::Core::Pending::NOT_YET_IMPLEMENTED) unless block
options.update(extra_options)
Expand Down Expand Up @@ -264,6 +268,11 @@ def self.define_example_group_method(name, metadata={})

begin
description = args.shift

unless NilClass === description || String === description || Module === description
RSpec.warning "`#{description.inspect}` is used as example group doc string. Use a string instead"
end

combined_metadata = metadata.dup
combined_metadata.merge!(args.pop) if args.last.is_a? Hash
args << combined_metadata
Expand Down Expand Up @@ -677,6 +686,7 @@ def self.each_instance_variable_for_example(group)
end
end

# @private
def initialize(inspect_output=nil)
@__inspect_output = inspect_output || '(no description provided)'
super() # no args get passed
Expand Down
70 changes: 68 additions & 2 deletions spec/rspec/core/example_group_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ def metadata_hash(*args)
end

it 'does not treat the first argument as a metadata key even if it is a symbol' do
group = RSpec.describe(:symbol)
group = with_an_expected_warning { RSpec.describe(:symbol) }
expect(group.metadata).not_to include(:symbol)
end

it 'treats the first argument as part of the description when it is a symbol' do
group = RSpec.describe(:symbol)
group = with_an_expected_warning { RSpec.describe(:symbol) }
expect(group.description).to eq("symbol")
end

Expand Down Expand Up @@ -1231,6 +1231,72 @@ def extract_execution_results(group)

end

describe "example group doc string" do
it "accepts a string for an example group doc string" do
expect { RSpec.describe 'MyClass' }.not_to output.to_stderr
end

it "accepts a class for an example group doc string" do
expect { RSpec.describe Numeric }.not_to output.to_stderr
end

it "accepts a module for an example group doc string" do
expect { RSpec.describe RSpec }.not_to output.to_stderr
end

it "accepts example group without a doc string" do
expect { RSpec.describe }.not_to output.to_stderr
end

it "emits a warning when a Symbol is used as an example group doc string" do
expect { RSpec.describe :foo }
.to output(/`:foo` is used as example group doc string. Use a string instead/)
.to_stderr
end

it "emits a warning when a Hash is used as an example group doc string" do
expect { RSpec.describe(foo: :bar) { } }
.to output(/`{:foo=>:bar}` is used as example group doc string. Use a string instead/)
.to_stderr
end
end

describe "example doc string" do
let(:group) { RSpec.describe }

it "accepts a string for an example doc string" do
expect { group.it('MyClass') { } }.not_to output.to_stderr
end

it "accepts example without a doc string" do
expect { group.it { } }.not_to output.to_stderr
end

it "emits a warning when a Class is used as an example doc string" do
expect { group.it(Numeric) { } }
.to output(/`Numeric` is used as example doc string. Use a string instead/)
.to_stderr
end

it "emits a warning when a Module is used as an example doc string" do
expect { group.it(RSpec) { } }
.to output(/`RSpec` is used as example doc string. Use a string instead/)
.to_stderr
end

it "emits a warning when a Symbol is used as an example doc string" do
expect { group.it(:foo) { } }
.to output(/`:foo` is used as example doc string. Use a string instead/)
.to_stderr
end

it "emits a warning when a Hash is used as an example doc string" do
expect { group.it(foo: :bar) { } }
.to output(/`{:foo=>:bar}` is used as example doc string. Use a string instead/)
.to_stderr
end
end

describe Object, "describing nested example_groups", :little_less_nested => 'yep' do

describe "A sample nested group", :nested_describe => "yep" do
Expand Down
2 changes: 1 addition & 1 deletion spec/rspec/core/hooks_filtering_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ module RSpec::Core
c.after(:each, :match => false) { filters << "after each in config"}
c.after(:all, :match => false) { filters << "after all in config"}
end
group = RSpec.describe(:match => true)
group = RSpec.describe('example group', :match => true)
group.example("example") {}
group.run
expect(filters).to eq([])
Expand Down
14 changes: 10 additions & 4 deletions spec/rspec/core/memoized_helpers_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module RSpec::Core
before(:each) { RSpec.configuration.configure_expectation_framework }

def subject_value_for(describe_arg, &block)
example_group = RSpec.describe(describe_arg, &block)
example_group = with_an_expected_warning { RSpec.describe(describe_arg, &block) }
subject_value = nil
example_group.example { subject_value = subject }
example_group.run
Expand Down Expand Up @@ -340,10 +340,16 @@ def not_ok?; false; end
end

it 'supports a new expect-based syntax' do
group = RSpec.describe([1, 2, 3]) do
it { is_expected.to be_an Array }
it { is_expected.not_to include 4 }
math_class = Class.new do
def easy?
false
end
end
group =
RSpec.describe(math_class) do
it { is_expected.to be_a math_class }
it { is_expected.to_not be_easy }
end

expect(group.run).to be true
end
Expand Down
10 changes: 5 additions & 5 deletions spec/rspec/core/metadata_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -381,24 +381,24 @@ def metadata_for(*args)

context "with a String" do
it "returns nil" do
expect(value_for "group").to be_nil
expect(value_for("group")).to be_nil
end
end

context "with a Symbol" do
it "returns the symbol" do
expect(value_for :group).to be(:group)
expect(with_an_expected_warning { value_for(:group) }).to be(:group)
end
end

context "with a class" do
it "returns the class" do
expect(value_for String).to be(String)
expect(value_for(String)).to be(String)
end

context "when the class is Regexp" do
it "returns the class" do
expect(value_for Regexp).to be(Regexp)
expect(value_for(Regexp)).to be(Regexp)
end
end
end
Expand Down Expand Up @@ -636,7 +636,7 @@ def group_value_for(*args)
it "finds the first non-rspec lib file in the caller array" do
value = nil

RSpec.describe(:caller => ["./lib/rspec/core/foo.rb", "#{__FILE__}:#{__LINE__}"]) do
RSpec.describe('example group', :caller => ["./lib/rspec/core/foo.rb", "#{__FILE__}:#{__LINE__}"]) do
value = metadata[:file_path]
end

Expand Down
4 changes: 4 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ def handle_current_dir_change
ensure
RSpec::Core::Metadata.instance_variable_set(:@relative_path_regex, nil)
end

def with_an_expected_warning
with_isolated_stderr { yield }
end
Comment on lines +66 to +68
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you feel about making this expect an error, e.g. at minimum

Suggested change
def with_an_expected_warning
with_isolated_stderr { yield }
end
def with_an_expected_warning(warning = //)
expect { yield }.to output(warning).to_stderr
end

This would be an actually expected warning then, optionally we could assert on the specifics?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't work as is, had to rework as

return_value = nil
expect { return_value = yield }.to output(warning).to_stderr
return_value

and it complicates subject_value_for in memoized_helpers_spec.rb, as some usages do output and some don't.
The potential to catch unexpected warnings may not overweight the added complexity.

end

RSpec.configure do |c|
Expand Down