aquarium 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. data/CHANGES +4 -0
  2. data/EXAMPLES.rd +4 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README +250 -0
  5. data/RELEASE-PLAN +1 -0
  6. data/Rakefile +236 -0
  7. data/UPGRADE +3 -0
  8. data/examples/aspect_design_example.rb +36 -0
  9. data/examples/design_by_contract_example.rb +88 -0
  10. data/examples/method_missing_example.rb +44 -0
  11. data/examples/method_tracing_example.rb +64 -0
  12. data/lib/aquarium.rb +7 -0
  13. data/lib/aquarium/aspects.rb +6 -0
  14. data/lib/aquarium/aspects/advice.rb +189 -0
  15. data/lib/aquarium/aspects/aspect.rb +577 -0
  16. data/lib/aquarium/aspects/default_object_handler.rb +27 -0
  17. data/lib/aquarium/aspects/dsl.rb +1 -0
  18. data/lib/aquarium/aspects/dsl/aspect_dsl.rb +61 -0
  19. data/lib/aquarium/aspects/join_point.rb +158 -0
  20. data/lib/aquarium/aspects/pointcut.rb +254 -0
  21. data/lib/aquarium/aspects/pointcut_composition.rb +36 -0
  22. data/lib/aquarium/extensions.rb +5 -0
  23. data/lib/aquarium/extensions/hash.rb +85 -0
  24. data/lib/aquarium/extensions/regexp.rb +20 -0
  25. data/lib/aquarium/extensions/set.rb +49 -0
  26. data/lib/aquarium/extensions/string.rb +13 -0
  27. data/lib/aquarium/extensions/symbol.rb +22 -0
  28. data/lib/aquarium/extras.rb +4 -0
  29. data/lib/aquarium/extras/design_by_contract.rb +64 -0
  30. data/lib/aquarium/finders.rb +4 -0
  31. data/lib/aquarium/finders/finder_result.rb +121 -0
  32. data/lib/aquarium/finders/method_finder.rb +228 -0
  33. data/lib/aquarium/finders/object_finder.rb +74 -0
  34. data/lib/aquarium/finders/type_finder.rb +127 -0
  35. data/lib/aquarium/utils.rb +9 -0
  36. data/lib/aquarium/utils/array_utils.rb +29 -0
  37. data/lib/aquarium/utils/hash_utils.rb +28 -0
  38. data/lib/aquarium/utils/html_escaper.rb +17 -0
  39. data/lib/aquarium/utils/invalid_options.rb +9 -0
  40. data/lib/aquarium/utils/method_utils.rb +18 -0
  41. data/lib/aquarium/utils/nil_object.rb +13 -0
  42. data/lib/aquarium/utils/set_utils.rb +32 -0
  43. data/lib/aquarium/version.rb +30 -0
  44. data/rake_tasks/examples.rake +7 -0
  45. data/rake_tasks/examples_specdoc.rake +8 -0
  46. data/rake_tasks/examples_with_rcov.rake +8 -0
  47. data/rake_tasks/verify_rcov.rake +7 -0
  48. data/spec/aquarium/aspects/advice_chain_node_spec.rb +34 -0
  49. data/spec/aquarium/aspects/advice_spec.rb +103 -0
  50. data/spec/aquarium/aspects/aspect_invocation_spec.rb +111 -0
  51. data/spec/aquarium/aspects/aspect_spec.rb +978 -0
  52. data/spec/aquarium/aspects/aspect_with_nested_types_spec.rb +129 -0
  53. data/spec/aquarium/aspects/concurrent_aspects_spec.rb +423 -0
  54. data/spec/aquarium/aspects/concurrent_aspects_with_objects_and_types_spec.rb +103 -0
  55. data/spec/aquarium/aspects/concurrently_accessed.rb +21 -0
  56. data/spec/aquarium/aspects/dsl/aspect_dsl_spec.rb +514 -0
  57. data/spec/aquarium/aspects/join_point_spec.rb +302 -0
  58. data/spec/aquarium/aspects/pointcut_and_composition_spec.rb +131 -0
  59. data/spec/aquarium/aspects/pointcut_or_composition_spec.rb +111 -0
  60. data/spec/aquarium/aspects/pointcut_spec.rb +800 -0
  61. data/spec/aquarium/extensions/hash_spec.rb +187 -0
  62. data/spec/aquarium/extensions/regex_spec.rb +40 -0
  63. data/spec/aquarium/extensions/set_spec.rb +105 -0
  64. data/spec/aquarium/extensions/string_spec.rb +25 -0
  65. data/spec/aquarium/extensions/symbol_spec.rb +37 -0
  66. data/spec/aquarium/extras/design_by_contract_spec.rb +68 -0
  67. data/spec/aquarium/finders/finder_result_spec.rb +359 -0
  68. data/spec/aquarium/finders/method_finder_spec.rb +878 -0
  69. data/spec/aquarium/finders/method_sorting_spec.rb +16 -0
  70. data/spec/aquarium/finders/object_finder_spec.rb +230 -0
  71. data/spec/aquarium/finders/type_finder_spec.rb +210 -0
  72. data/spec/aquarium/spec_example_classes.rb +117 -0
  73. data/spec/aquarium/spec_helper.rb +3 -0
  74. data/spec/aquarium/utils/array_utils_spec.rb +47 -0
  75. data/spec/aquarium/utils/hash_utils_spec.rb +48 -0
  76. data/spec/aquarium/utils/html_escaper_spec.rb +18 -0
  77. data/spec/aquarium/utils/method_utils_spec.rb +50 -0
  78. data/spec/aquarium/utils/nil_object_spec.rb +19 -0
  79. data/spec/aquarium/utils/set_utils_spec.rb +60 -0
  80. metadata +132 -0
@@ -0,0 +1,187 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+ require File.dirname(__FILE__) + '/../spec_example_classes'
3
+ require 'aquarium/extensions/hash'
4
+ require 'aquarium/utils/array_utils'
5
+ require 'aquarium/utils/hash_utils'
6
+ require 'set'
7
+
8
+ describe Hash, "#intersection" do
9
+ include Aquarium::Utils::ArrayUtils
10
+ include Aquarium::Utils::HashUtils
11
+
12
+ before(:each) do
13
+ @hash = {:a => 'a', :b => [:b1, :b2], :c => 'c'}
14
+ end
15
+
16
+ it "should return the same hash if intersected with itself." do
17
+ @hash.intersection(@hash).should == @hash
18
+ end
19
+
20
+ it "should return the same hash if intersected with an equivalent hash." do
21
+ @hash.intersection({:a => 'a', :b => [:b1, :b2], :c => 'c'}).should == @hash
22
+ end
23
+
24
+ it "should return an empty hash if one of the input hashes is empty." do
25
+ {}.intersection(@hash).should == {}
26
+ end
27
+
28
+ it "should return the common subset hash for two, non-equivalent hashes." do
29
+ hash2 = {:b =>:b1, :c => 'c', :d => 'd'}
30
+ @hash.intersection(hash2){|values1, values2| Set.new(make_array(values1)).intersection(Set.new(make_array(values2)))}.should == {:b =>Set.new([:b1]), :c => 'c'}
31
+ end
32
+ end
33
+
34
+ describe "intersection of hashes", :shared => true do
35
+ include Aquarium::Utils::ArrayUtils
36
+ include Aquarium::Utils::HashUtils
37
+
38
+ before(:each) do
39
+ @hash = {:a => 'a', :b => [:b1, :b2], :c => 'c'}
40
+ end
41
+
42
+ it "should return the same hash if intersected with itself." do
43
+ @hash.intersection(@hash).should == @hash
44
+ end
45
+
46
+ it "should return the same hash if intersected with an equivalent hash." do
47
+ @hash.intersection({:a => 'a', :b => [:b1, :b2], :c => 'c'}).should == @hash
48
+ end
49
+
50
+ it "should return an empty hash if one of the input hashes is empty." do
51
+ {}.intersection(@hash).should == {}
52
+ end
53
+
54
+ it "should return the common subset hash for two, non-equivalent hashes." do
55
+ hash2 = {:b =>:b1, :c => 'c', :d => 'd'}
56
+ @hash.intersection(hash2){|value1, value2| Set.new(make_array(value1)).intersection(Set.new(make_array(value2)))}.should == {:b =>Set.new([:b1]), :c => 'c'}
57
+ end
58
+ end
59
+
60
+ describe Hash, "#intersection" do
61
+ it_should_behave_like "intersection of hashes"
62
+ end
63
+
64
+ describe Hash, "#and" do
65
+ it_should_behave_like "intersection of hashes"
66
+ end
67
+
68
+ describe "union of hashes", :shared => true do
69
+ include Aquarium::Utils::ArrayUtils
70
+ include Aquarium::Utils::HashUtils
71
+
72
+ before(:each) do
73
+ @hash = {:a => 'a', :b => [:b1, :b2], :c => 'c'}
74
+ end
75
+
76
+ it "should return the same hash if unioned with itself." do
77
+ @hash.union(@hash).should == @hash
78
+ end
79
+
80
+ it "should return the same hash if unioned with an equivalent hash." do
81
+ @hash.union({:a => 'a', :b => [:b1, :b2], :c => 'c'}).should == @hash
82
+ end
83
+
84
+ it "should return a hash that is equivalent to the non-empty hash if the other hash is empty." do
85
+ {}.union(@hash).should == @hash
86
+ @hash.union({}).should == @hash
87
+ end
88
+
89
+ it "should return the same hash if unioned with nil." do
90
+ @hash.union(nil).should == @hash
91
+ end
92
+
93
+ it "should return a hash equivalent to the output of Hash#merge for two, non-equivalent hashes, with no block given." do
94
+ hash2 = {:b =>:b3, :c => 'c2', :d => 'd'}
95
+ @hash.union(hash2).should == {:a => 'a', :b => :b3, :c => 'c2', :d => 'd'}
96
+ end
97
+
98
+ it "should return the combined hashes for two, non-equivalent hashes, with a block given to merge values into an array." do
99
+ hash2 = {:b =>:b3, :c => 'c2', :d => 'd'}
100
+ @hash.union(hash2){|value1, value2| Set.new(make_array(value1)).union(Set.new(make_array(value2)))}.should == {:a => 'a', :b => Set.new([:b1, :b2, :b3]), :c => Set.new(['c', 'c2']), :d => 'd'}
101
+ end
102
+ end
103
+
104
+ describe Hash, "#union" do
105
+ it_should_behave_like "union of hashes"
106
+ end
107
+
108
+ describe Hash, "#or" do
109
+ it_should_behave_like "union of hashes"
110
+ end
111
+
112
+ describe Hash, "#eql_when_keys_compared?" do
113
+ include Aquarium::Utils::ArrayUtils
114
+ include Aquarium::Utils::HashUtils
115
+
116
+ it "should return true when comparing a hash to itself." do
117
+ h1={"1" => :a1, "2" => :a2, "3" => :a3}
118
+ h1.eql_when_keys_compared?(h1).should == true
119
+ end
120
+
121
+ it "should return true for hashes with string keys that satisfy String#==." do
122
+ h1={"1" => :a1, "2" => :a2, "3" => :a3}
123
+ h2={"1" => :a1, "2" => :a2, "3" => :a3}
124
+ h1.eql_when_keys_compared?(h2).should == true
125
+ end
126
+
127
+ it "should return false for hashes with matching keys, but different values." do
128
+ h1={"1" => :a1, "2" => :a2, "3" => /a/}
129
+ h2={"1" => :a1, "2" => :a2, "3" => /b/}
130
+ h1.eql_when_keys_compared?(h2).should == false
131
+ end
132
+
133
+ it "should return false for hashes where one hash is a subset of the other." do
134
+ h1={"1" => :a1, "2" => :a2}
135
+ h2={"1" => :a1, "2" => :a2, "3" => :a3}
136
+ h1.eql_when_keys_compared?(h2).should == false
137
+ h2.eql_when_keys_compared?(h1).should == false
138
+ end
139
+
140
+ it "should return true for hashes with Object keys that define a #<=> method, while Hash#eql? would return false." do
141
+ class Key
142
+ def initialize key
143
+ @key = key
144
+ end
145
+ attr_reader :key
146
+ def eql? other
147
+ key.eql? other.key
148
+ end
149
+ def <=> other
150
+ key <=> other.key
151
+ end
152
+ end
153
+
154
+ h1 = {}; h2 = {}
155
+ (0...4).each do |index|
156
+ h1[Key.new(index)] = {index.to_s => [index, index+1]}
157
+ h2[Key.new(index)] = {index.to_s => [index, index+1]}
158
+ end
159
+ h1.eql_when_keys_compared?(h2).should == true
160
+ h1.eql?(h2).should == false
161
+ end
162
+ end
163
+
164
+ describe Hash, "#equivalent_key" do
165
+ it "should return the key in the hash for which input_value#==(key) is true." do
166
+ class Key
167
+ def initialize key
168
+ @key = key
169
+ end
170
+ attr_reader :key
171
+ def eql? other
172
+ key.eql? other.key
173
+ end
174
+ alias :== :eql?
175
+ end
176
+
177
+ h1 = {}; h2 = {}
178
+ (0...4).each do |index|
179
+ h1[Key.new(index)] = {index.to_s => [index, index+1]}
180
+ h2[Key.new(index)] = {index.to_s => [index, index+1]}
181
+ end
182
+ h1[Key.new(0)].should be_nil
183
+ h1.equivalent_key(Key.new(0)).should_not be_nil
184
+ h1.equivalent_key(Key.new(5)).should be_nil
185
+ end
186
+
187
+ end
@@ -0,0 +1,40 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+ require 'aquarium/extensions/regexp'
3
+
4
+ describe Regexp, "#empty?" do
5
+
6
+ it "should return true for an empty regular expression" do
7
+ //.empty?.should be_true
8
+ Regexp.new("").empty?.should be_true
9
+ end
10
+
11
+ it "should return true for an empty regular expression with whitespace" do
12
+ / /.empty?.should be_true
13
+ Regexp.new(" ").empty?.should be_true
14
+ end
15
+
16
+ it "should return false for a non-empty regular expression" do
17
+ /x/.empty?.should be_false
18
+ Regexp.new("x").empty?.should be_false
19
+ end
20
+ end
21
+
22
+ describe Regexp, "#strip" do
23
+ it "should return equivalent Regexp if there is no leading or trailing whitespace." do
24
+ re = /^.{3}.*[a-z]$/
25
+ re.strip.should == re
26
+ end
27
+
28
+ it "should return new Regexp with removed leading and/or trailing whitespace, when present." do
29
+ re_string = "^.{3}.*[a-z]$"
30
+ re = Regexp.new " #{re_string} "
31
+ re.strip.source.should == re_string
32
+ end
33
+ end
34
+
35
+ describe Regexp, "#<=>" do
36
+ it "should sort by the output of #to_s" do
37
+ ary = [/^x/, /x/, /x$/]
38
+ ary.sort.should == [/^x/, /x$/, /x/]
39
+ end
40
+ end
@@ -0,0 +1,105 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+ require File.dirname(__FILE__) + '/../spec_example_classes'
3
+ require 'aquarium/extensions/set'
4
+
5
+ class Foo
6
+ def initialize name
7
+ @name = name
8
+ end
9
+ attr_reader :name
10
+ def eql? other
11
+ name.eql? other.name
12
+ end
13
+ alias :== :eql?
14
+ end
15
+ class Bar
16
+ end
17
+
18
+ describe "set comparison", :shared => true do
19
+ it "should return true for the same set" do
20
+ s = Set.new [Foo.new("f1"), Foo.new("f2")]
21
+ s.should eql(s)
22
+ end
23
+
24
+ it "should return true for equivalent sets" do
25
+ s1 = Set.new [Foo.new("f1"), Foo.new("f2")]
26
+ s2 = Set.new [Foo.new("f2"), Foo.new("f1")]
27
+ s1.should eql(s2)
28
+ end
29
+
30
+ it "should return false for sets where one is a subset of, but not equivalent to, the other set" do
31
+ s1 = Set.new [Foo.new("f1")]
32
+ s2 = Set.new [Foo.new("f2"), Foo.new("f1")]
33
+ s1.should_not eql(s2)
34
+ end
35
+
36
+ it "should return false for sets where some element pairs are of different types" do
37
+ s1 = Set.new [Foo.new("f1"), Bar.new]
38
+ s2 = Set.new [Foo.new("f1"), Foo.new("f2")]
39
+ s1.should_not eql(s2)
40
+ end
41
+ end
42
+
43
+ describe Set, "#==" do
44
+ it_should_behave_like "set comparison"
45
+ end
46
+
47
+ describe Set, "#eql?" do
48
+ it_should_behave_like "set comparison"
49
+ end
50
+
51
+ describe Set, "#union_using_eql_comparison" do
52
+ it "should return an equivalent set if unioned with itself" do
53
+ s = Set.new [Foo.new("f1"), Foo.new("f2")]
54
+ s.union_using_eql_comparison(s).should eql(s)
55
+ end
56
+
57
+ it "should return an equivalent set if unioned with another equivalent set" do
58
+ s1 = Set.new [Foo.new("f1"), Foo.new("f2")]
59
+ s2 = Set.new [Foo.new("f1"), Foo.new("f2")]
60
+ s1.union_using_eql_comparison(s2).should eql(s1)
61
+ end
62
+
63
+ it "should return an equivalent set if unioned with subset" do
64
+ s1 = Set.new [Foo.new("f1"), Foo.new("f2")]
65
+ s2 = Set.new [Foo.new("f1")]
66
+ s1.union_using_eql_comparison(s2).should eql(s1)
67
+ s2.union_using_eql_comparison(s1).should eql(s1)
68
+ end
69
+
70
+ it "should return a combined set if unioned with a disjoint set" do
71
+ s1 = Set.new [Foo.new("f1"), Foo.new("f2")]
72
+ s2 = Set.new [Foo.new("f3")]
73
+ s3 = Set.new [Foo.new("f1"), Foo.new("f2"), Foo.new("f3")]
74
+ s1.union_using_eql_comparison(s2).should eql(s3)
75
+ s2.union_using_eql_comparison(s1).should eql(s3)
76
+ end
77
+ end
78
+
79
+ describe Set, "#intersection_using_eql_comparison" do
80
+ it "should return an equivalent set if intersectioned with itself" do
81
+ s = Set.new [Foo.new("f1"), Foo.new("f2")]
82
+ s.intersection_using_eql_comparison(s).should eql(s)
83
+ end
84
+
85
+ it "should return an equivalent set if intersectioned with another equivalent set" do
86
+ s1 = Set.new [Foo.new("f1"), Foo.new("f2")]
87
+ s2 = Set.new [Foo.new("f1"), Foo.new("f2")]
88
+ s1.intersection_using_eql_comparison(s2).should eql(s1)
89
+ end
90
+
91
+ it "should return a subset if intersectioned with an equivalent subset" do
92
+ s1 = Set.new [Foo.new("f1"), Foo.new("f2")]
93
+ s2 = Set.new [Foo.new("f1")]
94
+ s1.intersection_using_eql_comparison(s2).should eql(s2)
95
+ s2.intersection_using_eql_comparison(s1).should eql(s2)
96
+ end
97
+
98
+ it "should return an empty set if intersectioned with a disjoint set" do
99
+ s1 = Set.new [Foo.new("f1"), Foo.new("f2")]
100
+ s2 = Set.new [Foo.new("f3")]
101
+ s1.intersection_using_eql_comparison(s2).should eql(Set.new)
102
+ s2.intersection_using_eql_comparison(s1).should eql(Set.new)
103
+ end
104
+ end
105
+
@@ -0,0 +1,25 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+ require 'aquarium/extensions/string'
3
+
4
+ describe String, "#to_camel_case" do
5
+ it "should return a camel-case string unchanged" do
6
+ "CamelCaseString".to_camel_case.should == "CamelCaseString"
7
+ end
8
+
9
+ it "should return a camel-case string from an input string with substrings separated by underscores" do
10
+ "camel_case_string".to_camel_case.should == "CamelCaseString"
11
+ end
12
+
13
+ it "should return a camel-case string with the first letters of each substring in uppercase and the rest of the letters in each substring unchanged" do
14
+ "cAmEl_cASE_stRinG".to_camel_case.should == "CAmElCASEStRinG"
15
+ end
16
+
17
+ it "should remove leading and trailing underscores" do
18
+ "camel_case_string_".to_camel_case.should == "CamelCaseString"
19
+ "_camel_case_string".to_camel_case.should == "CamelCaseString"
20
+ "camel_case_string__".to_camel_case.should == "CamelCaseString"
21
+ "__camel_case_string".to_camel_case.should == "CamelCaseString"
22
+ "_camel_case_string_".to_camel_case.should == "CamelCaseString"
23
+ "__camel_case_string__".to_camel_case.should == "CamelCaseString"
24
+ end
25
+ end
@@ -0,0 +1,37 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+ require 'aquarium/extensions/symbol'
3
+
4
+ describe "Symbol#empty?" do
5
+
6
+ it "should return true for an empty symbol with whitespace" do
7
+ :" \t ".empty?.should be_true
8
+ end
9
+
10
+ it "should return false for a non-empty symbol" do
11
+ :x.empty?.should be_false
12
+ end
13
+ end
14
+
15
+ describe "Symbol#strip" do
16
+ it "should return equivalent Symbol if there is no leading or trailing whitespace." do
17
+ :a.strip.should == :a
18
+ end
19
+
20
+ it "should return new Symbol with removed leading and/or trailing whitespace, when present." do
21
+ :" \ta\t ".strip.should == :a
22
+ end
23
+ end
24
+
25
+ describe "Symbol#<=>" do
26
+ it "should return < 0 if the string representation of the left-hand side symbol is less than the string representation of the right-hand side symbol." do
27
+ (:a <=> :b).should == -1
28
+ end
29
+
30
+ it "should return > 0 if the string representation of the left-hand side symbol is greater than the string representation of the right-hand side symbol." do
31
+ (:b <=> :a).should == 1
32
+ end
33
+
34
+ it "should return 0 if the string representation of the left-hand side symbol is equal to the string representation of the right-hand side symbol." do
35
+ (:a <=> :a).should == 0
36
+ end
37
+ end
@@ -0,0 +1,68 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+ require 'aquarium/extras/design_by_contract'
3
+
4
+ describe Aquarium::Extras::DesignByContract, "precondition" do
5
+ class PreCond
6
+ def action *args
7
+ end
8
+
9
+ precondition :method => :action, :message => "Must pass more than one argument." do |jp, *args|
10
+ args.size > 0
11
+ end
12
+ end
13
+
14
+ it "should add advice that raises if the precondition is not satisfied" do
15
+ lambda {PreCond.new.action}.should raise_error(Aquarium::Extras::DesignByContract::ContractError)
16
+ end
17
+
18
+ it "should add advice that does not raise if the precondition is satisfied" do
19
+ PreCond.new.action(:a1)
20
+ end
21
+ end
22
+
23
+ describe Aquarium::Extras::DesignByContract, "postcondition" do
24
+ class PostCond
25
+ def action *args
26
+ end
27
+
28
+ postcondition :method => :action, :message => "Must pass more than one argument and first argument must be non-empty." do |jp, *args|
29
+ args.size > 0 && ! args[0].empty?
30
+ end
31
+ end
32
+
33
+ it "should add advice that raises if the postcondition is not satisfied" do
34
+ lambda {PostCond.new.action}.should raise_error(Aquarium::Extras::DesignByContract::ContractError)
35
+ lambda {PostCond.new.action("")}.should raise_error(Aquarium::Extras::DesignByContract::ContractError)
36
+ end
37
+
38
+ it "should add advice that does not raise if the postcondition is satisfied" do
39
+ PostCond.new.action(:a1)
40
+ end
41
+ end
42
+
43
+
44
+ describe Aquarium::Extras::DesignByContract, "invariant" do
45
+ class InvarCond
46
+ def initialize
47
+ @invar = 0
48
+ end
49
+ attr_reader :invar
50
+ def good_action
51
+ end
52
+ def bad_action
53
+ @invar = 1
54
+ end
55
+
56
+ invariant :methods => /action$/, :message => "Must not change the @invar value." do |jp, *args|
57
+ jp.context.advised_object.invar == 0
58
+ end
59
+ end
60
+
61
+ it "should add advice that raises if the invariant is not satisfied" do
62
+ lambda {InvarCond.new.bad_action}.should raise_error(Aquarium::Extras::DesignByContract::ContractError)
63
+ end
64
+
65
+ it "should add advice that does not raise if the invariant is satisfied" do
66
+ InvarCond.new.good_action
67
+ end
68
+ end