spec/contracts_spec.rb in contracts-0.7 vs spec/contracts_spec.rb in contracts-0.8
- old
+ new
@@ -3,13 +3,13 @@
@o = GenericExample.new
end
describe "basic" do
it "should fail for insufficient arguments" do
- expect {
+ expect do
@o.hello
- }.to raise_error
+ end.to raise_error
end
it "should fail for insufficient contracts" do
expect { @o.bad_double(2) }.to raise_error(ContractError)
end
@@ -21,100 +21,110 @@
let(:expected_decorated_string) { "Hello, world!" }
subject { PatternMatchingExample.new }
it "should work as expected when there is no contract violation" do
expect(
- subject.process_request(PatternMatchingExample::Success[string_with_hello])
- ).to eq(PatternMatchingExample::Success[expected_decorated_string])
+ subject.process_request(PatternMatchingExample::Success.new(string_with_hello))
+ ).to eq(PatternMatchingExample::Success.new(expected_decorated_string))
expect(
subject.process_request(PatternMatchingExample::Failure.new)
).to be_a(PatternMatchingExample::Failure)
end
it "should not fall through to next pattern when there is a deep contract violation" do
expect(PatternMatchingExample::Failure).not_to receive(:is_a?)
- expect {
- subject.process_request(PatternMatchingExample::Success[string_without_hello])
- }.to raise_error(ContractError)
+ expect do
+ subject.process_request(PatternMatchingExample::Success.new(string_without_hello))
+ end.to raise_error(ContractError)
end
it "should fail when the pattern-matched method's contract fails" do
- expect {
+ expect do
subject.process_request("bad input")
- }.to raise_error(ContractError)
+ end.to raise_error(ContractError)
end
+ it "should work for differing arities" do
+ expect(
+ subject.do_stuff(1, "abc", 2)
+ ).to eq("bar")
+
+ expect(
+ subject.do_stuff(3, "def")
+ ).to eq("foo")
+ end
+
context "when failure_callback was overriden" do
before do
::Contract.override_failure_callback do |_data|
- raise RuntimeError, "contract violation"
+ fail "contract violation"
end
end
it "calls a method when first pattern matches" do
expect(
- subject.process_request(PatternMatchingExample::Success[string_with_hello])
- ).to eq(PatternMatchingExample::Success[expected_decorated_string])
+ subject.process_request(PatternMatchingExample::Success.new(string_with_hello))
+ ).to eq(PatternMatchingExample::Success.new(expected_decorated_string))
end
it "falls through to 2nd pattern when first pattern does not match" do
expect(
subject.process_request(PatternMatchingExample::Failure.new)
).to be_a(PatternMatchingExample::Failure)
end
it "uses overriden failure_callback when pattern matching fails" do
- expect {
+ expect do
subject.process_request("hello")
- }.to raise_error(RuntimeError, /contract violation/)
+ end.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 {
+ expect do
SingletonClassExample.hoge(3)
- }.to raise_error(ContractError, /Expected: String/)
+ end.to raise_error(ContractError, /Expected: String/)
end
context "when owner class does not include Contracts" do
- let(:error) {
+ let(:error) do
# 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
- }
+ end
it "fails with descriptive error" do
- expect {
+ expect do
Class.new(GenericExample) do
class << self
Contract String => String
def hoge(name)
"super#{name}"
end
end
end
- }.to raise_error(*error)
+ end.to raise_error(*error)
end
end
describe "builtin contracts usage" do
it "allows to use builtin contracts without namespacing and redundant Contracts inclusion" do
- expect {
+ expect do
SingletonClassExample.add("55", 5.6)
- }.to raise_error(ContractError, /Expected: Contracts::Num/)
+ end.to raise_error(ContractError, /Expected: Num/)
end
end
end
describe "no contracts feature" do
@@ -234,24 +244,24 @@
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 {
+ expect do
a.triple(5)
b.triple("a string")
- }.to_not raise_error
+ end.to_not raise_error
end
end
describe "instance and class methods" do
it "should allow a class to have an instance method and a class method with the same name" do
a = A.new
- expect {
+ expect do
a.instance_and_class_method(5)
A.instance_and_class_method("a string")
- }.to_not raise_error
+ end.to_not raise_error
end
end
describe "class methods" do
it "should pass for correct input" do
@@ -311,93 +321,131 @@
end
end
describe "Hashes" do
it "should pass for exact correct input" do
- expect { @o.person({:name => "calvin", :age => 10}) }.to_not raise_error
+ expect { @o.person(:name => "calvin", :age => 10) }.to_not raise_error
end
it "should pass even if some keys don't have contracts" do
- expect { @o.person({:name => "calvin", :age => 10, :foo => "bar"}) }.to_not raise_error
+ expect { @o.person(:name => "calvin", :age => 10, :foo => "bar") }.to_not raise_error
end
it "should fail if a key with a contract on it isn't provided" do
- expect { @o.person({:name => "calvin"}) }.to raise_error(ContractError)
+ expect { @o.person(:name => "calvin") }.to raise_error(ContractError)
end
it "should fail for incorrect input" do
- expect { @o.person({:name => 50, :age => 10}) }.to raise_error(ContractError)
+ expect { @o.person(:name => 50, :age => 10) }.to raise_error(ContractError)
end
end
describe "blocks" do
it "should pass for correct input" do
- expect { @o.do_call {
- 2 + 2
- }}.to_not raise_error
+ expect do
+ @o.do_call do
+ 2 + 2
+ end
+ end.to_not raise_error
end
it "should fail for incorrect input" do
- expect { @o.do_call(nil) }.to raise_error(ContractError)
+ expect do
+ @o.do_call(nil)
+ end.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/)
+ expect do
+ @o.double_with_proc(4)
+ end.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
+ expect do
+ @o.sum(1, 2, 3)
+ end.to_not raise_error
end
it "should fail for incorrect input" do
- expect { @o.sum(1, 2, "bad") }.to raise_error(ContractError)
+ expect do
+ @o.sum(1, 2, "bad")
+ end.to raise_error(ContractError)
end
+
+ it "should work with arg before splat" do
+ expect do
+ @o.arg_then_splat(3, "hello", "world")
+ end.to_not raise_error
+ 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
+ expect do
+ @o.with_partial_sums(1, 2, 3) do |partial_sum|
+ 2 * partial_sum + 1
+ end
+ end.not_to raise_error
+ expect do
+ @o.with_partial_sums_contracted(1, 2, 3) do |partial_sum|
+ 2 * partial_sum + 1
+ end
+ end.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 do
+ @o.with_partial_sums(1, 2, "bad") do |partial_sum|
+ 2 * partial_sum + 1
+ end
+ end.to raise_error(ContractError, /Actual: "bad"/)
- expect {
+ expect do
@o.with_partial_sums(1, 2, 3)
- }.to raise_error(ContractError, /Actual: nil/)
+ end.to raise_error(ContractError, /Actual: nil/)
- expect {
+ expect do
@o.with_partial_sums(1, 2, 3, lambda { |x| x })
- }.to raise_error(ContractError, /Actual: #<Proc/)
+ end.to raise_error(ContractError, /Actual: nil/)
end
context "when block has Func contract" do
it "should fail for incorrect input" do
- expect {
+ expect do
@o.with_partial_sums_contracted(1, 2, "bad") { |partial_sum| 2 * partial_sum + 1 }
- }.to raise_error(ContractError, /Actual: "bad"/)
+ end.to raise_error(ContractError, /Actual: "bad"/)
- expect {
+ expect do
@o.with_partial_sums_contracted(1, 2, 3)
- }.to raise_error(ContractError, /Actual: nil/)
+ end.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
expect { @o.map([1, 2, 3], lambda { |x| x + 1 }) }.to_not raise_error
end
+ it "should pass for a function that passes the contract as in tutorial" do
+ expect { @o.tutorial_map([1, 2, 3], lambda { |x| x + 1 }) }.to_not raise_error
+ end
+
it "should fail for a function that doesn't pass the contract" do
- expect { @o.map([1, 2, 3], lambda { |x| "bad return value" }) }.to raise_error(ContractError)
+ expect { @o.map([1, 2, 3], lambda { |_| "bad return value" }) }.to raise_error(ContractError)
end
+
+ it "should pass for a function that passes the contract with weak other args" do
+ expect { @o.map_plain(["hello", "joe"], lambda { |x| x.size }) }.to_not raise_error
+ end
+
+ it "should fail for a function that doesn't pass the contract with weak other args" do
+ expect { @o.map_plain(["hello", "joe"], lambda { |_| nil }) }.to raise_error(ContractError)
+ end
end
describe "default args to functions" do
it "should work for a function call that relies on default args" do
expect { @o.default_args }.to_not raise_error
@@ -441,10 +489,81 @@
expect(res).to eq("badbad")
end
end
end
+ describe "Contracts to_s formatting in expected" do
+ def not_s(match)
+ Regexp.new "[^\"\']#{match}[^\"\']"
+ end
+
+ def delim(match)
+ "(#{match})"
+ end
+
+ it "should not stringify native types" do
+ expect do
+ @o.constanty("bad", nil)
+ end.to raise_error(ContractError, not_s(123))
+
+ expect do
+ @o.constanty(123, "bad")
+ end.to raise_error(ContractError, not_s(nil))
+ end
+
+ it "should contain to_s representation within a Hash contract" do
+ expect do
+ @o.hash_complex_contracts(:rigged => "bad")
+ end.to raise_error(ContractError, not_s(delim "TrueClass or FalseClass"))
+ end
+
+ it "should contain to_s representation within a nested Hash contract" do
+ expect do
+ @o.nested_hash_complex_contracts(:rigged => true,
+ :contents => {
+ :kind => 0,
+ :total => 42 })
+ end.to raise_error(ContractError, not_s(delim "String or Symbol"))
+ end
+
+ it "should contain to_s representation within an Array contract" do
+ expect do
+ @o.array_complex_contracts(["bad"])
+ end.to raise_error(ContractError, not_s(delim "TrueClass or FalseClass"))
+ end
+
+ it "should contain to_s representation within a nested Array contract" do
+ expect do
+ @o.nested_array_complex_contracts([true, [0]])
+ end.to raise_error(ContractError, not_s(delim "String or Symbol"))
+ end
+
+ it "should not contain Contracts:: module prefix" do
+ expect do
+ @o.double("bad")
+ end.to raise_error(ContractError, /Expected: Num/)
+ end
+
+ it "should still show nils, not just blank space" do
+ expect do
+ @o.no_args("bad")
+ end.to raise_error(ContractError, /Expected: nil/)
+ end
+
+ it 'should show empty quotes as ""' do
+ expect do
+ @o.no_args("")
+ end.to raise_error(ContractError, /Actual: ""/)
+ end
+
+ it "should not use custom to_s if empty string" do
+ expect do
+ @o.using_empty_contract("bad")
+ end.to raise_error(ContractError, /Expected: EmptyCont/)
+ end
+ end
+
describe "functype" do
it "should correctly print out a instance method's type" do
expect(@o.functype(:double)).not_to eq("")
end
@@ -453,14 +572,24 @@
end
end
describe "private methods" do
it "should raise an error if you try to access a private method" do
- expect { @o.a_private_method }.to raise_error
+ expect { @o.a_private_method }.to raise_error(NoMethodError, /private/)
end
it "should raise an error if you try to access a private method" do
- expect { @o.a_really_private_method }.to raise_error
+ expect { @o.a_really_private_method }.to raise_error(NoMethodError, /private/)
+ end
+ end
+
+ describe "protected methods" do
+ it "should raise an error if you try to access a protected method" do
+ expect { @o.a_protected_method }.to raise_error(NoMethodError, /protected/)
+ end
+
+ it "should raise an error if you try to access a protected method" do
+ expect { @o.a_really_protected_method }.to raise_error(NoMethodError, /protected/)
end
end
describe "inherited methods" do
it "should apply the contract to an inherited method" do