committee 5.5.2 → 5.5.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8c6653c3224887d3adf7300b4c4e2f047a839ab31ba1890b87b8daad828e939d
4
- data.tar.gz: 7c00b24dff0a892dfe82b28304547e8ac47729f1ac87fcdf81f47575a7757bad
3
+ metadata.gz: 55b46e3f19c168b4554b537c7f5e29ef861a19437e602b184d97f47e55a90440
4
+ data.tar.gz: 96f8b60ed69dedb9352482bb2d9a8e95358b23e2d97a077f3040ddab43d7d9f9
5
5
  SHA512:
6
- metadata.gz: 876a44d4c13020892a3e6b10ee1008fc0b5ee0d7e294acbca8922c5ec4cf7c78fe6bee6374388bc9468a4511b11eb68cf6e3c49bf360e77f158942953e113bcb
7
- data.tar.gz: 17f3777d9d610fe64f86670c7b849a8dae18346ae5d59639b3bdd5cff2958649b1a6da78c5abe4d60e01dfd5a506fc2420f1c024de40d5f982bd2f353bf34d01
6
+ metadata.gz: beca39b681b278c29d0953d217cf2967979a9124516f4a70e177aea50c40537eb5cd57f621989feb2f73b6c86b8493609eb95ba5ae79019b6724cb43b33e4f76
7
+ data.tar.gz: b6c4456c9c36db3b6b537acbcdaf19170fe6173332379d8f594b150b3a3d533879711a7af7056cdd17182f416ff31fa1217d66a6a449ba9de08dd09e93d08759
@@ -21,11 +21,12 @@ module Committee
21
21
  end
22
22
 
23
23
  def initialize(options = {})
24
- @allow_form_params = options[:allow_form_params]
25
- @allow_get_body = options[:allow_get_body]
26
- @allow_query_params = options[:allow_query_params]
27
- @allow_non_get_query_params = options[:allow_non_get_query_params]
28
- @optimistic_json = options[:optimistic_json]
24
+ @allow_empty_date_and_datetime = options[:allow_empty_date_and_datetime]
25
+ @allow_form_params = options[:allow_form_params]
26
+ @allow_get_body = options[:allow_get_body]
27
+ @allow_query_params = options[:allow_query_params]
28
+ @allow_non_get_query_params = options[:allow_non_get_query_params]
29
+ @optimistic_json = options[:optimistic_json]
29
30
  end
30
31
 
31
32
  # return params and is_form_params
@@ -31,10 +31,12 @@ module Committee
31
31
  end
32
32
 
33
33
  # @param [Boolean] strict when not content_type or status code definition, raise error
34
- def validate_response_params(status_code, headers, response_data, strict, check_header)
34
+ def validate_response_params(status_code, headers, response_data, strict, check_header, validator_options: {})
35
35
  response_body = OpenAPIParser::RequestOperation::ValidatableResponseBody.new(status_code, response_data, headers)
36
36
 
37
- return request_operation.validate_response_body(response_body, response_validate_options(strict, check_header))
37
+ return request_operation.validate_response_body(
38
+ response_body,
39
+ response_validate_options(strict, check_header, validator_options: validator_options))
38
40
  rescue OpenAPIParser::OpenAPIError => e
39
41
  raise Committee::InvalidResponse.new(e.message, original_error: e)
40
42
  end
@@ -89,11 +91,15 @@ module Committee
89
91
 
90
92
  # @return [OpenAPIParser::SchemaValidator::Options]
91
93
  def build_openapi_parser_option(validator_option, coerce_value)
92
- datetime_coerce_class = validator_option.coerce_date_times ? DateTime : nil
93
- validate_header = validator_option.check_header
94
- OpenAPIParser::SchemaValidator::Options.new(coerce_value: coerce_value,
95
- datetime_coerce_class: datetime_coerce_class,
96
- validate_header: validate_header)
94
+ parser_options = {
95
+ coerce_value: coerce_value,
96
+ datetime_coerce_class: validator_option.coerce_date_times ? DateTime : nil,
97
+ validate_header: validator_option.check_header,
98
+ }
99
+ if OpenAPIParser::SchemaValidator::Options.method_defined?(:allow_empty_date_and_datetime)
100
+ parser_options[:allow_empty_date_and_datetime] = validator_option.allow_empty_date_and_datetime
101
+ end
102
+ OpenAPIParser::SchemaValidator::Options.new(**parser_options)
97
103
  end
98
104
 
99
105
  def validate_get_request_params(path_params, query_params, headers, validator_option)
@@ -104,7 +110,8 @@ module Committee
104
110
  end
105
111
 
106
112
  def validate_post_request_params(path_params, query_params, body_params, headers, validator_option)
107
- content_type = headers['Content-Type'].to_s.split(";").first.to_s
113
+ content_type_key = headers.keys.detect { |k| k.casecmp?('Content-Type') }
114
+ content_type = headers[content_type_key].to_s.split(';').first.to_s
108
115
 
109
116
  # bad performance because when we coerce value, same check
110
117
  validate_path_and_query_params(path_params, query_params, headers, validator_option)
@@ -130,8 +137,14 @@ module Committee
130
137
  end
131
138
  end
132
139
 
133
- def response_validate_options(strict, check_header)
134
- ::OpenAPIParser::SchemaValidator::ResponseValidateOptions.new(strict: strict, validate_header: check_header)
140
+ def response_validate_options(strict, check_header, validator_options: {})
141
+ options = { strict: strict, validate_header: check_header }
142
+
143
+ if OpenAPIParser::SchemaValidator::ResponseValidateOptions.method_defined?(:validator_options)
144
+ ::OpenAPIParser::SchemaValidator::ResponseValidateOptions.new(**options, **validator_options)
145
+ else
146
+ ::OpenAPIParser::SchemaValidator::ResponseValidateOptions.new(**options)
147
+ end
135
148
  end
136
149
  end
137
150
  end
@@ -12,12 +12,15 @@ module Committee
12
12
  @operation_wrapper = operation_wrapper
13
13
  @validate_success_only = validator_option.validate_success_only
14
14
  @check_header = validator_option.check_header
15
+ @allow_empty_date_and_datetime = validator_option.allow_empty_date_and_datetime
15
16
  end
16
17
 
17
18
  def call(status, headers, response_data, strict)
18
19
  return unless Committee::Middleware::ResponseValidation.validate?(status, validate_success_only)
19
20
 
20
- operation_wrapper.validate_response_params(status, headers, response_data, strict, check_header)
21
+ validator_options = { allow_empty_date_and_datetime: @allow_empty_date_and_datetime }
22
+
23
+ operation_wrapper.validate_response_params(status, headers, response_data, strict, check_header, validator_options: validator_options)
21
24
  end
22
25
 
23
26
  private
@@ -28,16 +28,16 @@ module Committee
28
28
 
29
29
  parse_to_json = if validator_option.parse_response_by_content_type
30
30
  content_type_key = headers.keys.detect { |k| k.casecmp?('Content-Type') }
31
- headers.fetch(content_type_key, nil)&.start_with?('application/json')
32
- else
33
- true
34
- end
31
+ headers.fetch(content_type_key, nil)&.start_with?('application/json')
32
+ else
33
+ true
34
+ end
35
35
 
36
36
  data = if parse_to_json
37
37
  full_body.empty? ? {} : JSON.parse(full_body)
38
- else
39
- full_body
40
- end
38
+ else
39
+ full_body
40
+ end
41
41
 
42
42
  # TODO: refactoring name
43
43
  strict = test_method
@@ -84,6 +84,7 @@ module Committee
84
84
 
85
85
  def request_unpack(request)
86
86
  unpacker = Committee::RequestUnpacker.new(
87
+ allow_empty_date_and_datetime: validator_option.allow_empty_date_and_datetime,
87
88
  allow_form_params: validator_option.allow_form_params,
88
89
  allow_get_body: validator_option.allow_get_body,
89
90
  allow_query_params: validator_option.allow_query_params,
@@ -5,6 +5,7 @@ module Committee
5
5
  class Option
6
6
  # Boolean Options
7
7
  attr_reader :allow_blank_structures,
8
+ :allow_empty_date_and_datetime,
8
9
  :allow_form_params,
9
10
  :allow_get_body,
10
11
  :allow_query_params,
@@ -36,6 +37,7 @@ module Committee
36
37
 
37
38
  # Boolean options and have a common value by default
38
39
  @allow_blank_structures = options.fetch(:allow_blank_structures, false)
40
+ @allow_empty_date_and_datetime = options.fetch(:allow_empty_date_and_datetime, false)
39
41
  @allow_form_params = options.fetch(:allow_form_params, true)
40
42
  @allow_query_params = options.fetch(:allow_query_params, true)
41
43
  @allow_non_get_query_params = options.fetch(:allow_non_get_query_params, false)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Committee
4
- VERSION = '5.5.2'.freeze
4
+ VERSION = '5.5.4'.freeze
5
5
  end
@@ -146,7 +146,7 @@ describe Committee::Middleware::RequestValidation do
146
146
  assert_equal 200, last_response.status
147
147
  end
148
148
 
149
- it "passes given an invalid datetime string with coerce_date_times enabled" do
149
+ it "errors given an invalid datetime string with coerce_date_times enabled" do
150
150
  @app = new_rack_app(schema: open_api_3_schema, coerce_date_times: true)
151
151
  params = { "datetime_string" => "invalid_datetime_format" }
152
152
  get "/string_params_coercer", params
@@ -244,6 +244,50 @@ describe Committee::Middleware::RequestValidation do
244
244
  assert_equal 200, last_response.status
245
245
  end
246
246
 
247
+ it "errors given an empty datetime string with allow_empty_date_and_datetime disabled" do
248
+ @app = new_rack_app(schema: open_api_3_schema)
249
+ params = { "datetime_string" => "" }
250
+ get "/string_params_coercer", params
251
+
252
+ assert_equal 400, last_response.status
253
+ assert_match(/\\"\\" is not conformant with date-time format/i, last_response.body)
254
+ end
255
+
256
+ it "passes given an empty datetime string with allow_empty_date_and_datetime enabled" do
257
+ @app = new_rack_app(schema: open_api_3_schema, allow_empty_date_and_datetime: true)
258
+ params = { "datetime_string" => "" }
259
+ get "/string_params_coercer", params
260
+
261
+ if OpenAPIParser::VERSION >= "2.2.5"
262
+ assert_equal 200, last_response.status
263
+ else
264
+ assert_equal 400, last_response.status
265
+ assert_match(/\\"\\" is not conformant with date-time format/i, last_response.body)
266
+ end
267
+ end
268
+
269
+ it "errors given an empty date string with allow_empty_date_and_datetime disabled" do
270
+ @app = new_rack_app(schema: open_api_3_schema)
271
+ params = { "date_string" => "" }
272
+ get "/string_params_coercer", params
273
+
274
+ assert_equal 400, last_response.status
275
+ assert_match(/\\"\\" is not conformant with date format/i, last_response.body)
276
+ end
277
+
278
+ it "passes given an empty date string with allow_empty_date_and_datetime enabled" do
279
+ @app = new_rack_app(schema: open_api_3_schema, allow_empty_date_and_datetime: true)
280
+ params = { "date_string" => "" }
281
+ get "/string_params_coercer", params
282
+
283
+ if OpenAPIParser::VERSION >= "2.2.5"
284
+ assert_equal 200, last_response.status
285
+ else
286
+ assert_equal 400, last_response.status
287
+ assert_match(/\\"\\" is not conformant with date format/i, last_response.body)
288
+ end
289
+ end
290
+
247
291
  it "OpenAPI3 detects an invalid request" do
248
292
  @app = new_rack_app(schema: open_api_3_schema, strict: true)
249
293
  header "Content-Type", "application/json"
@@ -75,6 +75,76 @@ describe Committee::SchemaValidator::OpenAPI3::ResponseValidator do
75
75
  call_response_validator
76
76
  end
77
77
 
78
+ describe 'allow_empty_date_and_datetime' do
79
+ it "errors given an empty date string with allow_empty_date_and_datetime disabled" do
80
+ @path = '/date_time'
81
+ @method = 'get'
82
+ @data = { 'date' => '' }
83
+
84
+ e = assert_raises(Committee::InvalidResponse) {
85
+ call_response_validator
86
+ }
87
+ assert_kind_of(OpenAPIParser::OpenAPIError, e.original_error)
88
+ assert_match(/\"\" is not conformant with date format/i, e.message)
89
+ end
90
+
91
+ it "errors given an empty date-time string with allow_empty_date_and_datetime disabled" do
92
+ @path = '/date_time'
93
+ @method = 'get'
94
+ @data = { 'date-time' => '' }
95
+
96
+ e = assert_raises(Committee::InvalidResponse) {
97
+ call_response_validator
98
+ }
99
+ assert_kind_of(OpenAPIParser::OpenAPIError, e.original_error)
100
+ assert_match(/\"\" is not conformant with date-time format/i, e.message)
101
+ end
102
+
103
+ it "passes given an empty date string with allow_empty_date_and_datetime enabled" do
104
+ @validator_option = Committee::SchemaValidator::Option.new(
105
+ { allow_empty_date_and_datetime: true },
106
+ open_api_3_schema,
107
+ :open_api_3)
108
+
109
+ @path = '/date_time'
110
+ @method = 'get'
111
+ @data = { 'date' => '' }
112
+
113
+ if OpenAPIParser::VERSION >= "2.2.6"
114
+ response = call_response_validator
115
+ assert_equal({ 'date' => '' }, response)
116
+ else
117
+ e = assert_raises(Committee::InvalidResponse) {
118
+ call_response_validator
119
+ }
120
+ assert_kind_of(OpenAPIParser::OpenAPIError, e.original_error)
121
+ assert_match(/\"\" is not conformant with date format/i, e.message)
122
+ end
123
+ end
124
+
125
+ it "passes given an empty date-time string with allow_empty_date_and_datetime enabled" do
126
+ @validator_option = Committee::SchemaValidator::Option.new(
127
+ { allow_empty_date_and_datetime: true },
128
+ open_api_3_schema,
129
+ :open_api_3)
130
+
131
+ @path = '/date_time'
132
+ @method = 'get'
133
+ @data = { 'date-time' => '' }
134
+
135
+ if OpenAPIParser::VERSION >= "2.2.6"
136
+ response = call_response_validator
137
+ assert_equal({ 'date-time' => '' }, response)
138
+ else
139
+ e = assert_raises(Committee::InvalidResponse) {
140
+ call_response_validator
141
+ }
142
+ assert_kind_of(OpenAPIParser::OpenAPIError, e.original_error)
143
+ assert_match(/\"\" is not conformant with date-time format/i, e.message)
144
+ end
145
+ end
146
+ end
147
+
78
148
  private
79
149
 
80
150
  def call_response_validator(strict = false)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: committee
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.5.2
4
+ version: 5.5.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brandur
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2025-03-28 00:00:00.000000000 Z
13
+ date: 2025-05-14 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: json_schema