iknow_params 2.2.1

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.
@@ -0,0 +1,313 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'iknow_params'
5
+
6
+ RSpec.describe IknowParams::Parser do
7
+ class Controller
8
+ attr_reader :params
9
+ def initialize(params)
10
+ @params = params
11
+ end
12
+ end
13
+
14
+ before { Controller.include IknowParams::Parser }
15
+
16
+ describe "#parse_param" do
17
+
18
+ let(:parsed) { Controller.new(@params).parse_param(@param, with: serializer) }
19
+
20
+ context "no serializer specified" do
21
+ let(:serializer) { nil }
22
+
23
+ it "returns the value" do
24
+ @params = {name: "foo"}
25
+ @param = :name
26
+
27
+ expect(parsed).to eq @params[@param]
28
+ end
29
+
30
+ it "requires the value" do
31
+ @params = {id: 5}
32
+ @param = :name
33
+
34
+ expect { parsed }.to raise_error(IknowParams::Parser::ParseError)
35
+ end
36
+
37
+ it "admits an explicit nil" do
38
+ @params = { name: nil }
39
+ @param = :name
40
+
41
+ expect(parsed).to eq(nil)
42
+ end
43
+
44
+ context "with a default specified" do
45
+ let(:default) { Object.new }
46
+ let(:parsed) { Controller.new(@params).parse_param(@param, with: serializer, default: default) }
47
+
48
+ it "returns the value when param is present" do
49
+ @params = {name: "foo"}
50
+ @param = :name
51
+
52
+ expect(parsed).to eq @params[@param]
53
+ end
54
+
55
+ it "returns the default when param is missing" do
56
+ @params = {id: 5}
57
+ @param = :name
58
+
59
+ expect(parsed).to eq default
60
+ end
61
+ end
62
+
63
+ context "when dumping the value" do
64
+ let(:parsed) { Controller.new(@params).parse_param(@param, with: serializer, dump: true) }
65
+
66
+ it "raises an error" do
67
+ @params = {name: "foo"}
68
+ @param = :name
69
+
70
+ expect { parsed }.to raise_error(IknowParams::Parser::ParseError)
71
+ end
72
+ end
73
+ end
74
+
75
+ context "with a serializer specified" do
76
+ let(:serializer) { :Integer }
77
+
78
+ it "returns the parsed value" do
79
+ @params = {id: "5"}
80
+ @param = :id
81
+
82
+ expect(parsed).to eq 5
83
+ end
84
+
85
+ it "registers a typed parse method" do
86
+ params = { id: "5" }
87
+ param = :id
88
+ expect(Controller.new(params).parse_integer_param(param)).to eq 5
89
+ end
90
+
91
+ it "requires the value" do
92
+ @params = {name: "5"}
93
+ @param = :id
94
+
95
+ expect { parsed }.to raise_error(IknowParams::Parser::ParseError)
96
+ end
97
+
98
+ it "raises an error when the param can't be parsed into the serializer's type" do
99
+ @params = {id: "fish"}
100
+ @param = :id
101
+
102
+ expect { parsed }.to raise_error(IknowParams::Parser::ParseError)
103
+ end
104
+
105
+ context "with a default specified" do
106
+ let(:default) { 9000 }
107
+ let(:parsed) { Controller.new(@params).parse_param(@param, with: serializer, default: default) }
108
+
109
+ it "returns the value when param is present" do
110
+ @params = {id: "10"}
111
+ @param = :id
112
+
113
+ expect(parsed).to eq 10
114
+ end
115
+
116
+ it "returns the default when param is missing" do
117
+ @params = {name: "22"}
118
+ @param = :id
119
+
120
+ expect(parsed).to eq default
121
+ end
122
+ end
123
+
124
+ context "when dumping the value" do
125
+ let(:parsed) { Controller.new(@params).parse_param(@param, with: serializer, dump: true) }
126
+
127
+ it "returns the string representation" do
128
+ @params = {id: "10"}
129
+ @param = :id
130
+
131
+ expect(parsed).to eq "10"
132
+ end
133
+ end
134
+ end
135
+
136
+ context "with a complex named serializer" do
137
+ class ThisInterestingType < IknowParams::Serializer::Integer
138
+ set_singleton!
139
+ end
140
+
141
+ it "registers a typed parse method" do
142
+ params = { id: "5" }
143
+ param = :id
144
+ expect(Controller.new(params).parse_this_interesting_type_param(param)).to eq 5
145
+ end
146
+ end
147
+ end
148
+
149
+ describe "#parse_array_param" do
150
+ let(:parsed) { Controller.new(@params).parse_array_param(@param, with: serializer) }
151
+
152
+ context "no serializer specified" do
153
+ let(:serializer) { nil }
154
+
155
+ it "returns the values" do
156
+ @params = {names: ["foo", "bar"]}
157
+ @param = :names
158
+
159
+ expect(parsed).to eq @params[@param]
160
+ end
161
+
162
+ it "requires the value" do
163
+ @params = {id: 5}
164
+ @param = :names
165
+
166
+ expect { parsed }.to raise_error(IknowParams::Parser::ParseError)
167
+ end
168
+
169
+ context "with a default specified" do
170
+ let(:default) { [Object.new] }
171
+ let(:parsed) { Controller.new(@params).parse_param(@param, with: serializer, default: default) }
172
+
173
+ it "returns the value when param is present" do
174
+ @params = {names: ["foo", "bar"]}
175
+ @param = :names
176
+
177
+ expect(parsed).to eq @params[@param]
178
+ end
179
+
180
+ it "returns the default when param is missing" do
181
+ @params = {id: 5}
182
+ @param = :names
183
+
184
+ expect(parsed).to eq default
185
+ end
186
+ end
187
+
188
+ context "when dumping the value" do
189
+ let(:parsed) { Controller.new(@params).parse_param(@param, with: serializer, dump: true) }
190
+
191
+ it "raises an error" do
192
+ @params = {names: ["foo"]}
193
+ @param = :names
194
+
195
+ expect { parsed }.to raise_error(IknowParams::Parser::ParseError)
196
+ end
197
+ end
198
+ end
199
+
200
+ context "with a serializer specified" do
201
+ let(:serializer) { :Integer }
202
+
203
+ it "returns the parsed value" do
204
+ @params = {ids: ["4", "5"]}
205
+ @param = :ids
206
+
207
+ expect(parsed).to eq [4, 5]
208
+ end
209
+
210
+ it "registers a typed parse array method" do
211
+ params = { ids: ['4', '5'] }
212
+ param = :ids
213
+ expect(Controller.new(params).parse_integer_array_param(param)).to eq [4, 5]
214
+ end
215
+
216
+ it "requires the value" do
217
+ @params = {name: "5"}
218
+ @param = :ids
219
+
220
+ expect { parsed }.to raise_error(IknowParams::Parser::ParseError)
221
+ end
222
+
223
+ it "raises an error when the one of the params can't be parsed into the serializer's type" do
224
+ @params = {ids: ["4", "fish"]}
225
+ @param = :ids
226
+
227
+ expect { parsed }.to raise_error(IknowParams::Parser::ParseError)
228
+ end
229
+
230
+ context "with a default specified" do
231
+ let(:default) { [4] }
232
+ let(:parsed) { Controller.new(@params).parse_array_param(@param, with: serializer, default: default) }
233
+
234
+ it "returns the value when param is present" do
235
+ @params = {ids: ["10"]}
236
+ @param = :ids
237
+
238
+ expect(parsed).to eq [10]
239
+ end
240
+
241
+ it "returns the default when param is missing" do
242
+ @params = {name: "22"}
243
+ @param = :ids
244
+
245
+ expect(parsed).to eq default
246
+ end
247
+ end
248
+
249
+ context "when dumping the value" do
250
+ let(:parsed) { Controller.new(@params).parse_array_param(@param, with: serializer, dump: true) }
251
+
252
+ it "returns the string representation" do
253
+ @params = {ids: ["10"]}
254
+ @param = :ids
255
+
256
+ expect(parsed).to eq ["10"]
257
+ end
258
+ end
259
+
260
+ end
261
+ end
262
+
263
+ describe '.parse_hash' do
264
+ let(:hash) { { name: "1" } }
265
+
266
+ it "invokes parsers on an arbitrary hash" do
267
+ parsed = IknowParams::Parser.parse_hash(hash) do
268
+ parse_param(:name, with: :Integer)
269
+ end
270
+ expect(parsed).to eq(1)
271
+ end
272
+ end
273
+
274
+ describe '.parse_value' do
275
+ it "invokes parsers on an arbitrary value" do
276
+ parsed = IknowParams::Parser.parse_value("1", with: :Integer)
277
+ expect(parsed).to eq(1)
278
+ end
279
+ end
280
+
281
+ describe '.parse_values' do
282
+ it "invokes parsers on an array of arbitrary values" do
283
+ parsed = IknowParams::Parser.parse_values(["1", "2"], with: :Integer)
284
+ expect(parsed).to eq([1, 2])
285
+ end
286
+ end
287
+
288
+ describe '#remove_blanks' do
289
+ let(:parsed) do
290
+ {"id" => 5,
291
+ "user" => {
292
+ "name" => "Tomoyo",
293
+ "favorite_color" => IknowParams::Parser::BLANK,
294
+ "comment_ids" => [IknowParams::Parser::BLANK, IknowParams::Parser::BLANK, 5]
295
+ }
296
+ }
297
+ end
298
+
299
+ let(:expected) do
300
+ {"id" => 5,
301
+ "user" => {
302
+ "name" => "Tomoyo",
303
+ "comment_ids" => [5]
304
+ }
305
+ }
306
+ end
307
+
308
+ it "removes blanks" do
309
+ expect(Controller.new({}).remove_blanks(parsed)).to eq expected
310
+ end
311
+ end
312
+ end
313
+
@@ -0,0 +1,221 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'iknow_params'
5
+
6
+ require 'rails'
7
+ require 'action_controller'
8
+
9
+ RSpec.describe IknowParams::Serializer do
10
+ shared_examples "a serializer" do
11
+ it "can load its type from a string" do
12
+ valid_values.each do |valid, parsed|
13
+ expect(described_class.load(valid)).to eq parsed
14
+ end
15
+ end
16
+
17
+ it "raises an error when asked to load a bad value" do
18
+ invalid_values.each do |invalid|
19
+ expect { described_class.load(invalid) }.to(raise_error(IknowParams::Serializer::LoadError), "value was accepted: #{invalid}")
20
+ end
21
+ end
22
+
23
+ it "dumps to a string" do
24
+ valid_values.each_value do |parsed|
25
+ expect(described_class.singleton.dump(parsed)).to eq parsed.public_send(string_serializer)
26
+ end
27
+ end
28
+
29
+ it "dumps to a string or JSON value when asked for JSON" do
30
+ valid_values.each_value do |parsed|
31
+ if described_class.json_value?
32
+ expect(described_class.singleton.dump(parsed, json: true)).to eq parsed
33
+ else
34
+ expect(described_class.singleton.dump(parsed, json: true)).to eq parsed.public_send(string_serializer)
35
+ end
36
+ end
37
+ end
38
+
39
+ it "matches the type of arguments" do
40
+ expect(described_class.singleton.matches_type?(valid_values.values.first)).to eq true
41
+
42
+ invalid_values.each do |invalid|
43
+ expect(described_class.singleton.matches_type?(invalid)).to(eq(false), "value was accepted: #{invalid}")
44
+ end
45
+ end
46
+ end
47
+
48
+ shared_examples "a JSON-value serializer" do
49
+ it "represents a JSON value" do
50
+ expect(described_class.json_value?).to eq true
51
+ end
52
+ end
53
+
54
+ shared_examples "a non-JSON value serializer" do
55
+ it "represents a non-JSON value" do
56
+ expect(described_class.json_value?).to eq false
57
+ end
58
+ end
59
+
60
+ # What we expect dump to use to serialize the entity to a string
61
+ let(:string_serializer) { :to_s }
62
+
63
+ describe IknowParams::Serializer::Integer do
64
+ let(:valid_values) { {"33" => 33, 33 => 33, "-1" => -1, -2 => -2} }
65
+ let(:invalid_values) { ["fish", "4.5", 4.5, Object.new] }
66
+
67
+ it_behaves_like "a serializer"
68
+ it_behaves_like "a JSON-value serializer"
69
+ end
70
+
71
+ describe IknowParams::Serializer::Float do
72
+ let(:valid_values) { {"33.3" => 33.3, 33.3 => 33.3, "0.0" => 0.0, 0.0 => 0.0, 0 => 0.0} }
73
+ let(:invalid_values) { ["fish", {}, Object.new] }
74
+
75
+ it_behaves_like "a serializer"
76
+ it_behaves_like "a JSON-value serializer"
77
+ end
78
+
79
+ describe IknowParams::Serializer::Boolean do
80
+ let(:valid_values) { {true => true, 'yes' => true, 'on' => true, 'ON' => true, 'true' => true, '1' => true, 1 => true, 1.0 => true,
81
+ false => false, 'no' => false, 'off' => false, 'OFF' => false, 'false' => false, '0' => false, 0 => false, 0.0 =>false} }
82
+
83
+ let(:invalid_values) { ["fish", {}, Object.new, 2] }
84
+
85
+ it_behaves_like "a serializer"
86
+ it_behaves_like "a JSON-value serializer"
87
+ end
88
+
89
+ describe IknowParams::Serializer::Numeric do
90
+ let(:valid_values) { {"33.3" => 33.3, 33.3 => 33.3, "0.0" => 0.0, 0.0 => 0.0, 0 => 0.0, "2" => 2, 2 => 2} }
91
+ let(:invalid_values) { ["fish", {}, Object.new] }
92
+
93
+ it_behaves_like "a serializer"
94
+ it_behaves_like "a JSON-value serializer"
95
+ end
96
+
97
+ describe IknowParams::Serializer::Date do
98
+ let(:valid_values) { {"2017/07/13" => Date.new(2017, 07, 13), "1998/01" => Date.new(1998, 01, 01), "2017/07/13 13:00" => Date.new(2017, 07, 13)} }
99
+ let(:invalid_values) { ["fish", {}, Object.new] }
100
+
101
+ let(:string_serializer) { :iso8601 }
102
+
103
+ it_behaves_like "a serializer"
104
+ it_behaves_like "a non-JSON value serializer"
105
+ end
106
+
107
+ describe IknowParams::Serializer::Time do
108
+ let(:valid_values) { {"2017/07/13 10:00 UTC" => Time.parse("2017/07/13 10:00 UTC"), "2017/07/13 13:00 JST" => Time.parse("2017/07/13 13:00 JST"), "20170525T204236+0700" => Time.parse("2017/05/25 20:42:36 +0700")} }
109
+ let(:invalid_values) { ["fish", {}, Object.new] }
110
+
111
+ let(:string_serializer) { :iso8601 }
112
+
113
+ it_behaves_like "a serializer"
114
+ it_behaves_like "a non-JSON value serializer"
115
+ end
116
+
117
+ describe IknowParams::Serializer::Duration do
118
+ let(:valid_values) { {
119
+ "P6DT1M" => 6.days + 1.minute,
120
+ "P6Y5M4DT3H2M1S" => 6.years + 5.months + 4.days + 3.hours + 2.minutes + 1.second
121
+ } }
122
+ let(:invalid_values) { ["fish", {}, Object.new] }
123
+
124
+ let(:string_serializer) { :iso8601 }
125
+
126
+ it_behaves_like "a serializer"
127
+ it_behaves_like "a non-JSON value serializer"
128
+ end
129
+
130
+ describe IknowParams::Serializer::Timezone do
131
+ let(:valid_values) { {"Asia/Tokyo" => TZInfo::Timezone.get("Asia/Tokyo"), "Asia/Shanghai" => TZInfo::Timezone.get("Asia/Shanghai"), "Europe/Berlin" => TZInfo::Timezone.get("Europe/Berlin")} }
132
+ let(:invalid_values) { ["Tokyo", {}, Object.new, "Eastern"] }
133
+
134
+ let(:string_serializer) { :identifier }
135
+
136
+ it_behaves_like "a serializer"
137
+ it_behaves_like "a non-JSON value serializer"
138
+ end
139
+
140
+ describe IknowParams::Serializer::UUID do
141
+ let(:valid_values) { {"e56986f4-4418-4f7a-99d8-3faccde33f6b" => "e56986f4-4418-4f7a-99d8-3faccde33f6b",
142
+ "1e851f60-4eb9-4660-ad4e-ac0b315f3647" => "1e851f60-4eb9-4660-ad4e-ac0b315f3647",
143
+ "8a540cb9-8107-45e8-8611-82b9171b4a4b" => "8a540cb9-8107-45e8-8611-82b9171b4a4b" } }
144
+
145
+ let(:invalid_values) { ["e56986f4-4418-4f7a-99d8-3faccde33f$b", {}, Object.new, "e56986f4-4418-4f7a-99d8-3faccde33fb"] }
146
+
147
+ it_behaves_like "a serializer"
148
+ it_behaves_like "a JSON-value serializer"
149
+ end
150
+
151
+ # Test abstract JsonWithSchema serializer by making a real schema
152
+ # and serializer for it.
153
+
154
+ class MyJsonSerializer < IknowParams::Serializer::JsonWithSchema
155
+ def initialize
156
+ schema = {"type" => "object", "required" => ["a"], "properties" => {"a" => {"type" => "integer"}}}
157
+ super(schema)
158
+ end
159
+
160
+ set_singleton!
161
+ end
162
+
163
+ describe MyJsonSerializer do
164
+ let(:valid_values) { {'{"a": 5}' => {"a" => 5}, '{"a": 6}' => {"a" => 6}} }
165
+ let(:invalid_values) { ['{"a": "5"}', '{"b": 6}', '[]', '{}'] }
166
+
167
+ let(:string_serializer) { :to_json }
168
+
169
+ it_behaves_like "a serializer"
170
+ it_behaves_like "a JSON-value serializer"
171
+ end
172
+
173
+ # Test abstract JsonWithSchema serializer by making a real schema
174
+ # and serializer for it.
175
+
176
+ class MyRailsJsonSerializer < IknowParams::Serializer::JsonWithSchema::Rails
177
+ def initialize
178
+ schema = {"type" => "object", "required" => ["a"], "properties" => {"a" => {"type" => "integer"}}}
179
+ super(schema)
180
+ end
181
+
182
+ set_singleton!
183
+ end
184
+
185
+ describe MyRailsJsonSerializer do
186
+ let(:valid_values) { {
187
+ '{"a": 5}' => {"a" => 5},
188
+ '{"a": 6}' => {"a" => 6},
189
+ ActionController::Parameters.new({"a" => 5}) => {"a" => 5}
190
+ } }
191
+
192
+ let(:invalid_values) { ['{"a": "5"}', '{"b": 6}', '[]', '{}'] }
193
+
194
+ let(:string_serializer) { :to_json }
195
+
196
+ it_behaves_like "a serializer"
197
+ it_behaves_like "a JSON-value serializer"
198
+ end
199
+
200
+ # Test abstract StringEnum serializer by making a real enum
201
+ # and serializer for it.
202
+
203
+ class MyStringEnumSerializer < IknowParams::Serializer::StringEnum
204
+ def initialize
205
+ super("a", "b")
206
+ end
207
+
208
+ set_singleton!
209
+ end
210
+
211
+ describe MyStringEnumSerializer do
212
+ let(:valid_values) { {'a' => 'a', 'b' => 'b', 'B' => 'b'} }
213
+ let(:invalid_values) { ['c', 'd'] }
214
+
215
+ let(:string_serializer) { :downcase }
216
+
217
+ it_behaves_like "a serializer"
218
+ it_behaves_like "a non-JSON value serializer"
219
+ end
220
+ end
221
+