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,93 @@
1
+ # frozen_string_literal: true
2
+ require 'spec_helper'
3
+ require 'stringio'
4
+ require 'tempfile'
5
+
6
+ describe 'Objective::Filters::FileFilter' do
7
+ class UploadedStringIO < StringIO
8
+ attr_accessor :content_type, :original_filename
9
+ end
10
+
11
+ if File.new('README.md').respond_to?(:size)
12
+ it 'allows files - file class' do
13
+ file = File.new('README.md')
14
+ f = Objective::Filters::FileFilter.new
15
+ result = f.feed(file)
16
+ assert_equal file, result.inputs
17
+ assert_nil result.errors
18
+ end
19
+ end
20
+
21
+ it 'allows files - stringio class' do
22
+ file = StringIO.new('bob')
23
+ f = Objective::Filters::FileFilter.new
24
+ result = f.feed(file)
25
+ assert_equal file, result.inputs
26
+ assert_nil result.errors
27
+ end
28
+
29
+ it 'allows files - tempfile' do
30
+ file = Tempfile.new('bob')
31
+ f = Objective::Filters::FileFilter.new
32
+ result = f.feed(file)
33
+ assert result.inputs.is_a?(Tempfile)
34
+ assert_nil result.errors
35
+ end
36
+
37
+ it 'doesn\'t allow non-files' do
38
+ f = Objective::Filters::FileFilter.new
39
+ result = f.feed('string')
40
+ assert_equal 'string', result.inputs
41
+ assert_equal :file, result.errors
42
+
43
+ result = f.feed(12)
44
+ assert_equal 12, result.inputs
45
+ assert_equal :file, result.errors
46
+ end
47
+
48
+ it 'considers nil to be invalid' do
49
+ f = Objective::Filters::FileFilter.new(:clippy)
50
+ result = f.feed(nil)
51
+ assert_nil result.inputs
52
+ assert_equal :nils, result.errors
53
+ end
54
+
55
+ it 'considers nil to be valid' do
56
+ f = Objective::Filters::FileFilter.new(:clippy, nils: Objective::ALLOW)
57
+ result = f.feed(nil)
58
+ assert_nil result.inputs
59
+ assert_nil result.errors
60
+ end
61
+
62
+ it 'should allow small files' do
63
+ file = StringIO.new('bob')
64
+ f = Objective::Filters::FileFilter.new(:clippy, size: 4)
65
+ result = f.feed(file)
66
+ assert_equal file, result.inputs
67
+ assert_nil result.errors
68
+ end
69
+
70
+ it 'shouldn\'t allow big files' do
71
+ file = StringIO.new('bob')
72
+ f = Objective::Filters::FileFilter.new(:clippy, size: 2)
73
+ result = f.feed(file)
74
+ assert_equal file, result.inputs
75
+ assert_equal :size, result.errors
76
+ end
77
+
78
+ it 'should require extra methods if uploaded file: accept' do
79
+ file = UploadedStringIO.new('bob')
80
+ f = Objective::Filters::FileFilter.new(:clippy, upload: true)
81
+ result = f.feed(file)
82
+ assert_equal file, result.inputs
83
+ assert_nil result.errors
84
+ end
85
+
86
+ it 'should require extra methods if uploaded file: deny' do
87
+ file = StringIO.new('bob')
88
+ f = Objective::Filters::FileFilter.new(:clippy, upload: true)
89
+ result = f.feed(file)
90
+ assert_equal file, result.inputs
91
+ assert_equal :file, result.errors
92
+ end
93
+ end
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+ require 'spec_helper'
3
+
4
+ describe 'Objective::Filters::FloatFilter' do
5
+ it 'allows floats' do
6
+ f = Objective::Filters::FloatFilter.new
7
+ result = f.feed(3.1415926)
8
+
9
+ assert result.inputs.is_a?(Float)
10
+ assert_equal 3.1415926, result.inputs
11
+ assert_nil result.errors
12
+ end
13
+
14
+ it 'allows integers' do
15
+ f = Objective::Filters::FloatFilter.new
16
+ result = f.feed(3)
17
+
18
+ assert result.inputs.is_a?(Float)
19
+ assert_equal 3, result.inputs
20
+ assert_nil result.errors
21
+ end
22
+
23
+ it 'allows bigdecimals' do
24
+ f = Objective::Filters::FloatFilter.new
25
+ result = f.feed(BigDecimal.new('3'))
26
+
27
+ assert result.inputs.is_a?(Float)
28
+ assert_equal 3, result.inputs
29
+ assert_nil result.errors
30
+ end
31
+
32
+ it 'allows strings that start with a digit' do
33
+ f = Objective::Filters::FloatFilter.new
34
+ result = f.feed('3')
35
+
36
+ assert result.inputs.is_a?(Float)
37
+ assert_equal 3.0, result.inputs
38
+ assert_nil result.errors
39
+ end
40
+
41
+ it 'allows string representation of float' do
42
+ f = Objective::Filters::FloatFilter.new
43
+ result = f.feed('3.14')
44
+
45
+ assert result.inputs.is_a?(Float)
46
+ assert_equal 3.14, result.inputs
47
+ assert_nil result.errors
48
+ end
49
+
50
+ it 'allows string representation of float without a number before dot' do
51
+ f = Objective::Filters::FloatFilter.new
52
+ result = f.feed('.14')
53
+
54
+ assert result.inputs.is_a?(Float)
55
+ assert_equal 0.14, result.inputs
56
+ assert_nil result.errors
57
+ end
58
+
59
+ it 'allows negative strings' do
60
+ f = Objective::Filters::FloatFilter.new
61
+ result = f.feed('-.14')
62
+
63
+ assert result.inputs.is_a?(Float)
64
+ assert_equal(-0.14, result.inputs)
65
+ assert_nil result.errors
66
+ end
67
+
68
+ it 'allows strings with a positive sign' do
69
+ f = Objective::Filters::FloatFilter.new
70
+ result = f.feed('+.14')
71
+
72
+ assert result.inputs.is_a?(Float)
73
+ assert_equal 0.14, result.inputs
74
+ assert_nil result.errors
75
+ end
76
+
77
+ it 'does not allow other strings, nor does it allow random objects or symbols' do
78
+ f = Objective::Filters::FloatFilter.new
79
+ ['zero', 'a1', {}, [], Object.new, :d].each do |thing|
80
+ result = f.feed(thing)
81
+ assert_equal :float, result.errors
82
+ end
83
+ end
84
+
85
+ it 'considers nil to be invalid' do
86
+ f = Objective::Filters::FloatFilter.new(:x)
87
+ result = f.feed(nil)
88
+ assert_nil result.inputs
89
+ assert_equal :nils, result.errors
90
+ end
91
+
92
+ it 'considers nil to be valid' do
93
+ f = Objective::Filters::FloatFilter.new(:x, nils: Objective::ALLOW)
94
+ result = f.feed(nil)
95
+ assert_nil result.inputs
96
+ assert_nil result.errors
97
+ end
98
+
99
+ it 'considers empty strings invalid' do
100
+ f = Objective::Filters::FloatFilter.new
101
+ result = f.feed('')
102
+ assert_equal :float, result.errors
103
+ end
104
+
105
+ it 'considers low numbers invalid' do
106
+ f = Objective::Filters::FloatFilter.new(:x, min: 10)
107
+ result = f.feed(3)
108
+
109
+ assert result.inputs.is_a?(Float)
110
+ assert_equal 3, result.inputs
111
+ assert_equal :min, result.errors
112
+ end
113
+
114
+ it 'considers low numbers valid' do
115
+ f = Objective::Filters::FloatFilter.new(:x, min: 10)
116
+ result = f.feed(31)
117
+
118
+ assert result.inputs.is_a?(Float)
119
+ assert_equal 31, result.inputs
120
+ assert_nil result.errors
121
+ end
122
+
123
+ it 'considers high numbers invalid' do
124
+ f = Objective::Filters::FloatFilter.new(:x, max: 10)
125
+ result = f.feed(31)
126
+
127
+ assert result.inputs.is_a?(Float)
128
+ assert_equal 31, result.inputs
129
+ assert_equal :max, result.errors
130
+ end
131
+
132
+ it 'considers high numbers vaild' do
133
+ f = Objective::Filters::FloatFilter.new(:x, max: 10)
134
+ result = f.feed(3)
135
+
136
+ assert result.inputs.is_a?(Float)
137
+ assert_equal 3, result.inputs
138
+ assert_nil result.errors
139
+ end
140
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+ require 'spec_helper'
3
+ require 'stringio'
4
+
5
+ describe 'Objective::Filters::HashFilter' do
6
+ it 'allows valid hashes' do
7
+ hf = Objective::Filters::HashFilter.new do
8
+ string :foo
9
+ end
10
+
11
+ result = hf.feed(foo: 'bar')
12
+ assert_equal ({ 'foo' => 'bar' }), result.inputs
13
+ assert_nil result.errors
14
+ end
15
+
16
+ it 'disallows non-hashes' do
17
+ hf = Objective::Filters::HashFilter.new do
18
+ string :foo
19
+ end
20
+
21
+ result = hf.feed('bar')
22
+ assert_equal :hash, result.errors
23
+ end
24
+
25
+ it 'allows floats in hashes' do
26
+ hf = Objective::Filters::HashFilter.new do
27
+ float :foo
28
+ end
29
+
30
+ result = hf.feed(foo: 3.14)
31
+ assert_equal ({ 'foo' => 3.14 }), result.inputs
32
+ assert_nil result.errors
33
+ end
34
+
35
+ it 'allows ducks in hashes' do
36
+ hf = Objective::Filters::HashFilter.new do
37
+ duck :foo, methods: [:length]
38
+ end
39
+
40
+ result = hf.feed(foo: '123')
41
+ assert_equal ({ 'foo' => '123' }), result.inputs
42
+ assert_nil result.errors
43
+ end
44
+
45
+ it 'allows dates in hashes' do
46
+ hf = Objective::Filters::HashFilter.new do
47
+ date :foo, format: '%d-%m-%Y'
48
+ end
49
+
50
+ result = hf.feed(foo: '1-1-2000')
51
+ assert_equal Date.new(2000, 1, 1), result.inputs[:foo]
52
+ assert_nil result.errors
53
+ end
54
+
55
+ it 'allows files in hashes' do
56
+ sio = StringIO.new('bob')
57
+ hf = Objective::Filters::HashFilter.new do
58
+ file :foo
59
+ end
60
+
61
+ result = hf.feed(foo: sio)
62
+ assert_equal ({ 'foo' => sio }), result.inputs
63
+ assert_nil result.errors
64
+ end
65
+ end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+ require 'spec_helper'
3
+
4
+ describe 'Objective::Filters::IntegerFilter' do
5
+ it 'allows integers' do
6
+ f = Objective::Filters::IntegerFilter.new
7
+ result = f.feed(3)
8
+
9
+ assert result.inputs.is_a?(Integer)
10
+ assert_equal 3, result.inputs
11
+ assert_nil result.errors
12
+ end
13
+
14
+ it 'allows floats equivalent to an integer' do
15
+ f = Objective::Filters::IntegerFilter.new
16
+ result = f.feed(3.0)
17
+
18
+ assert result.inputs.is_a?(Integer)
19
+ assert_equal 3, result.inputs
20
+ assert_nil result.errors
21
+ end
22
+
23
+ it 'does not allows floats with non-zero decimal places' do
24
+ f = Objective::Filters::IntegerFilter.new
25
+ result = f.feed(3.1)
26
+
27
+ assert_equal 3.1, result.inputs
28
+ assert_equal :integer, result.errors
29
+ end
30
+
31
+ it 'allows bigdecimals equivalent to an integer' do
32
+ f = Objective::Filters::IntegerFilter.new
33
+ result = f.feed(BigDecimal.new('3.000000'))
34
+
35
+ assert result.inputs.is_a?(Integer)
36
+ assert_equal 3, result.inputs
37
+ assert_nil result.errors
38
+ end
39
+
40
+ it 'does not allows decimals with non-zero decimal places' do
41
+ f = Objective::Filters::IntegerFilter.new
42
+ result = f.feed(BigDecimal.new('3.111111'))
43
+
44
+ assert_equal BigDecimal.new('3.111111'), result.inputs
45
+ assert_equal :integer, result.errors
46
+ end
47
+
48
+ it 'allows strings that start with a digit' do
49
+ f = Objective::Filters::IntegerFilter.new
50
+ result = f.feed('3')
51
+
52
+ assert result.inputs.is_a?(Integer)
53
+ assert_equal 3, result.inputs
54
+ assert_nil result.errors
55
+ end
56
+
57
+ it 'allows negative strings' do
58
+ f = Objective::Filters::IntegerFilter.new
59
+ result = f.feed('-3')
60
+
61
+ assert result.inputs.is_a?(Integer)
62
+ assert_equal(-3, result.inputs)
63
+ assert_nil result.errors
64
+ end
65
+
66
+ it 'does not allow other strings, nor does it allow random objects or symbols' do
67
+ f = Objective::Filters::IntegerFilter.new
68
+ ['zero', 'a1', {}, [], Object.new, :d].each do |thing|
69
+ result = f.feed(thing)
70
+ assert_equal :integer, result.errors
71
+ end
72
+ end
73
+
74
+ it 'considers nil to be invalid' do
75
+ f = Objective::Filters::IntegerFilter.new(:i)
76
+ result = f.feed(nil)
77
+
78
+ assert_nil result.inputs
79
+ assert_equal :nils, result.errors
80
+ end
81
+
82
+ it 'considers nil to be valid' do
83
+ f = Objective::Filters::IntegerFilter.new(:i, nils: Objective::ALLOW)
84
+ result = f.feed(nil)
85
+
86
+ assert_nil result.inputs
87
+ assert_nil result.errors
88
+ end
89
+
90
+ it 'considers empty strings to be empty' do
91
+ f = Objective::Filters::IntegerFilter.new
92
+ result = f.feed('')
93
+
94
+ assert_equal :integer, result.errors
95
+ end
96
+
97
+ it 'considers low numbers invalid' do
98
+ f = Objective::Filters::IntegerFilter.new(:i, min: 10)
99
+ result = f.feed(3)
100
+
101
+ assert result.inputs.is_a?(Integer)
102
+ assert_equal 3, result.inputs
103
+ assert_equal :min, result.errors
104
+ end
105
+
106
+ it 'considers low numbers valid' do
107
+ f = Objective::Filters::IntegerFilter.new(:i, min: 10)
108
+ result = f.feed(31)
109
+
110
+ assert result.inputs.is_a?(Integer)
111
+ assert_equal 31, result.inputs
112
+ assert_nil result.errors
113
+ end
114
+
115
+ it 'considers high numbers invalid' do
116
+ f = Objective::Filters::IntegerFilter.new(:i, max: 10)
117
+ result = f.feed(31)
118
+
119
+ assert result.inputs.is_a?(Integer)
120
+ assert_equal 31, result.inputs
121
+ assert_equal :max, result.errors
122
+ end
123
+
124
+ it 'considers high numbers vaild' do
125
+ f = Objective::Filters::IntegerFilter.new(:i, max: 10)
126
+ result = f.feed(3)
127
+
128
+ assert result.inputs.is_a?(Integer)
129
+ assert_equal 3, result.inputs
130
+ assert_nil result.errors
131
+ end
132
+
133
+ it 'considers not matching numbers to be invalid' do
134
+ f = Objective::Filters::IntegerFilter.new(:i, in: [3, 4, 5])
135
+ result = f.feed(6)
136
+
137
+ assert result.inputs.is_a?(Integer)
138
+ assert_equal 6, result.inputs
139
+ assert_equal :in, result.errors
140
+ end
141
+
142
+ it 'considers matching numbers to be valid' do
143
+ f = Objective::Filters::IntegerFilter.new(:i, in: [3, 4, 5])
144
+ result = f.feed(3)
145
+
146
+ assert result.inputs.is_a?(Integer)
147
+ assert_equal 3, result.inputs
148
+ assert_nil result.errors
149
+ end
150
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+ require 'spec_helper'
3
+
4
+ describe 'Objective::Filters::ModelFilter' do
5
+ class SimpleModel; end
6
+ class AlwaysNew
7
+ def new_record?
8
+ true
9
+ end
10
+ end
11
+
12
+ class AlwaysSaved
13
+ def new_record?
14
+ false
15
+ end
16
+ end
17
+
18
+ it 'allows models' do
19
+ f = Objective::Filters::ModelFilter.new(:simple_model)
20
+ m = SimpleModel.new
21
+ result = f.feed(m)
22
+ assert_equal m, result.inputs
23
+ assert_nil result.errors
24
+ end
25
+
26
+ it 'raises an exception during filtering if constantization fails' do
27
+ f = Objective::Filters::ModelFilter.new(:non_existent_class)
28
+
29
+ # NOTE: nil will short circuit the check for an existing constant
30
+ result = f.feed(nil)
31
+ assert_nil result.inputs
32
+ assert_equal :nils, result.errors
33
+
34
+ assert_raises NameError do
35
+ f.feed(0)
36
+ end
37
+ end
38
+
39
+ it 'raises an exception during filtering if constantization of class fails' do
40
+ f = Objective::Filters::ModelFilter.new(:simple_model, class: 'NonExistentClass')
41
+
42
+ # NOTE: nil will short circuit the check for an existing constant
43
+ result = f.feed(nil)
44
+ assert_nil result.inputs
45
+ assert_equal :nils, result.errors
46
+
47
+ assert_raises NameError do
48
+ f.feed(0)
49
+ end
50
+ end
51
+
52
+ it 'considers nil to be invalid' do
53
+ f = Objective::Filters::ModelFilter.new(:simple_model)
54
+ result = f.feed(nil)
55
+ assert_nil result.inputs
56
+ assert_equal :nils, result.errors
57
+ end
58
+
59
+ it 'considers nil to be valid' do
60
+ f = Objective::Filters::ModelFilter.new(:simple_model, nils: Objective::ALLOW)
61
+ result = f.feed(nil)
62
+ assert_nil result.inputs
63
+ assert_nil result.errors
64
+ end
65
+
66
+ # it "disallows different types of models" do
67
+ # end
68
+ #
69
+ # it "allows you to override class with a constant and succeed" do
70
+ # end
71
+ #
72
+ # it "allows you to override class with a string and succeed" do
73
+ # end
74
+ #
75
+ # it "allows you to override class and fail" do
76
+ # end
77
+ #
78
+ # it "allows anything if new_record is true" do
79
+ # end
80
+ #
81
+ # it "disallows new_records if new_record is false" do
82
+ # end
83
+ #
84
+ # it "allows saved records if new_record is false" do
85
+ # end
86
+ #
87
+ # it "allows other records if new_record is false" do
88
+ # end
89
+ #
90
+ # it "allows you to build a record from a hash, and succeed" do
91
+ # end
92
+ #
93
+ # it "allows you to build a record from a hash, and fail" do
94
+ # end
95
+ #
96
+ # it "makes sure that if you build a record from a hash, it still has to be of the right class" do
97
+ # end
98
+ end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+ require 'spec_helper'
3
+
4
+ describe 'Objective::Filters::RootFilter' do
5
+ describe 'optional filters and nils' do
6
+ it 'bar is optional -- it works if not passed' do
7
+ hf = Objective::Filters::RootFilter.new do
8
+ filter do
9
+ string :foo
10
+ string :bar, none: Objective::ALLOW
11
+ end
12
+ end
13
+
14
+ result = hf.feed(foo: 'bar')
15
+ assert_equal OpenStruct.new(foo: 'bar'), result.inputs
16
+ assert_nil result.errors
17
+ end
18
+
19
+ it 'bar is optional -- it works if nil is passed' do
20
+ hf = Objective::Filters::RootFilter.new do
21
+ filter do
22
+ string :foo
23
+ string :bar, nils: Objective::DISCARD
24
+ end
25
+ end
26
+
27
+ result = hf.feed(foo: 'bar', bar: nil)
28
+ assert_equal OpenStruct.new(foo: 'bar'), result.inputs
29
+ assert_nil result.errors
30
+ end
31
+
32
+ it 'bar is optional -- it works if nil is passed and nils are allowed' do
33
+ hf = Objective::Filters::RootFilter.new do
34
+ filter do
35
+ string :foo
36
+ string :bar, nils: Objective::ALLOW
37
+ end
38
+ end
39
+
40
+ result = hf.feed(foo: 'bar', bar: nil)
41
+ assert_equal OpenStruct.new(foo: 'bar', bar: nil), result.inputs
42
+ assert_nil result.errors
43
+ end
44
+ end
45
+
46
+ describe 'optional filters and empty values' do
47
+ it 'bar is optional -- discards empty' do
48
+ hf = Objective::Filters::RootFilter.new do
49
+ filter do
50
+ string :foo
51
+ string :bar, empty: Objective::DISCARD
52
+ end
53
+ end
54
+
55
+ result = hf.feed(foo: 'bar', bar: '')
56
+ assert_equal OpenStruct.new(foo: 'bar'), result.inputs
57
+ assert_nil result.errors
58
+ end
59
+
60
+ it 'bar is optional -- discards empty if it needs to be stripped' do
61
+ hf = Objective::Filters::RootFilter.new do
62
+ filter do
63
+ string :foo
64
+ string :bar, empty: Objective::DISCARD
65
+ end
66
+ end
67
+
68
+ result = hf.feed(foo: 'bar', bar: ' ')
69
+ assert_equal OpenStruct.new(foo: 'bar'), result.inputs
70
+ assert_nil result.errors
71
+ end
72
+
73
+ it "bar is optional -- don't discard empty if it's spaces but stripping is off" do
74
+ hf = Objective::Filters::RootFilter.new do
75
+ filter do
76
+ string :foo
77
+ string :bar, empty: Objective::DISCARD, strip: false
78
+ end
79
+ end
80
+
81
+ result = hf.feed(foo: 'bar', bar: ' ')
82
+ assert_equal OpenStruct.new(foo: 'bar', bar: ' '), result.inputs
83
+ assert_nil result.errors
84
+ end
85
+
86
+ it 'bar is optional -- errors if value is blank' do
87
+ hf = Objective::Filters::RootFilter.new do
88
+ filter do
89
+ string :foo
90
+ string :bar, none: Objective::ALLOW
91
+ end
92
+ end
93
+
94
+ result = hf.feed(foo: 'bar', bar: '')
95
+ assert_equal({ 'bar' => :empty }, result.errors.codes)
96
+ end
97
+ end
98
+
99
+ describe 'discarding invalid values' do
100
+ it 'should discard invalid optional values' do
101
+ hf = Objective::Filters::RootFilter.new do
102
+ filter do
103
+ string :foo
104
+ integer :bar, invalid: Objective::DISCARD
105
+ end
106
+ end
107
+
108
+ result = hf.feed(foo: 'bar', bar: 'baz')
109
+ assert_equal OpenStruct.new(foo: 'bar'), result.inputs
110
+ assert_nil result.errors
111
+ end
112
+ end
113
+ end