ward 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. data/.document +5 -0
  2. data/.gitignore +28 -0
  3. data/LICENSE +19 -0
  4. data/README.markdown +99 -0
  5. data/Rakefile +47 -0
  6. data/VERSION +1 -0
  7. data/features/acceptance_matcher.feature +78 -0
  8. data/features/attribute_keyword.feature +13 -0
  9. data/features/close_to_matcher.feature +130 -0
  10. data/features/context_arguments.feature +47 -0
  11. data/features/equal_to_matcher.feature +25 -0
  12. data/features/error_messages.feature +69 -0
  13. data/features/external_validation.feature +15 -0
  14. data/features/has_matcher.feature +72 -0
  15. data/features/has_matcher_initialized_with_expectation.feature +94 -0
  16. data/features/has_matcher_relativities.feature +171 -0
  17. data/features/include_matcher.feature +28 -0
  18. data/features/is_keyword.feature +42 -0
  19. data/features/is_not_keyword.feature +62 -0
  20. data/features/match_matcher.feature +49 -0
  21. data/features/multiple_validators.feature +29 -0
  22. data/features/nil_matcher.feature +25 -0
  23. data/features/predicate_matcher.feature +23 -0
  24. data/features/present_matcher.feature +59 -0
  25. data/features/satisfy_matcher.feature +80 -0
  26. data/features/scenario_validation.feature +81 -0
  27. data/features/step_definitions/external_validation_steps.rb +69 -0
  28. data/features/step_definitions/generic_validation_steps.rb +33 -0
  29. data/features/step_definitions/object_definition_steps.rb +43 -0
  30. data/features/support/env.rb +12 -0
  31. data/features/support/object_builder.rb +33 -0
  32. data/features/support/struct.rb +38 -0
  33. data/lang/en.yml +56 -0
  34. data/lib/ward.rb +26 -0
  35. data/lib/ward/context.rb +70 -0
  36. data/lib/ward/context_chain.rb +87 -0
  37. data/lib/ward/dsl.rb +7 -0
  38. data/lib/ward/dsl/validation_block.rb +73 -0
  39. data/lib/ward/dsl/validation_builder.rb +190 -0
  40. data/lib/ward/errors.rb +213 -0
  41. data/lib/ward/matchers.rb +97 -0
  42. data/lib/ward/matchers/acceptance.rb +43 -0
  43. data/lib/ward/matchers/close_to.rb +60 -0
  44. data/lib/ward/matchers/equal_to.rb +33 -0
  45. data/lib/ward/matchers/has.rb +283 -0
  46. data/lib/ward/matchers/include.rb +54 -0
  47. data/lib/ward/matchers/match.rb +29 -0
  48. data/lib/ward/matchers/matcher.rb +68 -0
  49. data/lib/ward/matchers/nil.rb +30 -0
  50. data/lib/ward/matchers/predicate.rb +31 -0
  51. data/lib/ward/matchers/present.rb +56 -0
  52. data/lib/ward/matchers/satisfy.rb +65 -0
  53. data/lib/ward/spec.rb +17 -0
  54. data/lib/ward/spec/matcher_matcher.rb +114 -0
  55. data/lib/ward/support.rb +7 -0
  56. data/lib/ward/support/basic_object.rb +55 -0
  57. data/lib/ward/support/result.rb +49 -0
  58. data/lib/ward/validator.rb +147 -0
  59. data/lib/ward/validator_set.rb +115 -0
  60. data/lib/ward/version.rb +3 -0
  61. data/spec/lib/has_matcher_relativity_examples.rb +15 -0
  62. data/spec/lib/have_public_method_defined.rb +22 -0
  63. data/spec/rcov.opts +8 -0
  64. data/spec/spec.opts +4 -0
  65. data/spec/spec_helper.rb +19 -0
  66. data/spec/ward/context_chain_spec.rb +178 -0
  67. data/spec/ward/context_spec.rb +57 -0
  68. data/spec/ward/dsl/validation_block_spec.rb +27 -0
  69. data/spec/ward/dsl/validation_builder_spec.rb +212 -0
  70. data/spec/ward/errors_spec.rb +149 -0
  71. data/spec/ward/matchers/acceptance_spec.rb +16 -0
  72. data/spec/ward/matchers/close_to_spec.rb +57 -0
  73. data/spec/ward/matchers/equal_to_spec.rb +16 -0
  74. data/spec/ward/matchers/has_spec.rb +175 -0
  75. data/spec/ward/matchers/include_spec.rb +41 -0
  76. data/spec/ward/matchers/match_spec.rb +21 -0
  77. data/spec/ward/matchers/matcher_spec.rb +54 -0
  78. data/spec/ward/matchers/nil_spec.rb +16 -0
  79. data/spec/ward/matchers/predicate_spec.rb +19 -0
  80. data/spec/ward/matchers/present_spec.rb +16 -0
  81. data/spec/ward/matchers/satisfy_spec.rb +68 -0
  82. data/spec/ward/matchers_spec.rb +51 -0
  83. data/spec/ward/spec/have_public_method_defined_spec.rb +31 -0
  84. data/spec/ward/spec/matcher_matcher_spec.rb +217 -0
  85. data/spec/ward/validator_set_spec.rb +178 -0
  86. data/spec/ward/validator_spec.rb +264 -0
  87. data/tasks/features.rake +15 -0
  88. data/tasks/rcov.rake +24 -0
  89. data/tasks/spec.rake +18 -0
  90. data/tasks/yard.rake +9 -0
  91. data/ward.gemspec +176 -0
  92. metadata +239 -0
@@ -0,0 +1,178 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ # @todo
4
+ # Replace all cases of ValidatorSet.new with the DSL.
5
+
6
+ describe Ward::ValidatorSet do
7
+ subject { Ward::ValidatorSet }
8
+
9
+ #
10
+ # .build
11
+ #
12
+
13
+ describe '.build' do
14
+ describe 'when no initial set is provided' do
15
+ it 'should add the validators to the set' do
16
+ dsl = Ward::ValidatorSet.build do |object|
17
+ object.name.matches(/abc/)
18
+ object.name.length.is.equal_to(3)
19
+ end
20
+
21
+ # ValidatorSet doesn't have a size method, but does implement Enumerable
22
+ dsl.inject(0) { |c, *| c += 1 }.should == 2
23
+ end
24
+ end # when no initial set is provided
25
+
26
+ describe 'when an initial set is provided' do
27
+ before(:all) do
28
+ @initial = Ward::ValidatorSet.build do |object|
29
+ object.name.matches(/abc/)
30
+ object.name.length.is.equal_to(3)
31
+ end
32
+
33
+ @set = Ward::ValidatorSet.build(@initial) do |object|
34
+ object.name.present
35
+ end
36
+ end
37
+
38
+ it 'should add the new validators to a copy of the initial set' do
39
+ # ValidatorSet doesn't have a size method, but does implement Enumerable
40
+ @set.inject(0) { |c, *| c += 1 }.should == 3
41
+ end
42
+
43
+ it 'should return a copy of the initial set' do
44
+ @set.should_not == @initial
45
+ @initial.inject(0) { |c, *| c += 1 }.should == 2
46
+ end
47
+ end # when an initial set is provided
48
+ end # .build
49
+
50
+ #
51
+ # enumeration
52
+ #
53
+
54
+ it 'should be enumerable' do
55
+ Ward::ValidatorSet.ancestors.should include(Enumerable)
56
+ end
57
+
58
+ it { should have_public_method_defined(:each) }
59
+ it { should have_public_method_defined(:to_a) }
60
+
61
+ #
62
+ # push
63
+ #
64
+
65
+ it { should have_public_method_defined(:push) }
66
+ it { should have_public_method_defined(:<<) }
67
+
68
+ describe '#push' do
69
+ it 'should add validator to the set' do
70
+ set = Ward::ValidatorSet.new
71
+ new_validator = Ward::Validator.new(nil, nil)
72
+ set.to_a.should be_empty
73
+ set.push(new_validator)
74
+ set.should include(new_validator)
75
+ end
76
+ end
77
+
78
+ #
79
+ # valid?
80
+ #
81
+
82
+ it { should have_public_method_defined(:valid?) }
83
+
84
+ describe '#valid?' do
85
+ describe 'with two validators, both of which pass' do
86
+ it 'should return true' do
87
+ set = Ward::ValidatorSet.build do |object|
88
+ object.length.is.equal_to(1)
89
+ object.length.is.present
90
+ end
91
+
92
+ set.valid?('a').should be_true
93
+ end
94
+ end
95
+
96
+ describe 'with two validators, both of which fail' do
97
+ before(:each) do
98
+ @set = Ward::ValidatorSet.build do |object|
99
+ object.length.is.equal_to(1)
100
+ object.length.is.equal_to(2)
101
+ end
102
+ end
103
+
104
+ it 'should return false' do
105
+ @set.valid?('').should be_false
106
+ end
107
+
108
+ it 'should run all the validators' do
109
+ @set.each do |validator|
110
+ validator.should_receive(:validate).and_return([false])
111
+ end
112
+
113
+ lambda { @set.valid?('') }.should_not raise_exception
114
+ end
115
+ end
116
+
117
+ describe 'with two validators, one of which fails' do
118
+ before(:each) do
119
+ @set = Ward::ValidatorSet.build do |object|
120
+ object.length.is.equal_to(1) # false
121
+ object.length.is.equal_to(2) # true
122
+ end
123
+ end
124
+
125
+ it 'should return false' do
126
+ @set.valid?('ab').should be_false
127
+ end
128
+
129
+ it 'should run all the validators' do
130
+ @set.to_a[0].should_receive(:validate).and_return([false])
131
+ @set.to_a[1].should_receive(:validate).and_return([true])
132
+
133
+ lambda { @set.valid?('ab') }.should_not raise_exception
134
+ end
135
+ end
136
+ end # valid?
137
+
138
+ #
139
+ # merge!
140
+ #
141
+
142
+ it { should have_public_method_defined(:merge!) }
143
+
144
+ describe '#merge!' do
145
+ before(:each) do
146
+ @set = Ward::ValidatorSet.build do |object|
147
+ object.length.is.equal_to(1)
148
+ end
149
+ end
150
+
151
+ it 'should return self' do
152
+ @set.merge!(Ward::ValidatorSet.new).should == @set
153
+ end
154
+
155
+ it "should add the argument's validators to the receiver" do
156
+ other = Ward::ValidatorSet.new
157
+ other << Ward::Validator.new(nil, nil)
158
+ running = lambda { @set.merge!(other) }
159
+
160
+ # select is used here since ValidatorSet doesn't have a size method, but
161
+ # does implement Enumerable.
162
+ running.should change { @set.select { |*| true }.size }.by(1)
163
+ end
164
+
165
+ it 'should not merge validators already contained in the set' do
166
+ pending do
167
+ other = Ward::ValidatorSet.new
168
+ other << @set.to_a.first.dup
169
+ running = lambda { @set.merge!(other) }
170
+
171
+ # select is used here since ValidatorSet doesn't have a size method, but
172
+ # does implement Enumerable.
173
+ running.should_not change { @set.select { |*| true }.size }
174
+ end
175
+ end
176
+ end
177
+
178
+ end
@@ -0,0 +1,264 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ describe Ward::Validator do
4
+ subject { Ward::Validator }
5
+
6
+ #
7
+ # initialize
8
+ #
9
+
10
+ describe '#initialize' do
11
+ describe 'scenarios' do
12
+ it 'should be [:default] when no scenarios option is given' do
13
+ Ward::Validator.new(nil, nil).scenarios.should == [:default]
14
+ end
15
+
16
+ it 'should be [:scenario] when the scenarios option is [:scenario]' do
17
+ validator = Ward::Validator.new(nil, nil, :scenarios => [:scenario])
18
+ validator.scenarios.should == [:scenario]
19
+ end
20
+
21
+ it 'should be [:scenario] when the scenarios option is :scenario' do
22
+ validator = Ward::Validator.new(nil, nil, :scenarios => :scenario)
23
+ validator.scenarios.should == [:scenario]
24
+ end
25
+ end
26
+ end
27
+
28
+ #
29
+ # context
30
+ #
31
+
32
+ it { should have_public_method_defined(:context) }
33
+
34
+ describe '#context' do
35
+ before(:all) do
36
+ @context = Ward::Validator.new('context', 'matcher').context
37
+ end
38
+
39
+ it 'should return the context' do
40
+ @context.should == 'context'
41
+ end
42
+ end
43
+
44
+ #
45
+ # matcher
46
+ #
47
+
48
+ it { should have_public_method_defined(:matcher) }
49
+
50
+ describe '#matcher' do
51
+ before(:all) do
52
+ @matcher = Ward::Validator.new('context', 'matcher').matcher
53
+ end
54
+
55
+ it 'should return the matcher' do
56
+ @matcher.should == 'matcher'
57
+ end
58
+ end
59
+
60
+ #
61
+ # validate
62
+ #
63
+
64
+ it { should have_public_method_defined(:validate) }
65
+
66
+ describe '#validate' do
67
+ describe 'when the validator is positive' do
68
+ before(:all) do
69
+ @validator = Ward::Validator.new(Ward::Context.new(:name),
70
+ Ward::Matchers::Nil.new, :negative => false)
71
+ end
72
+
73
+ describe 'when the matcher passes' do
74
+ it 'should return true' do
75
+ @validator.validate(mock(:name => nil)).should be_true
76
+ end
77
+ end
78
+
79
+ describe 'when the matcher fails' do
80
+ before(:all) do
81
+ @result = @validator.validate(mock(:name => ''))
82
+ end
83
+
84
+ it 'should return Array[false, ...]' do
85
+ @result.first.should be_false
86
+ end
87
+ end
88
+
89
+ describe 'when the matcher fails and return an error' do
90
+ before(:all) do
91
+ @validator.matcher.stub(:matches?).and_return([false, :error])
92
+ @result = @validator.validate(mock(:name => ''))
93
+ end
94
+
95
+ it 'should return Array[false, ...]' do
96
+ @result.first.should be_false
97
+ end
98
+ end
99
+
100
+ # Rubinius.
101
+ describe 'when the matcher returns a non-array which responds to #to_a' do
102
+ before(:all) do
103
+ @validator.matcher.stub(:matches?).and_return(mock(:to_a => []))
104
+ @result = @validator.validate(mock(:name => ''))
105
+ end
106
+
107
+ it 'should return Array[true, ...]' do
108
+ @result.first.should be_true
109
+ end
110
+
111
+ it 'should return Array[..., nil]' do
112
+ @result[1].should be_nil
113
+ end
114
+ end
115
+ end # when the matcher is positive
116
+
117
+ describe 'when the validator is negative' do
118
+ before(:all) do
119
+ @validator = Ward::Validator.new(Ward::Context.new(:name),
120
+ Ward::Matchers::Nil.new, :negative => true)
121
+ end
122
+
123
+ describe 'when the matcher passes' do
124
+ it 'should return Array[false, ...]' do
125
+ @validator.validate(mock(:name => nil)).first.should be_false
126
+ end
127
+ end
128
+
129
+ describe 'when the matcher fails' do
130
+ before(:all) do
131
+ @result = @validator.validate(mock(:name => ''))
132
+ end
133
+
134
+ it 'should return Array[true, ...]' do
135
+ @result.first.should be_true
136
+ end
137
+ end
138
+
139
+ describe 'when the matcher fails and return an error' do
140
+ before(:all) do
141
+ @validator.matcher.stub(:matches?).and_return([false, :error])
142
+ @result = @validator.validate(mock(:name => ''))
143
+ end
144
+
145
+ it 'should return Array[true, ...]' do
146
+ @result.first.should be_true
147
+ end
148
+ end
149
+
150
+ # Rubinius.
151
+ describe 'when the matcher returns a non-array which responds to #to_a' do
152
+ before(:all) do
153
+ @validator.matcher.stub(:matches?).and_return(mock(:to_a => []))
154
+ @result = @validator.validate(mock(:name => ''))
155
+ end
156
+
157
+ it 'should return Array[false, ...]' do
158
+ @result.first.should be_false
159
+ end
160
+
161
+ it 'should return Array[..., an_error]' do
162
+ @result[1].should_not be_nil
163
+ end
164
+ end
165
+ end # when the matcher is negative
166
+
167
+ #
168
+ # argument counts
169
+ #
170
+
171
+ describe 'when matcher #matches? accepts' do
172
+ describe 'one argument' do
173
+ it 'should supply the attribute' do
174
+ value = ''
175
+
176
+ Ward::Validator.new(Ward::Context.new(:name),
177
+ Class.new do
178
+ def matches?(arg1)
179
+ arg1.should == ''
180
+ end
181
+ end.new
182
+ ).validate(mock(:name => value))
183
+ end
184
+ end
185
+
186
+ describe 'two arguments' do
187
+ it 'should supply the attribute and record' do
188
+ value = ''
189
+ record = mock(:name => value)
190
+
191
+ Ward::Validator.new(Ward::Context.new(:name),
192
+ Class.new do
193
+ include Spec::Matchers
194
+ def matches?(arg1, arg2)
195
+ arg1.should == ''
196
+ arg2.should be_a(Spec::Mocks::Mock)
197
+ end
198
+ end.new
199
+ ).validate(record)
200
+ end
201
+ end
202
+ end # when matcher #matches? accepts (one|two) arguments?
203
+
204
+ end # validate
205
+
206
+ #
207
+ # scenarios
208
+ #
209
+
210
+ it { should have_public_method_defined(:scenarios) }
211
+
212
+ describe '#scenarios' do
213
+ before(:all) do
214
+ @matcher = Ward::Validator.new('context', 'matcher').scenarios
215
+ end
216
+
217
+ it 'should return an array' do
218
+ @matcher.should be_an(Array)
219
+ end
220
+ end
221
+
222
+ #
223
+ # scenario?
224
+ #
225
+
226
+ it { should have_public_method_defined(:scenario?) }
227
+
228
+ describe '#scenario?' do
229
+ it 'should return true when the validator exists in a given scenario' do
230
+ validator = Ward::Validator.new(nil, nil, :scenarios => [:update])
231
+ validator.scenario?(:update).should be_true
232
+ end
233
+
234
+ it 'should return true when the validator does not exist in a given scenario' do
235
+ validator = Ward::Validator.new(nil, nil)
236
+ validator.scenario?(:update).should be_false
237
+ end
238
+ end
239
+
240
+ #
241
+ # negative?
242
+ #
243
+
244
+ it { should have_public_method_defined(:negative?) }
245
+
246
+ describe 'negative?' do
247
+ it 'should return true when the validator requires that the matcher ' \
248
+ 'does not match the actual value' do
249
+ validator = Ward::Validator.new(nil, nil, :negative => true)
250
+ validator.should be_negative
251
+ end
252
+
253
+ it 'should return false when the validator requires that the matcher ' \
254
+ 'matches the actual value' do
255
+ validator = Ward::Validator.new(nil, nil, :negative => false)
256
+ validator.should_not be_negative
257
+
258
+ validator = Ward::Validator.new(nil, nil)
259
+ validator.should_not be_negative
260
+ end
261
+ end
262
+
263
+
264
+ end
@@ -0,0 +1,15 @@
1
+ begin
2
+ require 'cucumber/rake/task'
3
+
4
+ Cucumber::Rake::Task.new(:features) do |features|
5
+ features.cucumber_opts = '--format progress --tag ~@pending'
6
+ end
7
+
8
+ task :features => :check_dependencies
9
+
10
+ rescue LoadError
11
+ task :features do
12
+ abort "Cucumber is not available. In order to run features, you must: " \
13
+ "gem install cucumber"
14
+ end
15
+ end