objective 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/lib/objective/allow.rb +10 -0
  3. data/lib/objective/deny.rb +10 -0
  4. data/lib/objective/discard.rb +10 -0
  5. data/lib/objective/errors/error_array.rb +21 -0
  6. data/lib/objective/errors/error_atom.rb +27 -0
  7. data/lib/objective/errors/error_hash.rb +65 -0
  8. data/lib/objective/errors/error_message_creator.rb +46 -0
  9. data/lib/objective/errors/validation_error.rb +14 -0
  10. data/lib/objective/filter.rb +166 -0
  11. data/lib/objective/filters/any_filter.rb +7 -0
  12. data/lib/objective/filters/array_filter.rb +49 -0
  13. data/lib/objective/filters/boolean_filter.rb +21 -0
  14. data/lib/objective/filters/date_filter.rb +29 -0
  15. data/lib/objective/filters/decimal_filter.rb +46 -0
  16. data/lib/objective/filters/duck_filter.rb +18 -0
  17. data/lib/objective/filters/file_filter.rb +22 -0
  18. data/lib/objective/filters/float_filter.rb +45 -0
  19. data/lib/objective/filters/hash_filter.rb +42 -0
  20. data/lib/objective/filters/integer_filter.rb +60 -0
  21. data/lib/objective/filters/model_filter.rb +23 -0
  22. data/lib/objective/filters/root_filter.rb +54 -0
  23. data/lib/objective/filters/string_filter.rb +30 -0
  24. data/lib/objective/filters/time_filter.rb +30 -0
  25. data/lib/objective/filters.rb +140 -0
  26. data/lib/objective/none.rb +10 -0
  27. data/lib/objective/outcome.rb +5 -0
  28. data/lib/objective/unit.rb +103 -0
  29. data/lib/objective.rb +53 -0
  30. data/spec/default_spec.rb +33 -0
  31. data/spec/errors_spec.rb +135 -0
  32. data/spec/filters/any_filter_spec.rb +34 -0
  33. data/spec/filters/array_filter_spec.rb +195 -0
  34. data/spec/filters/boolean_filter_spec.rb +66 -0
  35. data/spec/filters/date_filter_spec.rb +145 -0
  36. data/spec/filters/decimal_filter_spec.rb +199 -0
  37. data/spec/filters/duck_filter_spec.rb +49 -0
  38. data/spec/filters/file_filter_spec.rb +93 -0
  39. data/spec/filters/float_filter_spec.rb +140 -0
  40. data/spec/filters/hash_filter_spec.rb +65 -0
  41. data/spec/filters/integer_filter_spec.rb +150 -0
  42. data/spec/filters/model_filter_spec.rb +98 -0
  43. data/spec/filters/root_filter_spec.rb +113 -0
  44. data/spec/filters/string_filter_spec.rb +251 -0
  45. data/spec/filters/time_filter_spec.rb +123 -0
  46. data/spec/inheritance_spec.rb +36 -0
  47. data/spec/simple_unit.rb +18 -0
  48. data/spec/spec_helper.rb +9 -0
  49. data/spec/unit_spec.rb +244 -0
  50. metadata +167 -0
@@ -0,0 +1,251 @@
1
+ # frozen_string_literal: true
2
+ require 'spec_helper'
3
+
4
+ describe 'Objective::Filters::StringFilter' do
5
+ it 'allows valid strings' do
6
+ sf = Objective::Filters::StringFilter.new
7
+ result = sf.feed('hello')
8
+ assert_equal 'hello', result.inputs
9
+ assert_nil result.errors
10
+ end
11
+
12
+ it 'allows symbols' do
13
+ sf = Objective::Filters::StringFilter.new
14
+ result = sf.feed(:hello)
15
+ assert_equal 'hello', result.inputs
16
+ assert_nil result.errors
17
+ end
18
+
19
+ it 'allows fixnums' do
20
+ sf = Objective::Filters::StringFilter.new
21
+ result = sf.feed(1)
22
+ assert_equal '1', result.inputs
23
+ assert_nil result.errors
24
+ end
25
+
26
+ it 'allows bignums' do
27
+ sf = Objective::Filters::StringFilter.new
28
+ result = sf.feed(11_111_111_111_111_111_111)
29
+ assert_equal '11111111111111111111', result.inputs
30
+ assert_nil result.errors
31
+ end
32
+
33
+ it 'disallows non-string' do
34
+ sf = Objective::Filters::StringFilter.new
35
+ [['foo'], { a: '1' }, Object.new].each do |thing|
36
+ result = sf.feed(thing)
37
+ assert_equal :string, result.errors
38
+ end
39
+ end
40
+
41
+ it 'strips' do
42
+ sf = Objective::Filters::StringFilter.new(:s, strip: true)
43
+ result = sf.feed(' hello ')
44
+ assert_equal 'hello', result.inputs
45
+ assert_nil result.errors
46
+ end
47
+
48
+ it 'doesn\'t strip' do
49
+ sf = Objective::Filters::StringFilter.new(:s, strip: false)
50
+ result = sf.feed(' hello ')
51
+ assert_equal ' hello ', result.inputs
52
+ assert_nil result.errors
53
+ end
54
+
55
+ it 'considers nil to be invalid' do
56
+ sf = Objective::Filters::StringFilter.new(:s)
57
+ result = sf.feed(nil)
58
+ assert_nil result.inputs
59
+ assert_equal :nils, result.errors
60
+ end
61
+
62
+ it 'considers nil to be valid' do
63
+ sf = Objective::Filters::StringFilter.new(:s, nils: Objective::ALLOW)
64
+ result = sf.feed(nil)
65
+ assert_nil result.inputs
66
+ assert_nil result.errors
67
+ end
68
+
69
+ it 'considers empty strings to be invalid' do
70
+ sf = Objective::Filters::StringFilter.new(:s)
71
+ result = sf.feed('')
72
+ assert_equal '', result.inputs
73
+ assert_equal :empty, result.errors
74
+ end
75
+
76
+ it 'considers empty strings to be valid' do
77
+ sf = Objective::Filters::StringFilter.new(:s, empty: Objective::ALLOW)
78
+ result = sf.feed('')
79
+ assert_equal '', result.inputs
80
+ assert_nil result.errors
81
+ end
82
+
83
+ it 'considers stripped strings that are empty to be invalid' do
84
+ sf = Objective::Filters::StringFilter.new(:s)
85
+ result = sf.feed(' ')
86
+ assert_equal '', result.inputs
87
+ assert_equal :empty, result.errors
88
+ end
89
+
90
+ it 'considers strings that contain only unprintable characters to be invalid' do
91
+ sf = Objective::Filters::StringFilter.new(:s)
92
+ result = sf.feed("\u0000\u0000")
93
+ assert_equal '', result.inputs
94
+ assert_equal :empty, result.errors
95
+ end
96
+
97
+ it 'considers long strings to be invalid' do
98
+ sf = Objective::Filters::StringFilter.new(:s, max: 5)
99
+ result = sf.feed('123456')
100
+ assert_equal '123456', result.inputs
101
+ assert_equal :max, result.errors
102
+ end
103
+
104
+ it 'considers long strings to be valid' do
105
+ sf = Objective::Filters::StringFilter.new(:s, max: 5)
106
+ result = sf.feed('12345')
107
+ assert_equal '12345', result.inputs
108
+ assert_nil result.errors
109
+ end
110
+
111
+ it 'considers short strings to be invalid' do
112
+ sf = Objective::Filters::StringFilter.new(:s, min: 5)
113
+ result = sf.feed('1234')
114
+ assert_equal '1234', result.inputs
115
+ assert_equal :min, result.errors
116
+ end
117
+
118
+ it 'considers short strings to be valid' do
119
+ sf = Objective::Filters::StringFilter.new(:s, min: 5)
120
+ result = sf.feed('12345')
121
+ assert_equal '12345', result.inputs
122
+ assert_nil result.errors
123
+ end
124
+
125
+ it 'considers bad matches to be invalid' do
126
+ sf = Objective::Filters::StringFilter.new(:s, matches: /aaa/)
127
+ result = sf.feed('aab')
128
+ assert_equal 'aab', result.inputs
129
+ assert_equal :matches, result.errors
130
+ end
131
+
132
+ it 'considers good matches to be valid' do
133
+ sf = Objective::Filters::StringFilter.new(:s, matches: /aaa/)
134
+ result = sf.feed('baaab')
135
+ assert_equal 'baaab', result.inputs
136
+ assert_nil result.errors
137
+ end
138
+
139
+ it 'considers non-inclusion to be invalid' do
140
+ sf = Objective::Filters::StringFilter.new(:s, in: %w(red blue green))
141
+ result = sf.feed('orange')
142
+ assert_equal 'orange', result.inputs
143
+ assert_equal :in, result.errors
144
+ end
145
+
146
+ it 'considers inclusion to be valid' do
147
+ sf = Objective::Filters::StringFilter.new(:s, in: %w(red blue green))
148
+ result = sf.feed('red')
149
+ assert_equal 'red', result.inputs
150
+ assert_nil result.errors
151
+ end
152
+
153
+ it 'converts symbols to strings' do
154
+ sf = Objective::Filters::StringFilter.new(:s)
155
+ result = sf.feed(:my_sym)
156
+ assert_equal 'my_sym', result.inputs
157
+ assert_nil result.errors
158
+ end
159
+
160
+ it 'converts integers to strings' do
161
+ sf = Objective::Filters::StringFilter.new(:s)
162
+ result = sf.feed(1)
163
+ assert_equal '1', result.inputs
164
+ assert_nil result.errors
165
+ end
166
+
167
+ it 'converts bigdecimals to strings' do
168
+ sf = Objective::Filters::StringFilter.new(:s)
169
+ result = sf.feed(BigDecimal.new('0.00000123'))
170
+ assert_equal '0.00000123', result.inputs
171
+ assert_nil result.errors
172
+ end
173
+
174
+ it 'converts bigdecimals to scientific notation strings' do
175
+ sf = Objective::Filters::StringFilter.new(:s, decimal_format: 'E')
176
+ result = sf.feed(BigDecimal.new('0.00000123'))
177
+ assert_equal '0.123e-5', result.inputs
178
+ assert_nil result.errors
179
+ end
180
+
181
+ it 'converts floats to strings' do
182
+ sf = Objective::Filters::StringFilter.new(:s)
183
+ result = sf.feed(0.0001)
184
+ assert_equal '0.0001', result.inputs
185
+ assert_nil result.errors
186
+ end
187
+
188
+ it 'converts booleans to strings' do
189
+ sf = Objective::Filters::StringFilter.new(:s)
190
+ result = sf.feed(true)
191
+ assert_equal 'true', result.inputs
192
+ assert_nil result.errors
193
+ end
194
+
195
+ it 'disallows symbols' do
196
+ sf = Objective::Filters::StringFilter.new(:s, strict: true)
197
+ result = sf.feed(:my_sym)
198
+ assert_equal :my_sym, result.inputs
199
+ assert_equal :string, result.errors
200
+ end
201
+
202
+ it 'disallows integers' do
203
+ sf = Objective::Filters::StringFilter.new(:s, strict: true)
204
+ result = sf.feed(1)
205
+ assert_equal 1, result.inputs
206
+ assert_equal :string, result.errors
207
+ end
208
+
209
+ it 'disallows bigdecimals' do
210
+ sf = Objective::Filters::StringFilter.new(:s, strict: true)
211
+ big_decimal = BigDecimal.new('0.0001')
212
+ result = sf.feed(big_decimal)
213
+ assert_equal big_decimal, result.inputs
214
+ assert_equal :string, result.errors
215
+ end
216
+
217
+ it 'disallows floats' do
218
+ sf = Objective::Filters::StringFilter.new(:s, strict: true)
219
+ result = sf.feed(0.0001)
220
+ assert_equal 0.0001, result.inputs
221
+ assert_equal :string, result.errors
222
+ end
223
+
224
+ it 'disallows booleans' do
225
+ sf = Objective::Filters::StringFilter.new(:s, strict: true)
226
+ result = sf.feed(true)
227
+ assert_equal true, result.inputs
228
+ assert_equal :string, result.errors
229
+ end
230
+
231
+ it 'removes unprintable characters' do
232
+ sf = Objective::Filters::StringFilter.new(:s, allow_control_characters: false)
233
+ result = sf.feed("Hello\u0000\u0000World!")
234
+ assert_equal 'Hello World!', result.inputs
235
+ assert_nil result.errors
236
+ end
237
+
238
+ it "doesn't remove unprintable characters" do
239
+ sf = Objective::Filters::StringFilter.new(:s, allow_control_characters: true)
240
+ result = sf.feed("Hello\u0000\u0000World!")
241
+ assert_equal "Hello\u0000\u0000World!", result.inputs
242
+ assert_nil result.errors
243
+ end
244
+
245
+ it "doesn't remove tabs, spaces and line breaks" do
246
+ sf = Objective::Filters::StringFilter.new(:s, allow_control_characters: false)
247
+ result = sf.feed("Hello,\tWorld !\r\nNew Line")
248
+ assert_equal "Hello,\tWorld !\r\nNew Line", result.inputs
249
+ assert_nil result.errors
250
+ end
251
+ end
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+ require 'spec_helper'
3
+
4
+ describe 'Objective::Filters::TimeFilter' do
5
+ it 'takes a Time object' do
6
+ time = Time.now
7
+ f = Objective::Filters::TimeFilter.new
8
+ result = f.feed(time)
9
+ assert_equal time, result.inputs
10
+ assert_nil result.errors
11
+ end
12
+
13
+ it 'takes a Date object and converts it to a time' do
14
+ date = Date.new
15
+ f = Objective::Filters::TimeFilter.new
16
+ result = f.feed(date)
17
+ assert_equal date.to_time, result.inputs
18
+ assert_nil result.errors
19
+ end
20
+
21
+ it 'takes a DateTime object and converts it to a time' do
22
+ date = DateTime.new
23
+ f = Objective::Filters::TimeFilter.new
24
+ result = f.feed(date)
25
+ assert_equal date.to_time, result.inputs
26
+ assert_nil result.errors
27
+ end
28
+
29
+ it 'checks if the given time is after a certain time' do
30
+ time = Time.now
31
+ f = Objective::Filters::TimeFilter.new(:t, after: time - 1)
32
+ result = f.feed(time)
33
+ assert_equal time, result.inputs
34
+ assert_nil result.errors
35
+ end
36
+
37
+ it 'gives errors when the given time is before the after time' do
38
+ time = Time.now
39
+ f = Objective::Filters::TimeFilter.new(:t, after: time + 1)
40
+ result = f.feed(time)
41
+ assert_equal time, result.inputs
42
+ assert_equal :after, result.errors
43
+ end
44
+
45
+ it 'checks if the given time is before a certain time' do
46
+ time = Time.now
47
+ f = Objective::Filters::TimeFilter.new(:t, before: time + 1)
48
+ result = f.feed(time)
49
+ assert_equal time, result.inputs
50
+ assert_nil result.errors
51
+ end
52
+
53
+ it 'gives errors when the given time is after the before time' do
54
+ time = Time.now
55
+ f = Objective::Filters::TimeFilter.new(:t, before: time - 1)
56
+ result = f.feed(time)
57
+ assert_equal time, result.inputs
58
+ assert_equal :before, result.errors
59
+ end
60
+
61
+ it 'checks if the given time is in the given range' do
62
+ time = Time.now
63
+ f = Objective::Filters::TimeFilter.new(:t, after: time - 1, before: time + 1)
64
+ result = f.feed(time)
65
+ assert_equal time, result.inputs
66
+ assert_nil result.errors
67
+ end
68
+
69
+ it 'should be able to parse a D-M-Y string to a time' do
70
+ date_string = '2-1-2000'
71
+ date = Date.new(2000, 1, 2)
72
+ f = Objective::Filters::TimeFilter.new
73
+ result = f.feed(date_string)
74
+ assert_equal date.to_time, result.inputs
75
+ assert_nil result.errors
76
+ end
77
+
78
+ it 'should be able to parse a Y-M-D string to a time' do
79
+ date_string = '2000-1-2'
80
+ date = Date.new(2000, 1, 2)
81
+ f = Objective::Filters::TimeFilter.new
82
+ result = f.feed(date_string)
83
+ assert_equal date.to_time, result.inputs
84
+ assert_nil result.errors
85
+ end
86
+
87
+ it 'should be able to handle time formatting' do
88
+ time_string = '2000-1-2 12:13:14'
89
+ time = Time.new(2000, 1, 2, 12, 13, 14)
90
+ f = Objective::Filters::TimeFilter.new(:t, format: '%Y-%m-%d %H:%M:%S')
91
+ result = f.feed(time_string)
92
+ assert_equal time, result.inputs
93
+ assert_nil result.errors
94
+
95
+ time_string = '1, 2, 2000, 121314'
96
+ f = Objective::Filters::TimeFilter.new(:t, format: '%m, %d, %Y, %H%M%S')
97
+ result = f.feed(time_string)
98
+ assert_equal time, result.inputs
99
+ assert_nil result.errors
100
+ end
101
+
102
+ it 'considers nil to be invalid' do
103
+ f = Objective::Filters::TimeFilter.new
104
+ result = f.feed(nil)
105
+ assert_nil result.inputs
106
+ assert_equal :nils, result.errors
107
+ end
108
+
109
+ it 'allows the use of nil when specified' do
110
+ f = Objective::Filters::TimeFilter.new(:t, nils: Objective::ALLOW)
111
+ result = f.feed(nil)
112
+ assert_nil result.inputs
113
+ assert_nil result.errors
114
+ end
115
+
116
+ it 'doesn\'t allow non-existing times' do
117
+ invalid_time_string = '1, 20, 2013 25:13'
118
+ f = Objective::Filters::TimeFilter.new
119
+ result = f.feed(invalid_time_string)
120
+ assert_equal '1, 20, 2013 25:13', result.inputs
121
+ assert_equal :time, result.errors
122
+ end
123
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+ require 'spec_helper'
3
+ require 'simple_unit'
4
+
5
+ describe 'Objective - inheritance' do
6
+ class SimpleInherited < SimpleUnit
7
+ filter do
8
+ integer :age
9
+ end
10
+
11
+ def execute
12
+ end
13
+ end
14
+
15
+ it 'should filter with inherited unit' do
16
+ outcome = SimpleInherited.run(name: 'bob', email: 'jon@jones.com', age: 10, amount: 22)
17
+ assert outcome.success
18
+ assert_equal OpenStruct.new(name: 'bob', email: 'jon@jones.com', age: 10, amount: 22), outcome.inputs
19
+ end
20
+
21
+ it 'should filter with original unit' do
22
+ outcome = SimpleUnit.run(name: 'bob', email: 'jon@jones.com', age: 10, amount: 22)
23
+ assert outcome.success
24
+ assert_equal OpenStruct.new(name: 'bob', email: 'jon@jones.com', amount: 22), outcome.inputs
25
+ end
26
+
27
+ it 'shouldnt collide' do
28
+ outcome = SimpleInherited.run(name: 'bob', email: 'jon@jones.com', age: 10, amount: 22)
29
+ assert outcome.success
30
+ assert_equal OpenStruct.new(name: 'bob', email: 'jon@jones.com', age: 10, amount: 22), outcome.inputs
31
+
32
+ outcome = SimpleUnit.run(name: 'bob', email: 'jon@jones.com', age: 10, amount: 22)
33
+ assert outcome.success
34
+ assert_equal OpenStruct.new(name: 'bob', email: 'jon@jones.com', amount: 22), outcome.inputs
35
+ end
36
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+ class SimpleUnit
3
+ include Objective::Unit
4
+
5
+ filter do
6
+ string :name, max: 10
7
+ string :email
8
+ integer :amount, none: ALLOW
9
+ end
10
+
11
+ def validate
12
+ return if email&.include?('@')
13
+ add_error(:email, :invalid, 'Email must contain @')
14
+ end
15
+
16
+ def execute
17
+ end
18
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+ require 'byebug'
3
+ require 'minitest/autorun'
4
+ require 'pp'
5
+
6
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__))
7
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
8
+
9
+ require 'objective'
data/spec/unit_spec.rb ADDED
@@ -0,0 +1,244 @@
1
+ # frozen_string_literal: true
2
+ require 'spec_helper'
3
+ require 'simple_unit'
4
+
5
+ describe 'Unit' do
6
+ describe 'SimpleUnit' do
7
+ it 'should allow valid input' do
8
+ outcome = SimpleUnit.run(name: 'John', email: 'john@gmail.com', amount: 5)
9
+
10
+ assert outcome.success
11
+ assert_equal OpenStruct.new(name: 'John', email: 'john@gmail.com', amount: 5), outcome.inputs
12
+ assert_nil outcome.errors
13
+ end
14
+
15
+ it 'should filter out extra inputs' do
16
+ outcome = SimpleUnit.run(name: 'John', email: 'john@gmail.com', amount: 5, buggers: true)
17
+
18
+ assert outcome.success
19
+ assert_equal OpenStruct.new(name: 'John', email: 'john@gmail.com', amount: 5), outcome.inputs
20
+ assert_nil outcome.errors
21
+ end
22
+
23
+ it 'should discover errors in inputs' do
24
+ outcome = SimpleUnit.run(name: 'JohnTooLong', email: 'john@gmail.com')
25
+
26
+ assert !outcome.success
27
+ assert_equal :max, outcome.errors.codes[:name]
28
+ end
29
+
30
+ it 'shouldn\'t throw an exception with run!' do
31
+ result = SimpleUnit.run!(name: 'John', email: 'john@gmail.com', amount: 5)
32
+ assert_nil result
33
+ end
34
+
35
+ it 'should throw an exception with run!' do
36
+ assert_raises Objective::ValidationError do
37
+ SimpleUnit.run!(name: 'John', email: 'john@gmail.com', amount: 'bob')
38
+ end
39
+ end
40
+
41
+ it 'should do standalone validation' do
42
+ outcome = SimpleUnit.build(name: 'JohnLong', email: 'john@gmail.com')
43
+ assert outcome.success
44
+ assert_nil outcome.errors
45
+
46
+ outcome = SimpleUnit.build(name: 'JohnTooLong', email: 'john@gmail.com')
47
+ assert !outcome.success
48
+ assert_nil outcome.result
49
+ assert_equal :max, outcome.errors.codes[:name]
50
+ end
51
+
52
+ it 'should execute a custom validate method' do
53
+ outcome = SimpleUnit.build(name: 'JohnLong', email: 'xxxx')
54
+
55
+ assert !outcome.success
56
+ assert_equal :invalid, outcome.errors.codes[:email]
57
+ end
58
+
59
+ it 'should execute custom validate method during run' do
60
+ outcome = SimpleUnit.run(name: 'JohnLong', email: 'xxxx')
61
+
62
+ assert !outcome.success
63
+ assert_nil outcome.result
64
+ assert_equal :invalid, outcome.errors.codes[:email]
65
+ end
66
+
67
+ it 'should execute custom validate method only if regular validations succeed' do
68
+ outcome = SimpleUnit.build(name: 'JohnTooLong', email: 'xxxx')
69
+
70
+ assert !outcome.success
71
+ assert_equal :max, outcome.errors.codes[:name]
72
+ assert_nil outcome.errors.codes[:email]
73
+ end
74
+
75
+ it 'should merge multiple hashes' do
76
+ outcome = SimpleUnit.run({ name: 'John', email: 'john@gmail.com' }, email: 'bob@jones.com', amount: 5)
77
+
78
+ assert outcome.success
79
+ assert_equal OpenStruct.new(name: 'John', email: 'bob@jones.com', amount: 5), outcome.inputs
80
+ end
81
+
82
+ it 'should merge hashes indifferently' do
83
+ outcome = SimpleUnit.run({ name: 'John', email: 'john@gmail.com' }, 'email' => 'bob@jones.com', 'amount' => 5)
84
+
85
+ assert outcome.success
86
+ assert_equal OpenStruct.new(name: 'John', email: 'bob@jones.com', amount: 5), outcome.inputs
87
+ end
88
+
89
+ it 'shouldn\'t accept non-hashes' do
90
+ assert_raises ArgumentError do
91
+ SimpleUnit.run(nil)
92
+ end
93
+
94
+ assert_raises ArgumentError do
95
+ SimpleUnit.run(1)
96
+ end
97
+
98
+ assert_raises ArgumentError do
99
+ SimpleUnit.run({ name: 'John' }, 1)
100
+ end
101
+ end
102
+
103
+ it 'should accept nothing at all' do
104
+ SimpleUnit.run # make sure nothing is raised
105
+ end
106
+
107
+ it 'should return the filtered inputs in the outcome' do
108
+ outcome = SimpleUnit.run(name: ' John ', email: 'john@gmail.com', amount: '5')
109
+ assert_equal(OpenStruct.new(name: 'John', email: 'john@gmail.com', amount: 5), outcome.inputs)
110
+ end
111
+ end
112
+
113
+ describe 'EigenUnit' do
114
+ class EigenUnit
115
+ include Objective::Unit
116
+ filter do
117
+ string :name
118
+ string :email, none: ALLOW
119
+ end
120
+
121
+ def execute
122
+ { name: name, email: email }
123
+ end
124
+ end
125
+
126
+ it 'should define methods for input keys' do
127
+ outcome = EigenUnit.run(name: 'John', email: 'john@gmail.com')
128
+ assert_equal({ name: 'John', email: 'john@gmail.com' }, outcome.result)
129
+ end
130
+ end
131
+
132
+ describe 'MutatatedUnit' do
133
+ class MutatatedUnit
134
+ include Objective::Unit
135
+ filter do
136
+ string :name
137
+ string :email, none: ALLOW
138
+ end
139
+
140
+ def execute
141
+ inputs.name = 'bob'
142
+ inputs.email = 'bob@jones.com'
143
+ { name: inputs[:name], email: inputs[:email] }
144
+ end
145
+ end
146
+
147
+ it 'should allow inputs to be changed' do
148
+ outcome = MutatatedUnit.run(name: 'John', email: 'john@gmail.com')
149
+ assert_equal({ name: 'bob', email: 'bob@jones.com' }, outcome.result)
150
+ end
151
+ end
152
+
153
+ describe 'ErrorfulUnit' do
154
+ class ErrorfulUnit
155
+ include Objective::Unit
156
+ filter do
157
+ string :name
158
+ string :email, none: ALLOW
159
+ end
160
+
161
+ def execute
162
+ add_error('bob', :is_a_bob)
163
+ 1
164
+ end
165
+ end
166
+
167
+ it 'should let you add errors' do
168
+ outcome = ErrorfulUnit.run(name: 'John', email: 'john@gmail.com')
169
+
170
+ assert !outcome.success
171
+ assert 1, outcome.result
172
+ assert :is_a_bob, outcome.errors.codes[:bob]
173
+ end
174
+ end
175
+
176
+ describe 'NestingErrorfulUnit' do
177
+ class NestingErrorfulUnit
178
+ include Objective::Unit
179
+ filter do
180
+ string :name
181
+ string :email, none: ALLOW
182
+ end
183
+
184
+ def execute
185
+ add_error('people.bob', :is_a_bob)
186
+ 1
187
+ end
188
+ end
189
+
190
+ it 'should let you add errors nested under a namespace' do
191
+ outcome = NestingErrorfulUnit.run(name: 'John', email: 'john@gmail.com')
192
+
193
+ assert !outcome.success
194
+ assert 1, outcome.result
195
+ assert :is_a_bob, outcome.errors[:people].codes[:bob]
196
+ end
197
+ end
198
+
199
+ describe 'MultiErrorUnit' do
200
+ class MultiErrorUnit
201
+ include Objective::Unit
202
+ filter do
203
+ string :name
204
+ string :email, none: ALLOW
205
+ end
206
+
207
+ def execute
208
+ moar_errors = Objective::Errors::ErrorHash.new
209
+ moar_errors[:bob] = Objective::Errors::ErrorAtom.new(:bob, :is_short)
210
+ moar_errors[:sally] = Objective::Errors::ErrorAtom.new(:sally, :is_fat)
211
+
212
+ merge_errors(moar_errors)
213
+ 1
214
+ end
215
+ end
216
+
217
+ it 'should let you merge errors' do
218
+ outcome = ErrorfulUnit.run(name: 'John', email: 'john@gmail.com')
219
+
220
+ assert !outcome.success
221
+ assert 1, outcome.result
222
+ assert :is_short, outcome.errors.codes[:bob]
223
+ assert :is_fat, outcome.errors.codes[:sally]
224
+ end
225
+ end
226
+
227
+ describe 'RawInputsUnit' do
228
+ class RawInputsUnit
229
+ include Objective::Unit
230
+ filter do
231
+ string :name
232
+ end
233
+
234
+ def execute
235
+ raw_inputs
236
+ end
237
+ end
238
+
239
+ it 'should return the raw input data' do
240
+ input = { 'name' => 'Hello World', 'other' => 'Foo Bar Baz' }
241
+ assert_equal OpenStruct.new(input), RawInputsUnit.run!(input)
242
+ end
243
+ end
244
+ end