openapi_contracts 0.9.1 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +28 -10
- data/lib/openapi_contracts/coverage/report.rb +63 -0
- data/lib/openapi_contracts/coverage/store.rb +19 -0
- data/lib/openapi_contracts/coverage.rb +24 -0
- data/lib/openapi_contracts/doc/operation.rb +8 -2
- data/lib/openapi_contracts/doc/parameter.rb +1 -4
- data/lib/openapi_contracts/doc/path.rb +10 -5
- data/lib/openapi_contracts/doc/pointer.rb +1 -1
- data/lib/openapi_contracts/doc/response.rb +7 -1
- data/lib/openapi_contracts/doc.rb +13 -5
- data/lib/openapi_contracts/match.rb +22 -4
- data/lib/openapi_contracts/parser.rb +6 -2
- data/lib/openapi_contracts/rspec.rb +2 -0
- data/lib/openapi_contracts/validators/schema_validation.rb +14 -20
- data/lib/openapi_contracts.rb +16 -0
- metadata +12 -10
- data/lib/openapi_contracts/parser/transformers/nullable.rb +0 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5891083b3cb25419145aab30a963c61f28973c40b8a4a74ea080b63bc970670b
|
4
|
+
data.tar.gz: 5febe1b938ba77edef2e6955e3b8cf8a161f40e5b5f828c6cc39f5105ed734d7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 87441e69b4caa9ac627e82c27e3d0b0e15162da1587c3bdb7ed4f5c2102fdda02f583df01652676d056b60af24fa9c67dedf38e38b1dfed346211f439de640c2
|
7
|
+
data.tar.gz: a725d1696dc0e7a3ee19bc3c46c1248f0ada9185bb492f44ea5c571944d98dbb6eb0f69625f68169ed931717782438524bbdc337014ea83116ad60a2d565b545
|
data/README.md
CHANGED
@@ -74,6 +74,33 @@ result = OpenapiContracts.match($doc, response, options = {})
|
|
74
74
|
raise result.errors.merge("/n") unless result.valid?
|
75
75
|
```
|
76
76
|
|
77
|
+
## Coverage reporting
|
78
|
+
|
79
|
+
You can generate a coverage report, giving an indication how many of your OpenApi operations and
|
80
|
+
responses are verified.
|
81
|
+
|
82
|
+
To enable the report, set the configuration `OpenapiContracts.collect_coverage = true`.
|
83
|
+
|
84
|
+
After the tests completed, you can generate the JSON file, for example:
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
RSpec.configure do |c|
|
88
|
+
c.after(:suite) do
|
89
|
+
$your_api_doc.coverage.report.generate(Rails.root.join("openapi_coverage.json"))
|
90
|
+
end
|
91
|
+
end
|
92
|
+
```
|
93
|
+
|
94
|
+
In case you run tests on multiple nodes and need to merge reports:
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
OpenapiContracts::Coverage.merge_reports(
|
98
|
+
$your_api_doc,
|
99
|
+
*Dir[Rails.root.join("openapi_coverage_*.json")]
|
100
|
+
).generate(Rails.root.join("openapi_coverage.json"))
|
101
|
+
|
102
|
+
```
|
103
|
+
|
77
104
|
## How it works
|
78
105
|
|
79
106
|
It uses the `request.path`, `request.method`, `status` and `headers` on the test subject
|
@@ -88,16 +115,7 @@ Then it does the following checks:
|
|
88
115
|
|
89
116
|
## Known Issues
|
90
117
|
|
91
|
-
|
92
|
-
|
93
|
-
For openapi schemas < 3.1, data is validated using JSON Schema Draft 04, even tho OpenApi 3.0 is a super+subset of Draft 05.
|
94
|
-
This is due to the fact that we validate the data using json-schemer which does not support 05 and even then would not be fully compatible.
|
95
|
-
However compatibility issues should be fairly rare and there might be workarounds by describing the data slightly different.
|
96
|
-
|
97
|
-
### OpenAPi 3.1
|
98
|
-
|
99
|
-
Here exists a similar problem. OpenApi 3.1 is finally fully compatible with JSON Draft 2020-12, but there is no support yet in json-schemer,
|
100
|
-
so we use the closest draft which is 07.
|
118
|
+
None at the moment :)
|
101
119
|
|
102
120
|
## Future plans
|
103
121
|
|
@@ -0,0 +1,63 @@
|
|
1
|
+
class OpenapiContracts::Coverage
|
2
|
+
class Report
|
3
|
+
def self.merge(doc, *reports)
|
4
|
+
reports.each_with_object(Report.new(doc)) do |r, m|
|
5
|
+
m.merge!(r)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :data
|
10
|
+
|
11
|
+
def as_json(*)
|
12
|
+
report
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(doc, data = {})
|
16
|
+
@doc = doc
|
17
|
+
@data = data
|
18
|
+
end
|
19
|
+
|
20
|
+
def generate(pathname)
|
21
|
+
File.write(pathname, JSON.pretty_generate(report))
|
22
|
+
end
|
23
|
+
|
24
|
+
def merge!(data)
|
25
|
+
@data.deep_merge!(data) { |_key, val1, val2| val1 + val2 }
|
26
|
+
end
|
27
|
+
|
28
|
+
def meta
|
29
|
+
{
|
30
|
+
'operations' => {
|
31
|
+
'covered' => total_covered_operations,
|
32
|
+
'total' => @doc.operations.count
|
33
|
+
},
|
34
|
+
'responses' => {
|
35
|
+
'covered' => total_covered_responses,
|
36
|
+
'total' => @doc.responses.count
|
37
|
+
}
|
38
|
+
}.tap do |d|
|
39
|
+
d['operations']['quota'] = d['operations']['covered'].to_f / d['operations']['total']
|
40
|
+
d['responses']['quota'] = d['responses']['covered'].to_f / d['responses']['total']
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def report
|
47
|
+
{
|
48
|
+
'meta' => meta,
|
49
|
+
'paths' => @data
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def total_covered_operations
|
54
|
+
@doc.operations.select { |o| @data.dig(o.path.to_s, o.verb).present? }.count
|
55
|
+
end
|
56
|
+
|
57
|
+
def total_covered_responses
|
58
|
+
@doc.responses.select { |r|
|
59
|
+
@data.dig(r.operation.path.to_s, r.operation.verb, r.status).present?
|
60
|
+
}.count
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class OpenapiContracts::Coverage
|
2
|
+
class Store
|
3
|
+
attr_accessor :data
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@data = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def clear!
|
10
|
+
@data = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def increment!(path, method, status, media_type)
|
14
|
+
keys = [path, method, status]
|
15
|
+
val = @data.dig(*keys) || Hash.new(0).tap { |h| OpenapiContracts.hash_bury!(@data, keys, h) }
|
16
|
+
val[media_type] += 1
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module OpenapiContracts
|
2
|
+
class Coverage
|
3
|
+
autoload :Report, 'openapi_contracts/coverage/report'
|
4
|
+
autoload :Store, 'openapi_contracts/coverage/store'
|
5
|
+
|
6
|
+
def self.merge_reports(doc, *others)
|
7
|
+
reports = others.map { |fp| JSON(File.read(fp))['paths'] }
|
8
|
+
Report.merge(doc, *reports)
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :store
|
12
|
+
|
13
|
+
def initialize(doc)
|
14
|
+
@store = Store.new
|
15
|
+
@doc = doc
|
16
|
+
end
|
17
|
+
|
18
|
+
delegate :clear!, :data, :increment!, to: :store
|
19
|
+
|
20
|
+
def report
|
21
|
+
Report.new(@doc, store.data)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -2,14 +2,20 @@ module OpenapiContracts
|
|
2
2
|
class Doc::Operation
|
3
3
|
include Doc::WithParameters
|
4
4
|
|
5
|
+
attr_reader :path
|
6
|
+
|
5
7
|
def initialize(path, spec)
|
6
8
|
@path = path
|
7
9
|
@spec = spec
|
8
|
-
@responses = spec.navigate('responses').each.to_h do |status, subspec|
|
9
|
-
[status, Doc::Response.new(subspec)]
|
10
|
+
@responses = spec.navigate('responses').each.to_h do |status, subspec|
|
11
|
+
[status, Doc::Response.new(self, status, subspec)]
|
10
12
|
end
|
11
13
|
end
|
12
14
|
|
15
|
+
def verb
|
16
|
+
@spec.pointer[2]
|
17
|
+
end
|
18
|
+
|
13
19
|
def request_body
|
14
20
|
return @request_body if instance_variable_defined?(:@request_body)
|
15
21
|
|
@@ -28,10 +28,7 @@ module OpenapiContracts
|
|
28
28
|
private
|
29
29
|
|
30
30
|
def schemer
|
31
|
-
@schemer ||=
|
32
|
-
schema = @spec.navigate('schema')
|
33
|
-
JSONSchemer.schema(Validators::SchemaValidation.build_validation_schema(schema))
|
34
|
-
end
|
31
|
+
@schemer ||= Validators::SchemaValidation.validation_schemer(@spec.navigate('schema'))
|
35
32
|
end
|
36
33
|
|
37
34
|
def integer_parameter_matches?(value)
|
@@ -10,6 +10,9 @@ module OpenapiContracts
|
|
10
10
|
@path = path
|
11
11
|
@spec = spec
|
12
12
|
@supported_methods = HTTP_METHODS & @spec.keys
|
13
|
+
@operations = @supported_methods.to_h do |verb|
|
14
|
+
[verb, Doc::Operation.new(self, @spec.navigate(verb))]
|
15
|
+
end
|
13
16
|
end
|
14
17
|
|
15
18
|
def dynamic?
|
@@ -17,7 +20,7 @@ module OpenapiContracts
|
|
17
20
|
end
|
18
21
|
|
19
22
|
def operations
|
20
|
-
@
|
23
|
+
@operations.each_value
|
21
24
|
end
|
22
25
|
|
23
26
|
def path_regexp
|
@@ -34,13 +37,15 @@ module OpenapiContracts
|
|
34
37
|
end
|
35
38
|
|
36
39
|
def supports_method?(method)
|
37
|
-
@
|
40
|
+
@operations.key?(method)
|
38
41
|
end
|
39
42
|
|
40
|
-
def
|
41
|
-
|
43
|
+
def to_s
|
44
|
+
@path
|
45
|
+
end
|
42
46
|
|
43
|
-
|
47
|
+
def with_method(method)
|
48
|
+
@operations[method]
|
44
49
|
end
|
45
50
|
end
|
46
51
|
end
|
@@ -1,6 +1,12 @@
|
|
1
1
|
module OpenapiContracts
|
2
2
|
class Doc::Response
|
3
|
-
|
3
|
+
attr_reader :coverage, :schema, :status, :operation
|
4
|
+
|
5
|
+
delegate :pointer, to: :schema
|
6
|
+
|
7
|
+
def initialize(operation, status, schema)
|
8
|
+
@operation = operation
|
9
|
+
@status = status
|
4
10
|
@schema = schema.follow_refs
|
5
11
|
end
|
6
12
|
|
@@ -14,7 +14,7 @@ module OpenapiContracts
|
|
14
14
|
new Parser.call(dir, filename)
|
15
15
|
end
|
16
16
|
|
17
|
-
attr_reader :schema
|
17
|
+
attr_reader :coverage, :schema
|
18
18
|
|
19
19
|
def initialize(raw)
|
20
20
|
@schema = Schema.new(raw)
|
@@ -22,6 +22,7 @@ module OpenapiContracts
|
|
22
22
|
[path, Path.new(path, @schema.at_pointer(Doc::Pointer['paths', path]))]
|
23
23
|
end
|
24
24
|
@dynamic_paths = paths.select(&:dynamic?)
|
25
|
+
@coverage = Coverage.new(self)
|
25
26
|
end
|
26
27
|
|
27
28
|
# Returns an Enumerator over all paths
|
@@ -33,14 +34,21 @@ module OpenapiContracts
|
|
33
34
|
OperationRouter.new(self).route(path, method.downcase)
|
34
35
|
end
|
35
36
|
|
37
|
+
# Returns an Enumerator over all Operations
|
38
|
+
def operations(&block)
|
39
|
+
return enum_for(:operations) unless block_given?
|
40
|
+
|
41
|
+
paths.each do |path|
|
42
|
+
path.operations.each(&block)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
36
46
|
# Returns an Enumerator over all Responses
|
37
47
|
def responses(&block)
|
38
48
|
return enum_for(:responses) unless block_given?
|
39
49
|
|
40
|
-
|
41
|
-
|
42
|
-
operation.responses.each(&block)
|
43
|
-
end
|
50
|
+
operations.each do |operation|
|
51
|
+
operation.responses.each(&block)
|
44
52
|
end
|
45
53
|
end
|
46
54
|
|
@@ -19,11 +19,20 @@ module OpenapiContracts
|
|
19
19
|
return @errors.empty? if instance_variable_defined?(:@errors)
|
20
20
|
|
21
21
|
@errors = matchers.call
|
22
|
+
@doc.coverage.increment!(operation.path.to_s, request_method, status, media_type) if collect_coverage?
|
22
23
|
@errors.empty?
|
23
24
|
end
|
24
25
|
|
25
26
|
private
|
26
27
|
|
28
|
+
def collect_coverage?
|
29
|
+
OpenapiContracts.collect_coverage && @request.present? && @errors.empty? && !@options[:nocov]
|
30
|
+
end
|
31
|
+
|
32
|
+
def media_type
|
33
|
+
@response.headers['Content-Type']&.split(';')&.first || 'no_content'
|
34
|
+
end
|
35
|
+
|
27
36
|
def matchers
|
28
37
|
env = Env.new(
|
29
38
|
options: @options,
|
@@ -39,10 +48,7 @@ module OpenapiContracts
|
|
39
48
|
end
|
40
49
|
|
41
50
|
def operation
|
42
|
-
@doc.operation_for(
|
43
|
-
@options.fetch(:path, @request.path),
|
44
|
-
@request.request_method.downcase
|
45
|
-
)
|
51
|
+
@operation ||= @doc.operation_for(path, request_method)
|
46
52
|
end
|
47
53
|
|
48
54
|
def request_compatible?
|
@@ -54,5 +60,17 @@ module OpenapiContracts
|
|
54
60
|
ancestors = @response.class.ancestors.map(&:to_s)
|
55
61
|
MIN_RESPONSE_ANCESTORS.all? { |s| ancestors.include?(s) }
|
56
62
|
end
|
63
|
+
|
64
|
+
def request_method
|
65
|
+
@request.request_method.downcase
|
66
|
+
end
|
67
|
+
|
68
|
+
def path
|
69
|
+
@options.fetch(:path, @request.path)
|
70
|
+
end
|
71
|
+
|
72
|
+
def status
|
73
|
+
@response.status.to_s
|
74
|
+
end
|
57
75
|
end
|
58
76
|
end
|
@@ -2,7 +2,7 @@ module OpenapiContracts
|
|
2
2
|
class Parser
|
3
3
|
autoload :Transformers, 'openapi_contracts/parser/transformers'
|
4
4
|
|
5
|
-
TRANSFORMERS = [Transformers::
|
5
|
+
TRANSFORMERS = [Transformers::Pointer].freeze
|
6
6
|
|
7
7
|
def self.call(dir, filename)
|
8
8
|
new(dir.join(filename)).parse
|
@@ -20,13 +20,17 @@ module OpenapiContracts
|
|
20
20
|
@filenesting = build_file_list
|
21
21
|
@filenesting.each_with_object({}) do |(path, pointer), schema|
|
22
22
|
target = pointer.to_a.reduce(schema) { |d, k| d[k] ||= {} }
|
23
|
-
target.delete('$ref') # ref file pointers
|
23
|
+
target.delete('$ref') # ref file pointers should be in the file list so save to delete
|
24
24
|
target.merge! file_to_data(path, pointer)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
28
|
private
|
29
29
|
|
30
|
+
# file list consists of
|
31
|
+
# - root file
|
32
|
+
# - all files in components/
|
33
|
+
# - all path files referenced by the root file
|
30
34
|
def build_file_list
|
31
35
|
list = {@rootfile.relative_path_from(@cwd) => Doc::Pointer[]}
|
32
36
|
Dir[File.expand_path('components/**/*.yaml', @cwd)].each do |file|
|
@@ -19,9 +19,11 @@ RSpec::Matchers.define :match_openapi_doc do |doc, options = {}| # rubocop:disab
|
|
19
19
|
desc
|
20
20
|
end
|
21
21
|
|
22
|
+
# :nocov:
|
22
23
|
failure_message do |_response|
|
23
24
|
@errors.map { |e| "* #{e}" }.join("\n")
|
24
25
|
end
|
26
|
+
# :nocov:
|
25
27
|
|
26
28
|
def with_http_status(status)
|
27
29
|
if status.is_a? Symbol
|
@@ -2,37 +2,31 @@ module OpenapiContracts::Validators
|
|
2
2
|
module SchemaValidation
|
3
3
|
module_function
|
4
4
|
|
5
|
-
def
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
)
|
5
|
+
def error_to_message(error)
|
6
|
+
msg = error['error']
|
7
|
+
msg.sub!(/^value/, error['data'].to_json) if error['data'].to_json.length < 50
|
8
|
+
msg
|
10
9
|
end
|
11
10
|
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
error['details'].to_a.map { |(key, val)|
|
16
|
-
"#{key.humanize}: #{val}#{pointer}"
|
17
|
-
}.to_sentence
|
11
|
+
def schema_draft_version(schema)
|
12
|
+
if schema.openapi_version.blank? || schema.openapi_version < Gem::Version.new('3.1')
|
13
|
+
JSONSchemer.openapi30
|
18
14
|
else
|
19
|
-
|
15
|
+
JSONSchemer.openapi31
|
20
16
|
end
|
21
17
|
end
|
22
18
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
26
|
-
|
19
|
+
def validation_schemer(schema)
|
20
|
+
schemer = JSONSchemer.schema(schema.raw, meta_schema: schema_draft_version(schema))
|
21
|
+
if schema.pointer.any?
|
22
|
+
schemer.ref(schema.fragment)
|
27
23
|
else
|
28
|
-
|
29
|
-
'http://json-schema.org/draft-07/schema#'
|
24
|
+
schemer
|
30
25
|
end
|
31
26
|
end
|
32
27
|
|
33
28
|
def validate_schema(schema, data)
|
34
|
-
|
35
|
-
schemer.validate(data).map do |err|
|
29
|
+
validation_schemer(schema).validate(data).map do |err|
|
36
30
|
error_to_message(err)
|
37
31
|
end
|
38
32
|
end
|
data/lib/openapi_contracts.rb
CHANGED
@@ -11,6 +11,7 @@ require 'rack'
|
|
11
11
|
require 'yaml'
|
12
12
|
|
13
13
|
module OpenapiContracts
|
14
|
+
autoload :Coverage, 'openapi_contracts/coverage'
|
14
15
|
autoload :Doc, 'openapi_contracts/doc'
|
15
16
|
autoload :Helper, 'openapi_contracts/helper'
|
16
17
|
autoload :Match, 'openapi_contracts/match'
|
@@ -19,13 +20,28 @@ module OpenapiContracts
|
|
19
20
|
autoload :PayloadParser, 'openapi_contracts/payload_parser'
|
20
21
|
autoload :Validators, 'openapi_contracts/validators'
|
21
22
|
|
23
|
+
include ActiveSupport::Configurable
|
24
|
+
|
22
25
|
Env = Struct.new(:operation, :options, :request, :response, keyword_init: true)
|
23
26
|
|
27
|
+
config_accessor(:collect_coverage) { false }
|
28
|
+
|
24
29
|
module_function
|
25
30
|
|
26
31
|
def match(doc, response, options = {})
|
27
32
|
Match.new(doc, response, options)
|
28
33
|
end
|
34
|
+
|
35
|
+
def hash_bury(hash, keys, value)
|
36
|
+
other = keys.reverse.reduce(value) { |m, k| {k => m} }
|
37
|
+
hash.deep_merge other
|
38
|
+
end
|
39
|
+
|
40
|
+
def hash_bury!(hash, keys, value)
|
41
|
+
other = keys.reverse.reduce(value) { |m, k| {k => m} }
|
42
|
+
hash.deep_merge! other
|
43
|
+
other
|
44
|
+
end
|
29
45
|
end
|
30
46
|
|
31
47
|
require 'openapi_contracts/rspec' if defined?(RSpec)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: openapi_contracts
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- mkon
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-09-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -36,14 +36,14 @@ dependencies:
|
|
36
36
|
requirements:
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version:
|
39
|
+
version: 2.0.0
|
40
40
|
type: :runtime
|
41
41
|
prerelease: false
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
44
|
- - "~>"
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version:
|
46
|
+
version: 2.0.0
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rack
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -92,28 +92,28 @@ dependencies:
|
|
92
92
|
requirements:
|
93
93
|
- - '='
|
94
94
|
- !ruby/object:Gem::Version
|
95
|
-
version: 1.
|
95
|
+
version: 1.56.1
|
96
96
|
type: :development
|
97
97
|
prerelease: false
|
98
98
|
version_requirements: !ruby/object:Gem::Requirement
|
99
99
|
requirements:
|
100
100
|
- - '='
|
101
101
|
- !ruby/object:Gem::Version
|
102
|
-
version: 1.
|
102
|
+
version: 1.56.1
|
103
103
|
- !ruby/object:Gem::Dependency
|
104
104
|
name: rubocop-rspec
|
105
105
|
requirement: !ruby/object:Gem::Requirement
|
106
106
|
requirements:
|
107
107
|
- - '='
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version: 2.23.
|
109
|
+
version: 2.23.2
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
112
|
version_requirements: !ruby/object:Gem::Requirement
|
113
113
|
requirements:
|
114
114
|
- - '='
|
115
115
|
- !ruby/object:Gem::Version
|
116
|
-
version: 2.23.
|
116
|
+
version: 2.23.2
|
117
117
|
- !ruby/object:Gem::Dependency
|
118
118
|
name: simplecov
|
119
119
|
requirement: !ruby/object:Gem::Requirement
|
@@ -137,6 +137,9 @@ extra_rdoc_files: []
|
|
137
137
|
files:
|
138
138
|
- README.md
|
139
139
|
- lib/openapi_contracts.rb
|
140
|
+
- lib/openapi_contracts/coverage.rb
|
141
|
+
- lib/openapi_contracts/coverage/report.rb
|
142
|
+
- lib/openapi_contracts/coverage/store.rb
|
140
143
|
- lib/openapi_contracts/doc.rb
|
141
144
|
- lib/openapi_contracts/doc/header.rb
|
142
145
|
- lib/openapi_contracts/doc/operation.rb
|
@@ -153,7 +156,6 @@ files:
|
|
153
156
|
- lib/openapi_contracts/parser.rb
|
154
157
|
- lib/openapi_contracts/parser/transformers.rb
|
155
158
|
- lib/openapi_contracts/parser/transformers/base.rb
|
156
|
-
- lib/openapi_contracts/parser/transformers/nullable.rb
|
157
159
|
- lib/openapi_contracts/parser/transformers/pointer.rb
|
158
160
|
- lib/openapi_contracts/payload_parser.rb
|
159
161
|
- lib/openapi_contracts/rspec.rb
|
@@ -188,7 +190,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
188
190
|
- !ruby/object:Gem::Version
|
189
191
|
version: '0'
|
190
192
|
requirements: []
|
191
|
-
rubygems_version: 3.4.
|
193
|
+
rubygems_version: 3.4.18
|
192
194
|
signing_key:
|
193
195
|
specification_version: 4
|
194
196
|
summary: Openapi schemas as API contracts
|