iknow_params 2.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+