Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: c6f24d281661
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 27270e3337ae
Choose a head ref
  • 2 commits
  • 5 files changed
  • 1 contributor

Commits on Aug 8, 2016

  1. Squashed 'spec/mspec/' changes from 55caa7c..88e734a

    88e734a New feature: automatic alias detection for shared describes
    3e4abb8 Replace tabs by spaces
    
    git-subtree-dir: spec/mspec
    git-subtree-split: 88e734a06d5810d22c6c828ec1571a32f4e0cb45
    eregon committed Aug 8, 2016
    Copy the full SHA
    cf29ea9 View commit details
  2. Copy the full SHA
    27270e3 View commit details
73 changes: 72 additions & 1 deletion spec/mspec/lib/mspec/runner/context.rb
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@
#++
class ContextState
attr_reader :state, :parent, :parents, :children, :examples, :to_s
attr_accessor :shared_method

def initialize(mod, options=nil)
@to_s = mod.to_s
@@ -31,6 +32,7 @@ def initialize(mod, options=nil)
@parent = nil
@parents = [self]
@children = []
@shared_method = nil

@mock_verify = Proc.new { Mock.verify_count }
@mock_cleanup = Proc.new { Mock.cleanup }
@@ -147,13 +149,26 @@ def description

# Injects the before/after blocks and examples from the shared
# describe block into this +ContextState+ instance.
def it_should_behave_like(desc)
def it_should_behave_like(desc, meth = nil, obj = nil)
return if MSpec.guarded?

unless state = MSpec.retrieve_shared(desc)
raise Exception, "Unable to find shared 'describe' for #{desc}"
end

if Symbol === meth and m = find_method(obj, meth)
if shared_method = state.shared_method
if same_implementation?(m, shared_method)
it "behaves the same as #{method_to_s(shared_method)} since it is an alias" do
true.should == true
end
return
end
else
state.shared_method = m
end
end

state.before(:all).each { |b| before :all, &b }
state.before(:each).each { |b| before :each, &b }
state.after(:each).each { |b| after :each, &b }
@@ -170,6 +185,62 @@ def it_should_behave_like(desc)
end
end

def find_method(obj, name)
if obj.respond_to?(name)
obj.method(name)
else
if mod = @to_s[/^([A-Z]\w+)\./, 1] and Object.const_defined?(mod)
mod = Object.const_get(mod)
if Module === mod and mod.respond_to?(name)
mod.method(name)
end
elsif mod = @to_s[/^([A-Z]\w+)#/, 1] and Object.const_defined?(mod)
mod = Object.const_get(mod)
if Module === mod and mod.method_defined?(name)
mod.instance_method(name)
end
end
end
end

def method_to_s(meth)
if Method === meth and Module === meth.receiver
"#{meth.receiver}.#{meth.name}"
else
"#{meth.owner}##{meth.name}"
end
end
private :method_to_s

def same_implementation?(meth1, meth2)
return true if meth1 == meth2

file1, line1 = meth1.source_location
file2, line2 = meth2.source_location

# No source_location available
return false if !file1 && !file2

# Assume the same if they are defined on the same line
return true if file1 == file2 and line1 == line2

calls_other = -> meth, file, line, other {
if file and File.readable?(file)
lines = File.readlines(file)
method_def, call, method_end = lines[line-1..line+1].map(&:strip)
if method_def == "def #{meth.name}(*args)" and method_end == "end"
if Method === other and Module === other.receiver
call == "#{other.receiver}.#{other.name}(*args)"
else
meth.owner == other.owner and call == "#{other.name}(*args)"
end
end
end
}

calls_other.call(meth1, file1, line1, meth2) or calls_other.call(meth2, file2, line2, meth1)
end

# Evaluates each block in +blocks+ using the +MSpec.protect+ method
# so that exceptions are handled and tallied. Returns true and does
# NOT evaluate any blocks if +check+ is true and
4 changes: 2 additions & 2 deletions spec/mspec/lib/mspec/runner/object.rb
Original file line number Diff line number Diff line change
@@ -15,8 +15,8 @@ def it(msg, &block)
MSpec.current.it msg, &block
end

def it_should_behave_like(desc)
MSpec.current.it_should_behave_like desc
def it_should_behave_like(*args)
MSpec.current.it_should_behave_like(*args)
end

# For ReadRuby compatiability
2 changes: 1 addition & 1 deletion spec/mspec/lib/mspec/runner/shared.rb
Original file line number Diff line number Diff line change
@@ -7,6 +7,6 @@ def it_behaves_like(desc, meth, obj=nil)
@object = obj
end

send :it_should_behave_like, desc.to_s
send :it_should_behave_like, desc.to_s, meth, obj
end
end
75 changes: 75 additions & 0 deletions spec/mspec/spec/runner/context_spec.rb
Original file line number Diff line number Diff line change
@@ -1039,3 +1039,78 @@ def example.example(state, spec)
@state.filter_examples.should be_false
end
end

describe ContextState, "#find_method" do
it "returns the method based on passed obj and name" do
state = ContextState.new ""
state.find_method(3, :+).should == 3.method(:+)
end

it "returns the method based on description" do
state = ContextState.new "Kernel.puts"
state.find_method(nil, :puts).should == Kernel.method(:puts)
end

it "returns the instance method based on description" do
state = ContextState.new "Enumerable#flat_map"
state.find_method(nil, :flat_map).should == Enumerable.instance_method(:flat_map)
end
end

class SameImplementation
def my_puts(*args)
Kernel.puts(*args)
end

def foo(*args)
bar(*args)
end

def bar
end
end

describe ContextState, "#same_implementation?" do
before :each do
@state = ContextState.new ""
end

it "returns true for the same method" do
@state.should be_same_implementation(3.method(:+), 3.method(:+))
end

it "returns true for aliases" do
@state.should be_same_implementation(
Enumerable.instance_method(:flat_map),
Enumerable.instance_method(:collect_concat))
end

it "returns false for different methods" do
@state.should_not be_same_implementation(3.method(:+), Kernel.method(:puts))
@state.should_not be_same_implementation(3.method(:+), Kernel.instance_method(:puts))
@state.should_not be_same_implementation(Kernel.instance_method(:puts), 3.method(:+))
@state.should_not be_same_implementation(Kernel.instance_method(:puts), Fixnum.instance_method(:+))
end

it "returns true for delegating methods when the source can be read" do
@state.should be_same_implementation(
SameImplementation.instance_method(:my_puts),
Kernel.method(:puts))

@state.should be_same_implementation(
SameImplementation.new.method(:my_puts),
Kernel.method(:puts))

@state.should be_same_implementation(
SameImplementation.new.method(:foo),
SameImplementation.new.method(:bar))

@state.should be_same_implementation(
SameImplementation.instance_method(:foo),
SameImplementation.instance_method(:bar))

@state.should be_same_implementation(
SameImplementation.new.method(:foo),
SameImplementation.instance_method(:bar))
end
end
12 changes: 6 additions & 6 deletions spec/mspec/spec/utils/deprecate_spec.rb
Original file line number Diff line number Diff line change
@@ -3,15 +3,15 @@

describe MSpec, "#deprecate" do
it "warns when using a deprecated method" do
warning = nil
$stderr.stub(:puts) { |str| warning = str }
MSpec.deprecate(:some_method, :other_method)
warning.should start_with(<<-EOS.chomp)
warning = nil
$stderr.stub(:puts) { |str| warning = str }
MSpec.deprecate(:some_method, :other_method)
warning.should start_with(<<-EOS.chomp)
some_method is deprecated, use other_method instead.
from
EOS
warning.should include(__FILE__)
warning.should include('8')
warning.should include(__FILE__)
warning.should include('8')
end
end