entitlements 0.1.8 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (176) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/bin/deploy-entitlements +10 -1
  4. data/lib/contracts-ruby2/CHANGELOG.markdown +115 -0
  5. data/lib/contracts-ruby2/Gemfile +17 -0
  6. data/lib/contracts-ruby2/LICENSE +23 -0
  7. data/lib/contracts-ruby2/README.md +108 -0
  8. data/lib/contracts-ruby2/Rakefile +8 -0
  9. data/lib/contracts-ruby2/TODO.markdown +6 -0
  10. data/lib/contracts-ruby2/TUTORIAL.md +773 -0
  11. data/lib/contracts-ruby2/benchmarks/bench.rb +67 -0
  12. data/lib/contracts-ruby2/benchmarks/hash.rb +69 -0
  13. data/lib/contracts-ruby2/benchmarks/invariants.rb +91 -0
  14. data/lib/contracts-ruby2/benchmarks/io.rb +62 -0
  15. data/lib/contracts-ruby2/benchmarks/wrap_test.rb +57 -0
  16. data/lib/contracts-ruby2/contracts.gemspec +17 -0
  17. data/lib/contracts-ruby2/cucumber.yml +1 -0
  18. data/lib/contracts-ruby2/dependabot.yml +20 -0
  19. data/lib/contracts-ruby2/features/README.md +17 -0
  20. data/lib/contracts-ruby2/features/basics/functype.feature +71 -0
  21. data/lib/contracts-ruby2/features/basics/pretty-print.feature +241 -0
  22. data/lib/contracts-ruby2/features/basics/simple_example.feature +210 -0
  23. data/lib/contracts-ruby2/features/builtin_contracts/README.md +22 -0
  24. data/lib/contracts-ruby2/features/builtin_contracts/and.feature +103 -0
  25. data/lib/contracts-ruby2/features/builtin_contracts/any.feature +44 -0
  26. data/lib/contracts-ruby2/features/builtin_contracts/args.feature +80 -0
  27. data/lib/contracts-ruby2/features/builtin_contracts/array_of.feature +1 -0
  28. data/lib/contracts-ruby2/features/builtin_contracts/bool.feature +64 -0
  29. data/lib/contracts-ruby2/features/builtin_contracts/enum.feature +1 -0
  30. data/lib/contracts-ruby2/features/builtin_contracts/eq.feature +1 -0
  31. data/lib/contracts-ruby2/features/builtin_contracts/exactly.feature +1 -0
  32. data/lib/contracts-ruby2/features/builtin_contracts/func.feature +1 -0
  33. data/lib/contracts-ruby2/features/builtin_contracts/hash_of.feature +1 -0
  34. data/lib/contracts-ruby2/features/builtin_contracts/int.feature +93 -0
  35. data/lib/contracts-ruby2/features/builtin_contracts/keyword_args.feature +1 -0
  36. data/lib/contracts-ruby2/features/builtin_contracts/maybe.feature +1 -0
  37. data/lib/contracts-ruby2/features/builtin_contracts/nat.feature +115 -0
  38. data/lib/contracts-ruby2/features/builtin_contracts/nat_pos.feature +119 -0
  39. data/lib/contracts-ruby2/features/builtin_contracts/neg.feature +115 -0
  40. data/lib/contracts-ruby2/features/builtin_contracts/none.feature +145 -0
  41. data/lib/contracts-ruby2/features/builtin_contracts/not.feature +1 -0
  42. data/lib/contracts-ruby2/features/builtin_contracts/num.feature +64 -0
  43. data/lib/contracts-ruby2/features/builtin_contracts/or.feature +83 -0
  44. data/lib/contracts-ruby2/features/builtin_contracts/pos.feature +116 -0
  45. data/lib/contracts-ruby2/features/builtin_contracts/range_of.feature +1 -0
  46. data/lib/contracts-ruby2/features/builtin_contracts/respond_to.feature +78 -0
  47. data/lib/contracts-ruby2/features/builtin_contracts/send.feature +147 -0
  48. data/lib/contracts-ruby2/features/builtin_contracts/set_of.feature +1 -0
  49. data/lib/contracts-ruby2/features/builtin_contracts/xor.feature +99 -0
  50. data/lib/contracts-ruby2/features/support/env.rb +6 -0
  51. data/lib/contracts-ruby2/lib/contracts/attrs.rb +24 -0
  52. data/lib/contracts-ruby2/lib/contracts/builtin_contracts.rb +542 -0
  53. data/lib/contracts-ruby2/lib/contracts/call_with.rb +108 -0
  54. data/lib/contracts-ruby2/lib/contracts/core.rb +52 -0
  55. data/lib/contracts-ruby2/lib/contracts/decorators.rb +47 -0
  56. data/lib/contracts-ruby2/lib/contracts/engine/base.rb +136 -0
  57. data/lib/contracts-ruby2/lib/contracts/engine/eigenclass.rb +50 -0
  58. data/lib/contracts-ruby2/lib/contracts/engine/target.rb +70 -0
  59. data/lib/contracts-ruby2/lib/contracts/engine.rb +26 -0
  60. data/lib/contracts-ruby2/lib/contracts/errors.rb +71 -0
  61. data/lib/contracts-ruby2/lib/contracts/formatters.rb +136 -0
  62. data/lib/contracts-ruby2/lib/contracts/invariants.rb +68 -0
  63. data/lib/contracts-ruby2/lib/contracts/method_handler.rb +187 -0
  64. data/lib/contracts-ruby2/lib/contracts/method_reference.rb +100 -0
  65. data/lib/contracts-ruby2/lib/contracts/support.rb +61 -0
  66. data/lib/contracts-ruby2/lib/contracts/validators.rb +139 -0
  67. data/lib/contracts-ruby2/lib/contracts/version.rb +3 -0
  68. data/lib/contracts-ruby2/lib/contracts.rb +281 -0
  69. data/lib/contracts-ruby2/script/docs-release +3 -0
  70. data/lib/contracts-ruby2/script/docs-staging +3 -0
  71. data/lib/contracts-ruby2/script/rubocop.rb +5 -0
  72. data/lib/contracts-ruby2/spec/attrs_spec.rb +119 -0
  73. data/lib/contracts-ruby2/spec/builtin_contracts_spec.rb +461 -0
  74. data/lib/contracts-ruby2/spec/contracts_spec.rb +770 -0
  75. data/lib/contracts-ruby2/spec/fixtures/fixtures.rb +730 -0
  76. data/lib/contracts-ruby2/spec/invariants_spec.rb +17 -0
  77. data/lib/contracts-ruby2/spec/methods_spec.rb +54 -0
  78. data/lib/contracts-ruby2/spec/module_spec.rb +18 -0
  79. data/lib/contracts-ruby2/spec/override_validators_spec.rb +162 -0
  80. data/lib/contracts-ruby2/spec/ruby_version_specific/contracts_spec_1.9.rb +24 -0
  81. data/lib/contracts-ruby2/spec/ruby_version_specific/contracts_spec_2.0.rb +55 -0
  82. data/lib/contracts-ruby2/spec/ruby_version_specific/contracts_spec_2.1.rb +63 -0
  83. data/lib/contracts-ruby2/spec/spec_helper.rb +102 -0
  84. data/lib/contracts-ruby2/spec/support.rb +10 -0
  85. data/lib/contracts-ruby2/spec/support_spec.rb +21 -0
  86. data/lib/contracts-ruby2/spec/validators_spec.rb +47 -0
  87. data/lib/contracts-ruby3/CHANGELOG.markdown +117 -0
  88. data/lib/contracts-ruby3/Gemfile +21 -0
  89. data/lib/contracts-ruby3/LICENSE +23 -0
  90. data/lib/contracts-ruby3/README.md +114 -0
  91. data/lib/contracts-ruby3/Rakefile +10 -0
  92. data/lib/contracts-ruby3/TODO.markdown +6 -0
  93. data/lib/contracts-ruby3/TUTORIAL.md +773 -0
  94. data/lib/contracts-ruby3/benchmarks/bench.rb +67 -0
  95. data/lib/contracts-ruby3/benchmarks/hash.rb +69 -0
  96. data/lib/contracts-ruby3/benchmarks/invariants.rb +91 -0
  97. data/lib/contracts-ruby3/benchmarks/io.rb +62 -0
  98. data/lib/contracts-ruby3/benchmarks/wrap_test.rb +57 -0
  99. data/lib/contracts-ruby3/contracts.gemspec +20 -0
  100. data/lib/contracts-ruby3/cucumber.yml +1 -0
  101. data/lib/contracts-ruby3/dependabot.yml +20 -0
  102. data/lib/contracts-ruby3/features/README.md +17 -0
  103. data/lib/contracts-ruby3/features/basics/functype.feature +71 -0
  104. data/lib/contracts-ruby3/features/basics/pretty-print.feature +241 -0
  105. data/lib/contracts-ruby3/features/basics/simple_example.feature +210 -0
  106. data/lib/contracts-ruby3/features/builtin_contracts/README.md +22 -0
  107. data/lib/contracts-ruby3/features/builtin_contracts/and.feature +103 -0
  108. data/lib/contracts-ruby3/features/builtin_contracts/any.feature +44 -0
  109. data/lib/contracts-ruby3/features/builtin_contracts/args.feature +80 -0
  110. data/lib/contracts-ruby3/features/builtin_contracts/array_of.feature +1 -0
  111. data/lib/contracts-ruby3/features/builtin_contracts/bool.feature +64 -0
  112. data/lib/contracts-ruby3/features/builtin_contracts/enum.feature +1 -0
  113. data/lib/contracts-ruby3/features/builtin_contracts/eq.feature +1 -0
  114. data/lib/contracts-ruby3/features/builtin_contracts/exactly.feature +1 -0
  115. data/lib/contracts-ruby3/features/builtin_contracts/func.feature +1 -0
  116. data/lib/contracts-ruby3/features/builtin_contracts/hash_of.feature +1 -0
  117. data/lib/contracts-ruby3/features/builtin_contracts/int.feature +93 -0
  118. data/lib/contracts-ruby3/features/builtin_contracts/keyword_args.feature +1 -0
  119. data/lib/contracts-ruby3/features/builtin_contracts/maybe.feature +1 -0
  120. data/lib/contracts-ruby3/features/builtin_contracts/nat.feature +115 -0
  121. data/lib/contracts-ruby3/features/builtin_contracts/nat_pos.feature +119 -0
  122. data/lib/contracts-ruby3/features/builtin_contracts/neg.feature +115 -0
  123. data/lib/contracts-ruby3/features/builtin_contracts/none.feature +145 -0
  124. data/lib/contracts-ruby3/features/builtin_contracts/not.feature +1 -0
  125. data/lib/contracts-ruby3/features/builtin_contracts/num.feature +64 -0
  126. data/lib/contracts-ruby3/features/builtin_contracts/or.feature +83 -0
  127. data/lib/contracts-ruby3/features/builtin_contracts/pos.feature +116 -0
  128. data/lib/contracts-ruby3/features/builtin_contracts/range_of.feature +1 -0
  129. data/lib/contracts-ruby3/features/builtin_contracts/respond_to.feature +78 -0
  130. data/lib/contracts-ruby3/features/builtin_contracts/send.feature +147 -0
  131. data/lib/contracts-ruby3/features/builtin_contracts/set_of.feature +1 -0
  132. data/lib/contracts-ruby3/features/builtin_contracts/xor.feature +99 -0
  133. data/lib/contracts-ruby3/features/support/env.rb +8 -0
  134. data/lib/contracts-ruby3/lib/contracts/attrs.rb +26 -0
  135. data/lib/contracts-ruby3/lib/contracts/builtin_contracts.rb +575 -0
  136. data/lib/contracts-ruby3/lib/contracts/call_with.rb +119 -0
  137. data/lib/contracts-ruby3/lib/contracts/core.rb +54 -0
  138. data/lib/contracts-ruby3/lib/contracts/decorators.rb +50 -0
  139. data/lib/contracts-ruby3/lib/contracts/engine/base.rb +137 -0
  140. data/lib/contracts-ruby3/lib/contracts/engine/eigenclass.rb +51 -0
  141. data/lib/contracts-ruby3/lib/contracts/engine/target.rb +72 -0
  142. data/lib/contracts-ruby3/lib/contracts/engine.rb +28 -0
  143. data/lib/contracts-ruby3/lib/contracts/errors.rb +74 -0
  144. data/lib/contracts-ruby3/lib/contracts/formatters.rb +140 -0
  145. data/lib/contracts-ruby3/lib/contracts/invariants.rb +72 -0
  146. data/lib/contracts-ruby3/lib/contracts/method_handler.rb +197 -0
  147. data/lib/contracts-ruby3/lib/contracts/method_reference.rb +102 -0
  148. data/lib/contracts-ruby3/lib/contracts/support.rb +63 -0
  149. data/lib/contracts-ruby3/lib/contracts/validators.rb +143 -0
  150. data/lib/contracts-ruby3/lib/contracts/version.rb +5 -0
  151. data/lib/contracts-ruby3/lib/contracts.rb +290 -0
  152. data/lib/contracts-ruby3/script/docs-release +3 -0
  153. data/lib/contracts-ruby3/script/docs-staging +3 -0
  154. data/lib/contracts-ruby3/script/rubocop.rb +5 -0
  155. data/lib/contracts-ruby3/spec/attrs_spec.rb +119 -0
  156. data/lib/contracts-ruby3/spec/builtin_contracts_spec.rb +457 -0
  157. data/lib/contracts-ruby3/spec/contracts_spec.rb +773 -0
  158. data/lib/contracts-ruby3/spec/fixtures/fixtures.rb +725 -0
  159. data/lib/contracts-ruby3/spec/invariants_spec.rb +17 -0
  160. data/lib/contracts-ruby3/spec/methods_spec.rb +54 -0
  161. data/lib/contracts-ruby3/spec/module_spec.rb +18 -0
  162. data/lib/contracts-ruby3/spec/override_validators_spec.rb +162 -0
  163. data/lib/contracts-ruby3/spec/ruby_version_specific/contracts_spec_1.9.rb +24 -0
  164. data/lib/contracts-ruby3/spec/ruby_version_specific/contracts_spec_2.0.rb +55 -0
  165. data/lib/contracts-ruby3/spec/ruby_version_specific/contracts_spec_2.1.rb +63 -0
  166. data/lib/contracts-ruby3/spec/spec_helper.rb +102 -0
  167. data/lib/contracts-ruby3/spec/support.rb +10 -0
  168. data/lib/contracts-ruby3/spec/support_spec.rb +21 -0
  169. data/lib/contracts-ruby3/spec/validators_spec.rb +47 -0
  170. data/lib/entitlements/data/groups/calculated/yaml.rb +7 -1
  171. data/lib/entitlements/data/people/yaml.rb +9 -1
  172. data/lib/entitlements/extras/ldap_group/rules/ldap_group.rb +5 -1
  173. data/lib/entitlements/extras/orgchart/person_methods.rb +7 -1
  174. data/lib/entitlements.rb +13 -2
  175. data/lib/ruby_version_check.rb +17 -0
  176. metadata +209 -14
@@ -0,0 +1,773 @@
1
+ RSpec.describe "Contracts:" do
2
+ before :all do
3
+ @o = GenericExample.new
4
+ end
5
+
6
+ describe "basic" do
7
+ it "should fail for insufficient arguments" do
8
+ expect do
9
+ @o.hello
10
+ end.to raise_error ArgumentError
11
+ end
12
+
13
+ it "should fail for insufficient contracts" do
14
+ expect { @o.bad_double(2) }.to raise_error(ContractError)
15
+ end
16
+ end
17
+
18
+ describe "contracts for functions with no arguments" do
19
+ it "should work for functions with no args" do
20
+ expect { @o.no_args }.to_not raise_error
21
+ end
22
+
23
+ it "should still work for old-style contracts for functions with no args" do
24
+ expect { @o.old_style_no_args }.to_not raise_error
25
+ end
26
+
27
+ it "should not work for a function with a bad contract" do
28
+ expect do
29
+ Class.new(GenericExample) do
30
+ Contract Num, Num
31
+ def no_args_bad_contract
32
+ 1
33
+ end
34
+ end
35
+ end.to raise_error NameError
36
+ end
37
+ end
38
+
39
+ describe "pattern matching" do
40
+ let(:string_with_hello) { "Hello, world" }
41
+ let(:string_without_hello) { "Hi, world" }
42
+ let(:expected_decorated_string) { "Hello, world!" }
43
+ subject { PatternMatchingExample.new }
44
+
45
+ it "should work as expected when there is no contract violation" do
46
+ expect(
47
+ subject.process_request(PatternMatchingExample::Success.new(string_with_hello))
48
+ ).to eq(PatternMatchingExample::Success.new(expected_decorated_string))
49
+
50
+ expect(
51
+ subject.process_request(PatternMatchingExample::Failure.new)
52
+ ).to be_a(PatternMatchingExample::Failure)
53
+ end
54
+
55
+ it "should not fall through to next pattern when there is a deep contract violation" do
56
+ expect(PatternMatchingExample::Failure).not_to receive(:is_a?)
57
+ expect do
58
+ subject.process_request(PatternMatchingExample::Success.new(string_without_hello))
59
+ end.to raise_error(ContractError)
60
+ end
61
+
62
+ it "should fail when the pattern-matched method's contract fails" do
63
+ expect do
64
+ subject.process_request("bad input")
65
+ end.to raise_error(ContractError)
66
+ end
67
+
68
+ it "should work for differing arities" do
69
+ expect(
70
+ subject.do_stuff(1, "abc", 2)
71
+ ).to eq("bar")
72
+
73
+ expect(
74
+ subject.do_stuff(3, "def")
75
+ ).to eq("foo")
76
+ end
77
+
78
+ it "if the return contract for a pattern match fails, it should fail instead of trying the next pattern match" do
79
+ expect do
80
+ subject.double(1)
81
+ end.to raise_error(ContractError)
82
+ end
83
+
84
+ it "should fail if multiple methods are defined with the same contract (for pattern-matching)" do
85
+ expect do
86
+ Class.new(GenericExample) do
87
+ Contract Contracts::Num => Contracts::Num
88
+ def same_param_contract x
89
+ x + 2
90
+ end
91
+
92
+ Contract Contracts::Num => String
93
+ def same_param_contract x
94
+ "sdf"
95
+ end
96
+ end
97
+ end.to raise_error(ContractError)
98
+ end
99
+
100
+ context "when failure_callback was overriden" do
101
+ before do
102
+ ::Contract.override_failure_callback do |_data|
103
+ fail "contract violation"
104
+ end
105
+ end
106
+
107
+ it "calls a method when first pattern matches" do
108
+ expect(
109
+ subject.process_request(PatternMatchingExample::Success.new(string_with_hello))
110
+ ).to eq(PatternMatchingExample::Success.new(expected_decorated_string))
111
+ end
112
+
113
+ it "falls through to 2nd pattern when first pattern does not match" do
114
+ expect(
115
+ subject.process_request(PatternMatchingExample::Failure.new)
116
+ ).to be_a(PatternMatchingExample::Failure)
117
+ end
118
+
119
+ it "if the return contract for a pattern match fails, it should fail instead of trying the next pattern match, even with the failure callback" do
120
+ expect do
121
+ subject.double(1)
122
+ end.to raise_error(ContractError)
123
+ end
124
+
125
+ it "uses overriden failure_callback when pattern matching fails" do
126
+ expect do
127
+ subject.process_request("hello")
128
+ end.to raise_error(RuntimeError, /contract violation/)
129
+ end
130
+ end
131
+ end
132
+
133
+ describe "usage in singleton class" do
134
+ it "should work normally when there is no contract violation" do
135
+ expect(SingletonClassExample.hoge("hoge")).to eq("superhoge")
136
+ end
137
+
138
+ it "should fail with proper error when there is contract violation" do
139
+ expect do
140
+ SingletonClassExample.hoge(3)
141
+ end.to raise_error(ContractError, /Expected: String/)
142
+ end
143
+
144
+ describe "builtin contracts usage" do
145
+ it "allows to use builtin contracts without namespacing and redundant Contracts inclusion" do
146
+ expect do
147
+ SingletonClassExample.add("55", 5.6)
148
+ end.to raise_error(ContractError, /Expected: Num/)
149
+ end
150
+ end
151
+ end
152
+
153
+ describe "usage in the singleton class of a subclass" do
154
+ subject { SingletonInheritanceExampleSubclass }
155
+
156
+ it "should work with a valid contract on a singleton method" do
157
+ expect(subject.num(1)).to eq(1)
158
+ end
159
+ end
160
+
161
+ describe "no contracts feature" do
162
+ it "disables normal contract checks" do
163
+ object = NoContractsSimpleExample.new
164
+ expect { object.some_method(3) }.not_to raise_error
165
+ end
166
+
167
+ it "disables invariants" do
168
+ object = NoContractsInvariantsExample.new
169
+ object.day = 7
170
+ expect { object.next_day }.not_to raise_error
171
+ end
172
+
173
+ it "does not disable pattern matching" do
174
+ object = NoContractsPatternMatchingExample.new
175
+
176
+ expect(object.on_response(200, "hello")).to eq("hello!")
177
+ expect(object.on_response(404, "Not found")).to eq("error 404: Not found")
178
+ expect { object.on_response(nil, "junk response") }.to raise_error(ContractError)
179
+ end
180
+ end
181
+
182
+ describe "module usage" do
183
+ context "with instance methods" do
184
+ it "should check contract" do
185
+ expect { KlassWithModuleExample.new.plus(3, nil) }.to raise_error(ContractError)
186
+ end
187
+ end
188
+
189
+ context "with singleton methods" do
190
+ it "should check contract" do
191
+ expect { ModuleExample.hoge(nil) }.to raise_error(ContractError)
192
+ end
193
+ end
194
+
195
+ context "with singleton class methods" do
196
+ it "should check contract" do
197
+ expect { ModuleExample.eat(:food) }.to raise_error(ContractError)
198
+ end
199
+ end
200
+ end
201
+
202
+ describe "singleton methods self in inherited methods" do
203
+ it "should be a proper self" do
204
+ expect(SingletonInheritanceExampleSubclass.a_contracted_self).to eq(SingletonInheritanceExampleSubclass)
205
+ end
206
+ end
207
+
208
+ describe "anonymous classes" do
209
+ let(:klass) do
210
+ Class.new do
211
+ include Contracts::Core
212
+
213
+ Contract String => String
214
+ def greeting(name)
215
+ "hello, #{name}"
216
+ end
217
+ end
218
+ end
219
+
220
+ let(:obj) { klass.new }
221
+
222
+ it "does not fail when contract is satisfied" do
223
+ expect(obj.greeting("world")).to eq("hello, world")
224
+ end
225
+
226
+ it "fails with error when contract is violated" do
227
+ expect { obj.greeting(3) }.to raise_error(ContractError, /Actual: 3/)
228
+ end
229
+ end
230
+
231
+ describe "anonymous modules" do
232
+ let(:mod) do
233
+ Module.new do
234
+ include Contracts::Core
235
+
236
+ Contract String => String
237
+ def greeting(name)
238
+ "hello, #{name}"
239
+ end
240
+
241
+ Contract String => String
242
+ def self.greeting(name)
243
+ "hello, #{name}"
244
+ end
245
+ end
246
+ end
247
+
248
+ let(:klass) do
249
+ Class.new.tap { |klass| klass.send(:include, mod) }
250
+ end
251
+
252
+ let(:obj) { klass.new }
253
+
254
+ it "does not fail when contract is satisfied" do
255
+ expect(obj.greeting("world")).to eq("hello, world")
256
+ end
257
+
258
+ it "fails with error when contract is violated" do
259
+ expect { obj.greeting(3) }.to raise_error(ContractError, /Actual: 3/)
260
+ end
261
+
262
+ context "when called on module itself" do
263
+ let(:obj) { mod }
264
+
265
+ it "does not fail when contract is satisfied" do
266
+ expect(obj.greeting("world")).to eq("hello, world")
267
+ end
268
+
269
+ it "fails with error when contract is violated" do
270
+ expect { obj.greeting(3) }.to raise_error(ContractError, /Actual: 3/)
271
+ end
272
+ end
273
+ end
274
+
275
+ describe "instance methods" do
276
+ it "should allow two classes to have the same method with different contracts" do
277
+ a = A.new
278
+ b = B.new
279
+ expect do
280
+ a.triple(5)
281
+ b.triple("a string")
282
+ end.to_not raise_error
283
+ end
284
+ end
285
+
286
+ describe "instance and class methods" do
287
+ it "should allow a class to have an instance method and a class method with the same name" do
288
+ a = A.new
289
+ expect do
290
+ a.instance_and_class_method(5)
291
+ A.instance_and_class_method("a string")
292
+ end.to_not raise_error
293
+ end
294
+ end
295
+
296
+ describe "class methods" do
297
+ it "should pass for correct input" do
298
+ expect { GenericExample.a_class_method(2) }.to_not raise_error
299
+ end
300
+
301
+ it "should fail for incorrect input" do
302
+ expect { GenericExample.a_class_method("bad") }.to raise_error(ContractError)
303
+ end
304
+ end
305
+
306
+ describe "classes" do
307
+ it "should pass for correct input" do
308
+ expect { @o.hello("calvin") }.to_not raise_error
309
+ end
310
+
311
+ it "should fail for incorrect input" do
312
+ expect { @o.hello(1) }.to raise_error(ContractError)
313
+ end
314
+ end
315
+
316
+ describe "classes with a valid? class method" do
317
+ it "should pass for correct input" do
318
+ expect { @o.double(2) }.to_not raise_error
319
+ end
320
+
321
+ it "should fail for incorrect input" do
322
+ expect { @o.double("bad") }.to raise_error(ContractError)
323
+ end
324
+ end
325
+
326
+ describe "Procs" do
327
+ it "should pass for correct input" do
328
+ expect { @o.square(2) }.to_not raise_error
329
+ end
330
+
331
+ it "should fail for incorrect input" do
332
+ expect { @o.square("bad") }.to raise_error(ContractError)
333
+ end
334
+ end
335
+
336
+ describe "Arrays" do
337
+ it "should pass for correct input" do
338
+ expect { @o.sum_three([1, 2, 3]) }.to_not raise_error
339
+ end
340
+
341
+ it "should fail for insufficient items" do
342
+ expect { @o.square([1, 2]) }.to raise_error(ContractError)
343
+ end
344
+
345
+ it "should fail for some incorrect elements" do
346
+ expect { @o.sum_three([1, 2, "three"]) }.to raise_error(ContractError)
347
+ end
348
+ end
349
+
350
+ describe "Hashes" do
351
+ it "should pass for exact correct input" do
352
+ expect { @o.person({ :name => "calvin", :age => 10 }) }.to_not raise_error
353
+ end
354
+
355
+ it "should pass even if some keys don't have contracts" do
356
+ expect { @o.person({ :name => "calvin", :age => 10, :foo => "bar" }) }.to_not raise_error
357
+ end
358
+
359
+ it "should fail if a key with a contract on it isn't provided" do
360
+ expect { @o.person({ :name => "calvin" }) }.to raise_error(ContractError)
361
+ end
362
+
363
+ it "should fail for incorrect input" do
364
+ expect { @o.person({ :name => 50, :age => 10 }) }.to raise_error(ContractError)
365
+ end
366
+ end
367
+
368
+ describe "blocks" do
369
+ it "should pass for correct input" do
370
+ expect do
371
+ @o.do_call do
372
+ 2 + 2
373
+ end
374
+ end.to_not raise_error
375
+ end
376
+
377
+ it "should fail for incorrect input" do
378
+ expect do
379
+ @o.do_call(nil)
380
+ end.to raise_error(ContractError)
381
+ end
382
+
383
+ it "should handle properly lack of block when there are other arguments" do
384
+ expect do
385
+ @o.double_with_proc(4)
386
+ end.to raise_error(ContractError, /Actual: nil/)
387
+ end
388
+
389
+ it "should succeed for maybe proc with no proc" do
390
+ expect do
391
+ @o.maybe_call(5)
392
+ end.to_not raise_error
393
+ end
394
+
395
+ it "should succeed for maybe proc with proc" do
396
+ expect do
397
+ @o.maybe_call(5) do
398
+ 2 + 2
399
+ end
400
+ end.to_not raise_error
401
+ end
402
+
403
+ it "should fail for maybe proc with invalid input" do
404
+ expect do
405
+ @o.maybe_call("bad")
406
+ end.to raise_error(ContractError)
407
+ end
408
+
409
+ describe "varargs are given with a maybe block" do
410
+ it "when a block is passed in, varargs should be correct" do
411
+ expect(@o.maybe_call(1, 2, 3) { 1 + 1 }).to eq([1, 2, 3])
412
+ end
413
+
414
+ it "when a block is NOT passed in, varargs should still be correct" do
415
+ expect(@o.maybe_call(1, 2, 3)).to eq([1, 2, 3])
416
+ end
417
+ end
418
+ end
419
+
420
+ describe "varargs" do
421
+ it "should pass for correct input" do
422
+ expect do
423
+ @o.sum(1, 2, 3)
424
+ end.to_not raise_error
425
+ end
426
+
427
+ it "should fail for incorrect input" do
428
+ expect do
429
+ @o.sum(1, 2, "bad")
430
+ end.to raise_error(ContractError)
431
+ end
432
+
433
+ it "should work with arg before splat" do
434
+ expect do
435
+ @o.arg_then_splat(3, "hello", "world")
436
+ end.to_not raise_error
437
+ end
438
+ end
439
+
440
+ describe "varargs with block" do
441
+ it "should pass for correct input" do
442
+ expect do
443
+ @o.with_partial_sums(1, 2, 3) do |partial_sum|
444
+ 2 * partial_sum + 1
445
+ end
446
+ end.not_to raise_error
447
+ expect do
448
+ @o.with_partial_sums_contracted(1, 2, 3) do |partial_sum|
449
+ 2 * partial_sum + 1
450
+ end
451
+ end.not_to raise_error
452
+ end
453
+
454
+ it "should fail for incorrect input" do
455
+ expect do
456
+ @o.with_partial_sums(1, 2, "bad") do |partial_sum|
457
+ 2 * partial_sum + 1
458
+ end
459
+ end.to raise_error(ContractError, /Actual: "bad"/)
460
+
461
+ expect do
462
+ @o.with_partial_sums(1, 2, 3)
463
+ end.to raise_error(ContractError, /Actual: nil/)
464
+
465
+ expect do
466
+ @o.with_partial_sums(1, 2, 3, lambda { |x| x })
467
+ end.to raise_error(ContractError, /Actual: nil/)
468
+ end
469
+
470
+ context "when block has Func contract" do
471
+ it "should fail for incorrect input" do
472
+ expect do
473
+ @o.with_partial_sums_contracted(1, 2, "bad") { |partial_sum| 2 * partial_sum + 1 }
474
+ end.to raise_error(ContractError, /Actual: "bad"/)
475
+
476
+ expect do
477
+ @o.with_partial_sums_contracted(1, 2, 3)
478
+ end.to raise_error(ContractError, /Actual: nil/)
479
+ end
480
+ end
481
+ end
482
+
483
+ describe "contracts on functions" do
484
+ it "should pass for a function that passes the contract" do
485
+ expect { @o.map([1, 2, 3], lambda { |x| x + 1 }) }.to_not raise_error
486
+ end
487
+
488
+ it "should pass for a function that passes the contract as in tutorial" do
489
+ expect { @o.tutorial_map([1, 2, 3], lambda { |x| x + 1 }) }.to_not raise_error
490
+ end
491
+
492
+ it "should fail for a function that doesn't pass the contract" do
493
+ expect { @o.map([1, 2, 3], lambda { |_| "bad return value" }) }.to raise_error(ContractError)
494
+ end
495
+
496
+ it "should pass for a function that passes the contract with weak other args" do
497
+ expect { @o.map_plain(["hello", "joe"], lambda { |x| x.size }) }.to_not raise_error
498
+ end
499
+
500
+ it "should fail for a function that doesn't pass the contract with weak other args" do
501
+ expect { @o.map_plain(["hello", "joe"], lambda { |_| nil }) }.to raise_error(ContractError)
502
+ end
503
+
504
+ it "should fail for a returned function that doesn't pass the contract" do
505
+ expect { @o.lambda_with_wrong_return.call("hello") }.to raise_error(ContractError)
506
+ end
507
+
508
+ it "should fail for a returned function that receives the wrong argument type" do
509
+ expect { @o.lambda_with_correct_return.call(123) }.to raise_error(ContractError)
510
+ end
511
+
512
+ it "should not fail for a returned function that passes the contract" do
513
+ expect { @o.lambda_with_correct_return.call("hello") }.to_not raise_error
514
+ end
515
+ end
516
+
517
+ describe "default args to functions" do
518
+ it "should work for a function call that relies on default args" do
519
+ expect { @o.default_args }.to_not raise_error
520
+ expect { @o.default_args("foo") }.to raise_error(ContractError)
521
+ end
522
+ end
523
+
524
+ describe "classes" do
525
+ it "should not fail for an object that is the exact type as the contract" do
526
+ p = Parent.new
527
+ expect { @o.id_(p) }.to_not raise_error
528
+ end
529
+
530
+ it "should not fail for an object that is a subclass of the type in the contract" do
531
+ c = Child.new
532
+ expect { @o.id_(c) }.to_not raise_error
533
+ end
534
+ end
535
+
536
+ describe "failure callbacks" do
537
+ before :each do
538
+ ::Contract.override_failure_callback do |_data|
539
+ should_call
540
+ end
541
+ end
542
+
543
+ context "when failure_callback returns false" do
544
+ let(:should_call) { false }
545
+
546
+ it "does not call a function for which the contract fails" do
547
+ res = @o.double("bad")
548
+ expect(res).to eq(nil)
549
+ end
550
+ end
551
+
552
+ context "when failure_callback returns true" do
553
+ let(:should_call) { true }
554
+
555
+ it "calls a function for which the contract fails" do
556
+ res = @o.double("bad")
557
+ expect(res).to eq("badbad")
558
+ end
559
+ end
560
+ end
561
+
562
+ describe "module contracts" do
563
+ it "passes for instance of class including module" do
564
+ expect(
565
+ ModuleContractExample.hello(ModuleContractExample::AClassWithModule.new)
566
+ ).to eq(:world)
567
+ end
568
+
569
+ it "passes for instance of class including inherited module" do
570
+ expect(
571
+ ModuleContractExample.hello(ModuleContractExample::AClassWithInheritedModule.new)
572
+ ).to eq(:world)
573
+ end
574
+
575
+ it "does not pass for instance of class not including module" do
576
+ expect do
577
+ ModuleContractExample.hello(ModuleContractExample::AClassWithoutModule.new)
578
+ end.to raise_error(ContractError, /Expected: ModuleContractExample::AModule/)
579
+ end
580
+
581
+ it "does not pass for instance of class including another module" do
582
+ expect do
583
+ ModuleContractExample.hello(ModuleContractExample::AClassWithAnotherModule.new)
584
+ end.to raise_error(ContractError, /Expected: ModuleContractExample::AModule/)
585
+ end
586
+
587
+ it "passes for instance of class including both modules" do
588
+ expect(
589
+ ModuleContractExample.hello(ModuleContractExample::AClassWithBothModules.new)
590
+ ).to eq(:world)
591
+ end
592
+ end
593
+
594
+ describe "Contracts to_s formatting in expected" do
595
+ def not_s(match)
596
+ Regexp.new "[^\"\']#{match}[^\"\']"
597
+ end
598
+
599
+ def delim(match)
600
+ "(#{match})"
601
+ end
602
+
603
+ it "should not stringify native types" do
604
+ expect do
605
+ @o.constanty("bad", nil)
606
+ end.to raise_error(ContractError, not_s(123))
607
+
608
+ expect do
609
+ @o.constanty(123, "bad")
610
+ end.to raise_error(ContractError, not_s(nil))
611
+ end
612
+
613
+ it "should contain to_s representation within a Hash contract" do
614
+ expect do
615
+ @o.hash_complex_contracts({ :rigged => "bad" })
616
+ end.to raise_error(ContractError, not_s(delim "TrueClass or FalseClass"))
617
+ end
618
+
619
+ it "should contain to_s representation within a nested Hash contract" do
620
+ expect do
621
+ @o.nested_hash_complex_contracts({
622
+ :rigged => true,
623
+ :contents => {
624
+ :kind => 0,
625
+ :total => 42,
626
+ },
627
+ })
628
+ end.to raise_error(ContractError, not_s(delim "String or Symbol"))
629
+ end
630
+
631
+ it "should contain to_s representation within an Array contract" do
632
+ expect do
633
+ @o.array_complex_contracts(["bad"])
634
+ end.to raise_error(ContractError, not_s(delim "TrueClass or FalseClass"))
635
+ end
636
+
637
+ it "should contain to_s representation within a nested Array contract" do
638
+ expect do
639
+ @o.nested_array_complex_contracts([true, [0]])
640
+ end.to raise_error(ContractError, not_s(delim "String or Symbol"))
641
+ end
642
+
643
+ it "should wrap and pretty print for long param contracts" do
644
+ expect do
645
+ @o.long_array_param_contracts(true)
646
+ end.to(
647
+ raise_error(
648
+ ParamContractError,
649
+ /\[\(String or Symbol\),\n \(String or Symbol\),/
650
+ )
651
+ )
652
+ end
653
+
654
+ it "should wrap and pretty print for long return contracts" do
655
+ expect do
656
+ @o.long_array_return_contracts
657
+ end.to(
658
+ raise_error(
659
+ ReturnContractError,
660
+ /\[\(String or Symbol\),\n \(String or Symbol\),/
661
+ )
662
+ )
663
+ end
664
+
665
+ it "should not contain Contracts:: module prefix" do
666
+ expect do
667
+ @o.double("bad")
668
+ end.to raise_error(ContractError, /Expected: Num/)
669
+ end
670
+
671
+ it "should still show nils, not just blank space" do
672
+ expect do
673
+ @o.no_args("bad")
674
+ end.to raise_error(ContractError, /Expected: nil/)
675
+ end
676
+
677
+ it 'should show empty quotes as ""' do
678
+ expect do
679
+ @o.no_args("")
680
+ end.to raise_error(ContractError, /Actual: ""/)
681
+ end
682
+
683
+ it "should not use custom to_s if empty string" do
684
+ expect do
685
+ @o.using_empty_contract("bad")
686
+ end.to raise_error(ContractError, /Expected: EmptyCont/)
687
+ end
688
+ end
689
+
690
+ describe "functype" do
691
+ it "should correctly print out a instance method's type" do
692
+ expect(@o.functype(:double)).not_to eq("")
693
+ end
694
+
695
+ it "should correctly print out a class method's type" do
696
+ expect(A.functype(:a_class_method)).not_to eq("")
697
+ end
698
+ end
699
+
700
+ describe "private methods" do
701
+ it "should raise an error if you try to access a private method" do
702
+ expect { @o.a_private_method }.to raise_error(NoMethodError, /private/)
703
+ end
704
+
705
+ it "should raise an error if you try to access a private method" do
706
+ expect { @o.a_really_private_method }.to raise_error(NoMethodError, /private/)
707
+ end
708
+ end
709
+
710
+ describe "protected methods" do
711
+ it "should raise an error if you try to access a protected method" do
712
+ expect { @o.a_protected_method }.to raise_error(NoMethodError, /protected/)
713
+ end
714
+
715
+ it "should raise an error if you try to access a protected method" do
716
+ expect { @o.a_really_protected_method }.to raise_error(NoMethodError, /protected/)
717
+ end
718
+ end
719
+
720
+ describe "inherited methods" do
721
+ it "should apply the contract to an inherited method" do
722
+ c = Child.new
723
+ expect { c.double(2) }.to_not raise_error
724
+ expect { c.double("asd") }.to raise_error ParamContractError
725
+ end
726
+ end
727
+
728
+ describe "classes with extended modules" do
729
+ let(:klass) do
730
+ m = Module.new do
731
+ include Contracts::Core
732
+ end
733
+
734
+ Class.new do
735
+ include Contracts::Core
736
+ extend m
737
+
738
+ Contract String => nil
739
+ def foo(x)
740
+ end
741
+ end
742
+ end
743
+
744
+ it "is possible to define it" do
745
+ expect { klass }.not_to raise_error
746
+ end
747
+
748
+ it "works correctly with methods with passing contracts" do
749
+ expect { klass.new.foo("bar") }.not_to raise_error
750
+ end
751
+
752
+ it "works correctly with methods with passing contracts" do
753
+ expect { klass.new.foo(42) }.to raise_error(ContractError, /Expected: String/)
754
+ end
755
+
756
+ # See the discussion on this issue:
757
+ # https://github.com/egonSchiele/contracts.ruby/issues/229
758
+ it "should not fail with 'undefined method 'Contract''" do
759
+ expect do
760
+ class ModuleThenContracts
761
+ include ModuleWithContracts
762
+ include Contracts::Core
763
+
764
+ # fails on this line
765
+ Contract C::Num => C::Num
766
+ def double(x)
767
+ x * 2
768
+ end
769
+ end
770
+ end.to_not raise_error
771
+ end
772
+ end
773
+ end