spec/contracts_spec.rb in contracts-0.5 vs spec/contracts_spec.rb in contracts-0.6
- old
+ new
@@ -1,10 +1,8 @@
-include Contracts
-
RSpec.describe "Contracts:" do
before :all do
- @o = Object.new
+ @o = GenericExample.new
end
describe "basic" do
it "should fail for insufficient arguments" do
expect {
@@ -71,10 +69,163 @@
}.to raise_error(RuntimeError, /contract violation/)
end
end
end
+ describe "usage in singleton class" do
+ it "should work normally when there is no contract violation" do
+ expect(SingletonClassExample.hoge("hoge")).to eq("superhoge")
+ end
+
+ it "should fail with proper error when there is contract violation" do
+ expect {
+ SingletonClassExample.hoge(3)
+ }.to raise_error(ContractError, /Expected: String/)
+ end
+
+ context "when owner class does not include Contracts" do
+ let(:error) {
+ # NOTE Unable to support this user-friendly error for ruby
+ # 1.8.7 and jruby 1.8, 1.9 it has much less support for
+ # singleton inheritance hierarchy
+ if Contracts::Support.eigenclass_hierarchy_supported?
+ [Contracts::ContractsNotIncluded, Contracts::ContractsNotIncluded::DEFAULT_MESSAGE]
+ else
+ [NoMethodError, /undefined method `Contract'/]
+ end
+ }
+
+ it "fails with descriptive error" do
+ expect {
+ Class.new(GenericExample) do
+ class << self
+ Contract String => String
+ def hoge(name)
+ "super#{name}"
+ end
+ end
+ end
+ }.to raise_error(*error)
+ end
+ end
+ end
+
+ describe "no contracts feature" do
+ it "disables normal contract checks" do
+ object = NoContractsSimpleExample.new
+ expect { object.some_method(3) }.not_to raise_error
+ end
+
+ it "disables invariants" do
+ object = NoContractsInvariantsExample.new
+ object.day = 7
+ expect { object.next_day }.not_to raise_error
+ end
+
+ it "does not disable pattern matching" do
+ object = NoContractsPatternMatchingExample.new
+
+ expect(object.on_response(200, "hello")).to eq("hello!")
+ expect(object.on_response(404, "Not found")).to eq("error 404: Not found")
+ expect { object.on_response(nil, "junk response") }.to raise_error(ContractError)
+ end
+ end
+
+ describe "module usage" do
+ context "with instance methods" do
+ it "should check contract" do
+ expect { KlassWithModuleExample.new.plus(3, nil) }.to raise_error(ContractError)
+ end
+ end
+
+ context "with singleton methods" do
+ it "should check contract" do
+ expect { ModuleExample.hoge(nil) }.to raise_error(ContractError)
+ end
+ end
+
+ context "with singleton class methods" do
+ it "should check contract" do
+ expect { ModuleExample.eat(:food) }.to raise_error(ContractError)
+ end
+ end
+ end
+
+ describe "singleton methods self in inherited methods" do
+ it "should be a proper self" do
+ expect(SingletonInheritanceExampleSubclass.a_contracted_self).to eq(SingletonInheritanceExampleSubclass)
+ end
+ end
+
+ describe "anonymous classes" do
+ let(:klass) do
+ Class.new do
+ include Contracts
+
+ Contract String => String
+ def greeting(name)
+ "hello, #{name}"
+ end
+ end
+ end
+
+ let(:obj) { klass.new }
+
+ it "does not fail when contract is satisfied" do
+ expect(obj.greeting("world")).to eq("hello, world")
+ end
+
+ it "fails with error when contract is violated" do
+ expect { obj.greeting(3) }.to raise_error(ContractError, /Actual: 3/)
+ end
+ end
+
+ describe "anonymous modules" do
+ let(:mod) do
+ Module.new do
+ include Contracts
+ include Contracts::Modules
+
+ Contract String => String
+ def greeting(name)
+ "hello, #{name}"
+ end
+
+ Contract String => String
+ def self.greeting(name)
+ "hello, #{name}"
+ end
+ end
+ end
+
+ let(:klass) do
+ Class.new.tap { |klass| klass.send(:include, mod) }
+ end
+
+ let(:obj) { klass.new }
+
+ it "does not fail when contract is satisfied" do
+ expect(obj.greeting("world")).to eq("hello, world")
+ end
+
+ it "fails with error when contract is violated" do
+ expect { obj.greeting(3) }.to raise_error(ContractError, /Actual: 3/)
+ end
+
+ context "when called on module itself" do
+ let(:obj) { mod }
+
+ it "does not fail when contract is satisfied" do
+ expect(obj.greeting("world")).to eq("hello, world")
+ end
+
+ it "fails with error when contract is violated" do
+ expect { obj.greeting(3) }.to raise_error(ContractError, /Actual: 3/)
+ end
+ end
+ end
+
describe "instance methods" do
it "should allow two classes to have the same method with different contracts" do
a = A.new
b = B.new
expect {
@@ -94,15 +245,15 @@
end
end
describe "class methods" do
it "should pass for correct input" do
- expect { Object.a_class_method(2) }.to_not raise_error
+ expect { GenericExample.a_class_method(2) }.to_not raise_error
end
it "should fail for incorrect input" do
- expect { Object.a_class_method("bad") }.to raise_error(ContractError)
+ expect { GenericExample.a_class_method("bad") }.to raise_error(ContractError)
end
end
it "should work for functions with no args" do
expect { @o.no_args }.to_not raise_error
@@ -178,18 +329,55 @@
end
it "should fail for incorrect input" do
expect { @o.do_call(nil) }.to raise_error(ContractError)
end
+
+ it "should handle properly lack of block when there are other arguments" do
+ expect { @o.double_with_proc(4) }.to raise_error(ContractError, /Actual: nil/)
+ end
end
describe "varargs" do
it "should pass for correct input" do
expect { @o.sum(1, 2, 3) }.to_not raise_error
end
it "should fail for incorrect input" do
expect { @o.sum(1, 2, "bad") }.to raise_error(ContractError)
+ end
+ end
+
+ describe "varargs with block" do
+ it "should pass for correct input" do
+ expect { @o.with_partial_sums(1, 2, 3) { |partial_sum| 2 * partial_sum + 1 } }.not_to raise_error
+ expect { @o.with_partial_sums_contracted(1, 2, 3) { |partial_sum| 2 * partial_sum + 1 } }.not_to raise_error
+ end
+
+ it "should fail for incorrect input" do
+ expect {
+ @o.with_partial_sums(1, 2, "bad") { |partial_sum| 2 * partial_sum + 1 }
+ }.to raise_error(ContractError, /Actual: "bad"/)
+
+ expect {
+ @o.with_partial_sums(1, 2, 3)
+ }.to raise_error(ContractError, /Actual: nil/)
+
+ expect {
+ @o.with_partial_sums(1, 2, 3, lambda { |x| x })
+ }.to raise_error(ContractError, /Actual: #<Proc/)
+ end
+
+ context "when block has Func contract" do
+ it "should fail for incorrect input" do
+ expect {
+ @o.with_partial_sums_contracted(1, 2, "bad") { |partial_sum| 2 * partial_sum + 1 }
+ }.to raise_error(ContractError, /Actual: "bad"/)
+
+ expect {
+ @o.with_partial_sums_contracted(1, 2, 3)
+ }.to raise_error(ContractError, /Actual: nil/)
+ end
end
end
describe "contracts on functions" do
it "should pass for a function that passes the contract" do