rspec-json_api 1.4.0 → 1.6.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +77 -28
- data/README.md +320 -319
- data/lib/generators/rspec/json_api/interface/interface_generator.rb +3 -1
- data/lib/generators/rspec/json_api/type/type_generator.rb +25 -23
- data/lib/rspec/json_api/constraints.rb +58 -0
- data/lib/rspec/json_api/matchers/match_json_schema.rb +35 -11
- data/lib/rspec/json_api/schema_match.rb +162 -0
- data/lib/rspec/json_api/traversal.rb +49 -0
- data/lib/rspec/json_api/types/uri.rb +5 -1
- data/lib/rspec/json_api/types/uuid.rb +1 -1
- data/lib/rspec/json_api/version.rb +7 -7
- data/lib/rspec/json_api.rb +23 -25
- metadata +8 -26
- data/.github/workflows/main.yml +0 -20
- data/.gitignore +0 -11
- data/.rspec +0 -3
- data/.rubocop.yml +0 -50
- data/.ruby-version +0 -1
- data/CODE_OF_CONDUCT.md +0 -84
- data/Gemfile +0 -14
- data/Gemfile.lock +0 -262
- data/Rakefile +0 -12
- data/bin/console +0 -15
- data/bin/setup +0 -8
- data/lib/extensions/array.rb +0 -8
- data/lib/extensions/hash.rb +0 -36
- data/lib/generators/rspec/json_api/interface/templates/interface.erb +0 -9
- data/lib/rspec/json_api/compare_array.rb +0 -39
- data/lib/rspec/json_api/compare_hash.rb +0 -114
- data/rspec-json_api.gemspec +0 -38
|
@@ -1,23 +1,25 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Rspec
|
|
4
|
-
module JsonApi
|
|
5
|
-
module Generators
|
|
6
|
-
class TypeGenerator < Rails::Generators::NamedBase
|
|
7
|
-
source_root File.expand_path("templates", __dir__)
|
|
8
|
-
|
|
9
|
-
def copy_type_file
|
|
10
|
-
create_file "spec/rspec/json_api/types/#{file_name}.rb", <<~FILE
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rspec
|
|
4
|
+
module JsonApi
|
|
5
|
+
module Generators
|
|
6
|
+
class TypeGenerator < Rails::Generators::NamedBase
|
|
7
|
+
source_root File.expand_path("templates", __dir__)
|
|
8
|
+
|
|
9
|
+
def copy_type_file
|
|
10
|
+
create_file "spec/rspec/json_api/types/#{file_name}.rb", <<~FILE
|
|
11
|
+
# frozen_string_literal: true
|
|
12
|
+
|
|
13
|
+
module RSpec
|
|
14
|
+
module JsonApi
|
|
15
|
+
module Types
|
|
16
|
+
#{file_name.upcase} = //
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
FILE
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RSpec
|
|
4
|
+
module JsonApi
|
|
5
|
+
# Constraints evaluates the option hash produced by a schema Proc
|
|
6
|
+
# (e.g. `-> { { type: Integer, min: 1, max: 10, allow_blank: true } }`)
|
|
7
|
+
# against an actual value.
|
|
8
|
+
#
|
|
9
|
+
# allow_blank is a modifier, not a constraint of its own: when it is true a
|
|
10
|
+
# blank value is accepted and the remaining options are skipped; otherwise
|
|
11
|
+
# the value is checked against every other option.
|
|
12
|
+
module Constraints
|
|
13
|
+
module_function
|
|
14
|
+
|
|
15
|
+
SUPPORTED_OPTIONS = %i[allow_blank type value min max inclusion regex lambda].freeze
|
|
16
|
+
|
|
17
|
+
# @param value [Object] the actual value being matched.
|
|
18
|
+
# @param options [Hash] the option hash returned by the schema Proc.
|
|
19
|
+
# @return [Boolean] true when the value satisfies the options.
|
|
20
|
+
# @raise [ArgumentError] when an option key is not supported.
|
|
21
|
+
def match(value, options)
|
|
22
|
+
validate!(options)
|
|
23
|
+
|
|
24
|
+
return true if value.blank? && options[:allow_blank]
|
|
25
|
+
|
|
26
|
+
options.except(:allow_blank).all? do |option, condition|
|
|
27
|
+
satisfies?(value, option, condition)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def validate!(options)
|
|
32
|
+
raise ArgumentError, "options must be a Hash, got #{options.class}" unless options.is_a?(Hash)
|
|
33
|
+
|
|
34
|
+
unknown = options.keys - SUPPORTED_OPTIONS
|
|
35
|
+
return if unknown.empty?
|
|
36
|
+
|
|
37
|
+
raise ArgumentError, "Unsupported match option(s): #{unknown.join(", ")}"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def satisfies?(value, option, condition)
|
|
41
|
+
case option
|
|
42
|
+
when :type then value.instance_of?(condition)
|
|
43
|
+
when :value then value == condition
|
|
44
|
+
when :inclusion then condition.include?(value)
|
|
45
|
+
when :regex then condition.match?(value.to_s)
|
|
46
|
+
when :lambda then condition.call(value)
|
|
47
|
+
when :min, :max then within_bound?(value, option, condition)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def within_bound?(value, option, condition)
|
|
52
|
+
return false unless value.is_a?(Numeric) && condition.is_a?(Numeric)
|
|
53
|
+
|
|
54
|
+
option == :min ? value >= condition : value <= condition
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -23,38 +23,62 @@ module RSpec
|
|
|
23
23
|
# @param actual [String] The JSON string to test against the expected schema.
|
|
24
24
|
# @return [Boolean] true if the actual JSON matches the expected schema, false otherwise.
|
|
25
25
|
def matches?(actual)
|
|
26
|
-
@
|
|
27
|
-
@
|
|
26
|
+
@diff = nil
|
|
27
|
+
@actual = actual
|
|
28
|
+
@type_error = !actual.is_a?(String)
|
|
29
|
+
|
|
30
|
+
return false if @type_error
|
|
28
31
|
|
|
29
|
-
|
|
32
|
+
@actual = JSON.parse(actual, symbolize_names: true)
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
RSpec::JsonApi::SchemaMatch.match(@actual, expected)
|
|
35
|
+
rescue JSON::ParserError
|
|
36
|
+
@actual = actual
|
|
37
|
+
false
|
|
38
|
+
end
|
|
35
39
|
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
# A non-String actual is a mistake in the spec rather than a fact about the
|
|
41
|
+
# response, so the negated form has to fail rather than pass by default.
|
|
42
|
+
# @param actual [String] The JSON string to test against the expected schema.
|
|
43
|
+
# @return [Boolean] true if the actual JSON does not match the expected schema.
|
|
44
|
+
def does_not_match?(actual)
|
|
45
|
+
!matches?(actual) && !@type_error
|
|
38
46
|
end
|
|
39
47
|
|
|
40
48
|
# Provides a failure message for when the JSON data does not match the expected schema.
|
|
41
49
|
# @return [String] A descriptive message detailing the mismatch between expected and actual JSON.
|
|
42
50
|
def failure_message
|
|
51
|
+
return type_error_message if @type_error
|
|
52
|
+
|
|
43
53
|
<<~MSG
|
|
44
54
|
expected: #{expected}
|
|
45
55
|
got: #{actual}
|
|
46
56
|
|
|
47
57
|
Diff:
|
|
48
|
-
#{
|
|
58
|
+
#{diff}
|
|
49
59
|
MSG
|
|
50
60
|
end
|
|
51
61
|
|
|
52
62
|
# Provides a failure message for when the JSON data matches the expected schema, but it was expected not to.
|
|
53
63
|
# This is used in negative matchers.
|
|
54
|
-
# @return [
|
|
64
|
+
# @return [String] A descriptive message indicating the JSON was expected not to match the schema.
|
|
55
65
|
def failure_message_when_negated
|
|
66
|
+
return type_error_message if @type_error
|
|
67
|
+
|
|
56
68
|
"expected the JSON data not to match the provided schema, but it did."
|
|
57
69
|
end
|
|
70
|
+
|
|
71
|
+
private
|
|
72
|
+
|
|
73
|
+
# The diff is only needed to render a failure message, so it is built
|
|
74
|
+
# lazily and memoized rather than on every matches? call.
|
|
75
|
+
def diff
|
|
76
|
+
@diff ||= Diffy::Diff.new(expected, actual, context: 5)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def type_error_message
|
|
80
|
+
"expected a JSON String to match against the schema, got #{actual.class}"
|
|
81
|
+
end
|
|
58
82
|
end
|
|
59
83
|
end
|
|
60
84
|
end
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RSpec
|
|
4
|
+
module JsonApi
|
|
5
|
+
# SchemaMatch compares parsed JSON (a Hash, an Array, or a scalar) against an
|
|
6
|
+
# expected schema. It is the single entry point behind the match_json_schema
|
|
7
|
+
# matcher: callers hand it the actual and expected values and it dispatches on
|
|
8
|
+
# shape internally, so the matcher does not need to know whether it is looking
|
|
9
|
+
# at an object or a collection.
|
|
10
|
+
module SchemaMatch
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
# Top-level comparison. Applies the shape guards (class equality and, for
|
|
14
|
+
# objects, key-set equality) before recursing.
|
|
15
|
+
def match(actual, expected)
|
|
16
|
+
return false unless actual.instance_of?(expected.class)
|
|
17
|
+
|
|
18
|
+
case expected
|
|
19
|
+
when Array
|
|
20
|
+
compare_array(actual, expected)
|
|
21
|
+
when Hash
|
|
22
|
+
return false unless same_key_structure?(actual, expected)
|
|
23
|
+
|
|
24
|
+
compare(actual, expected)
|
|
25
|
+
else
|
|
26
|
+
compare_simple_value(actual, expected)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def same_key_structure?(actual, expected)
|
|
31
|
+
Traversal.deep_sort(Traversal.deep_keys(actual)) ==
|
|
32
|
+
Traversal.deep_sort(Traversal.deep_keys(expected))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def compare(actual, expected)
|
|
36
|
+
return false unless actual.is_a?(Hash)
|
|
37
|
+
return false if actual.blank? && expected.present?
|
|
38
|
+
|
|
39
|
+
keys = Traversal.deep_key_paths(expected) | Traversal.deep_key_paths(actual)
|
|
40
|
+
|
|
41
|
+
compare_key_paths_and_values(keys, actual, expected)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def compare_key_paths_and_values(keys, actual, expected)
|
|
45
|
+
keys.all? do |key_path|
|
|
46
|
+
actual_value = dig_path(actual, key_path)
|
|
47
|
+
expected_value = dig_path(expected, key_path)
|
|
48
|
+
|
|
49
|
+
compare_values(actual_value, expected_value)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Digs a key path without raising when an intermediate value is not a Hash.
|
|
54
|
+
# Plain Hash#dig raises TypeError if it walks into a scalar (e.g. a schema
|
|
55
|
+
# expects a nested object but the actual value is a String), so a mismatch
|
|
56
|
+
# would crash instead of failing the match.
|
|
57
|
+
def dig_path(data, key_path)
|
|
58
|
+
key_path.reduce(data) do |value, key|
|
|
59
|
+
break nil unless value.is_a?(Hash)
|
|
60
|
+
|
|
61
|
+
value[key]
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def compare_values(actual_value, expected_value)
|
|
66
|
+
case expected_value
|
|
67
|
+
when Class then compare_class(actual_value, expected_value)
|
|
68
|
+
when Regexp then compare_regexp(actual_value, expected_value)
|
|
69
|
+
when Proc then compare_proc(actual_value, expected_value)
|
|
70
|
+
when Array then compare_array(actual_value, expected_value)
|
|
71
|
+
else compare_simple_value(actual_value, expected_value)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def compare_class(actual_value, expected_value)
|
|
76
|
+
actual_value.instance_of?(expected_value)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def compare_regexp(actual_value, expected_value)
|
|
80
|
+
expected_value.match?(actual_value.to_s)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# A schema Proc describes the constraints for a value; it is called without
|
|
84
|
+
# arguments and must return the option Hash. A Proc that expects the value
|
|
85
|
+
# as an argument is a common misreading of the DSL, and calling it here
|
|
86
|
+
# would raise a bare "wrong number of arguments" from deep in the matcher.
|
|
87
|
+
def compare_proc(actual_value, expected_value)
|
|
88
|
+
if declares_value_parameter?(expected_value)
|
|
89
|
+
raise ArgumentError,
|
|
90
|
+
"schema Proc must take no arguments; " \
|
|
91
|
+
"write -> { { lambda: ->(value) { ... } } } to test the value itself"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
options = expected_value.call
|
|
95
|
+
raise ArgumentError, "schema Proc must return an options Hash, got #{options.class}" unless options.is_a?(Hash)
|
|
96
|
+
|
|
97
|
+
Constraints.match(actual_value, options)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# A non-lambda Proc reports its block parameters as optional, so
|
|
101
|
+
# `proc { |value| ... }` has to be caught on the parameter list rather
|
|
102
|
+
# than on arity. A bare splat states no expectation and is left alone.
|
|
103
|
+
def declares_value_parameter?(callable)
|
|
104
|
+
callable.parameters.any? { |type, _name| %i[req opt keyreq].include?(type) }
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# A list schema only ever matches an actual Array. Without this guard the
|
|
108
|
+
# branches below call Array methods on whatever the response contained, so
|
|
109
|
+
# a null or a scalar where a list was expected raised NoMethodError
|
|
110
|
+
# instead of failing the match.
|
|
111
|
+
def compare_array(actual_value, expected_value)
|
|
112
|
+
return false unless actual_value.is_a?(Array)
|
|
113
|
+
|
|
114
|
+
if simple_type?(expected_value)
|
|
115
|
+
compare_typed_array(actual_value, expected_value)
|
|
116
|
+
elsif interface?(expected_value)
|
|
117
|
+
compare_interface_array(actual_value, expected_value)
|
|
118
|
+
else
|
|
119
|
+
compare_exact_array(actual_value, expected_value)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# [SomeClass] => every element must be an instance of SomeClass.
|
|
124
|
+
def compare_typed_array(actual_value, expected_value)
|
|
125
|
+
type = expected_value[0]
|
|
126
|
+
|
|
127
|
+
actual_value.all? { |elem| compare_class(elem, type) }
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# [{ ...interface... }] => every element must match the single interface.
|
|
131
|
+
# Elements go through match (not compare) so each one is held to the same
|
|
132
|
+
# key-structure guard as a top-level object; otherwise an element with an
|
|
133
|
+
# extra null-valued key would slip through (nil == nil).
|
|
134
|
+
def compare_interface_array(actual_value, expected_value)
|
|
135
|
+
interface = expected_value[0]
|
|
136
|
+
|
|
137
|
+
actual_value.all? { |elem| match(elem, interface) }
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Any other array => element-by-element match, sizes must be equal.
|
|
141
|
+
def compare_exact_array(actual_value, expected_value)
|
|
142
|
+
return false if actual_value.size != expected_value.size
|
|
143
|
+
|
|
144
|
+
expected_value.each_with_index.all? do |elem, index|
|
|
145
|
+
elem.is_a?(Hash) ? compare(actual_value[index], elem) : compare_values(actual_value[index], elem)
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def compare_simple_value(actual_value, expected_value)
|
|
150
|
+
actual_value == expected_value
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def simple_type?(expected_value)
|
|
154
|
+
expected_value.size == 1 && expected_value[0].instance_of?(Class)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def interface?(expected_value)
|
|
158
|
+
expected_value.size == 1 && expected_value[0].is_a?(Hash)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RSpec
|
|
4
|
+
module JsonApi
|
|
5
|
+
# Traversal holds the structural helpers used to compare JSON shapes:
|
|
6
|
+
# collecting the nested key structure of a Hash and sorting it into a
|
|
7
|
+
# canonical order. These were previously monkey-patched onto core Hash and
|
|
8
|
+
# Array; keeping them here means the gem no longer mutates those classes in
|
|
9
|
+
# the host application.
|
|
10
|
+
module Traversal
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
# The nested keys of a hash, with each nested hash's keys inlined as an
|
|
14
|
+
# array, e.g. { a: 1, b: { c: 2 } } => [:a, :b, [:c]].
|
|
15
|
+
def deep_keys(hash)
|
|
16
|
+
hash.each_with_object([]) do |(key, value), keys|
|
|
17
|
+
keys << key
|
|
18
|
+
keys << deep_keys(value) if value.respond_to?(:keys)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Every leaf key path of a hash, e.g. { a: { b: 1 }, c: 2 } => [[:a, :b], [:c]].
|
|
23
|
+
def deep_key_paths(hash)
|
|
24
|
+
stack = hash.map { |key, value| [[key], value] }
|
|
25
|
+
key_map = []
|
|
26
|
+
|
|
27
|
+
until stack.empty?
|
|
28
|
+
key, value = stack.pop
|
|
29
|
+
|
|
30
|
+
key_map << key unless value.is_a?(Hash)
|
|
31
|
+
|
|
32
|
+
next unless value.is_a?(Hash)
|
|
33
|
+
|
|
34
|
+
value.each { |k, v| stack.push([key.dup << k, v]) }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
key_map.reverse
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Recursively sorts an array (and any nested arrays) into a canonical order
|
|
41
|
+
# so two key structures can be compared regardless of original order.
|
|
42
|
+
def deep_sort(array)
|
|
43
|
+
array
|
|
44
|
+
.map { |element| element.is_a?(Array) ? deep_sort(element) : element }
|
|
45
|
+
.sort_by { |element| element.is_a?(Array) ? element.first.to_s : element.to_s }
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
module RSpec
|
|
4
4
|
module JsonApi
|
|
5
5
|
module Types
|
|
6
|
-
|
|
6
|
+
# URI::DEFAULT_PARSER.make_regexp is unanchored, and comparison uses
|
|
7
|
+
# Regexp#match?, so on its own it accepts any string that merely contains
|
|
8
|
+
# a URI ("see https://example.com for details"). \A...\z holds the whole
|
|
9
|
+
# value to the pattern, the same way EMAIL and UUID already are anchored.
|
|
10
|
+
URI = /\A#{::URI::DEFAULT_PARSER.make_regexp}\z/
|
|
7
11
|
end
|
|
8
12
|
end
|
|
9
13
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module RSpec
|
|
4
|
-
module JsonApi
|
|
5
|
-
VERSION = "1.
|
|
6
|
-
end
|
|
7
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RSpec
|
|
4
|
+
module JsonApi
|
|
5
|
+
VERSION = "1.6.0"
|
|
6
|
+
end
|
|
7
|
+
end
|
data/lib/rspec/json_api.rb
CHANGED
|
@@ -1,25 +1,23 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# Load 3rd party libraries
|
|
4
|
-
require "json"
|
|
5
|
-
require "
|
|
6
|
-
require "
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
require "rspec/json_api/
|
|
11
|
-
require "rspec/json_api/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
require "rspec/json_api/matchers"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
require "rspec/json_api/types/
|
|
24
|
-
require "rspec/json_api/types/uri"
|
|
25
|
-
require "rspec/json_api/types/uuid"
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Load 3rd party libraries
|
|
4
|
+
require "json"
|
|
5
|
+
require "uri"
|
|
6
|
+
require "diffy"
|
|
7
|
+
require "active_support/core_ext/object/blank"
|
|
8
|
+
|
|
9
|
+
# Load the json_api parts
|
|
10
|
+
require "rspec/json_api/version"
|
|
11
|
+
require "rspec/json_api/traversal"
|
|
12
|
+
require "rspec/json_api/constraints"
|
|
13
|
+
require "rspec/json_api/schema_match"
|
|
14
|
+
|
|
15
|
+
# Load matchers
|
|
16
|
+
require "rspec/json_api/matchers"
|
|
17
|
+
require "rspec/json_api/matchers/match_json_schema"
|
|
18
|
+
require "rspec/json_api/matchers/have_no_content"
|
|
19
|
+
|
|
20
|
+
# Load defined types
|
|
21
|
+
require "rspec/json_api/types/email"
|
|
22
|
+
require "rspec/json_api/types/uri"
|
|
23
|
+
require "rspec/json_api/types/uuid"
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rspec-json_api
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michal Gajowiak
|
|
8
|
-
|
|
9
|
-
bindir: exe
|
|
8
|
+
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: activesupport
|
|
@@ -39,7 +38,7 @@ dependencies:
|
|
|
39
38
|
- !ruby/object:Gem::Version
|
|
40
39
|
version: 3.4.2
|
|
41
40
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name:
|
|
41
|
+
name: railties
|
|
43
42
|
requirement: !ruby/object:Gem::Requirement
|
|
44
43
|
requirements:
|
|
45
44
|
- - ">="
|
|
@@ -66,47 +65,32 @@ dependencies:
|
|
|
66
65
|
- - ">="
|
|
67
66
|
- !ruby/object:Gem::Version
|
|
68
67
|
version: 5.0.2
|
|
69
|
-
description:
|
|
70
68
|
email:
|
|
71
69
|
- m.gajowiak@nomtek.com
|
|
72
70
|
executables: []
|
|
73
71
|
extensions: []
|
|
74
72
|
extra_rdoc_files: []
|
|
75
73
|
files:
|
|
76
|
-
- ".github/workflows/main.yml"
|
|
77
|
-
- ".gitignore"
|
|
78
|
-
- ".rspec"
|
|
79
|
-
- ".rubocop.yml"
|
|
80
|
-
- ".ruby-version"
|
|
81
74
|
- CHANGELOG.md
|
|
82
|
-
- CODE_OF_CONDUCT.md
|
|
83
|
-
- Gemfile
|
|
84
|
-
- Gemfile.lock
|
|
85
75
|
- LICENSE.txt
|
|
86
76
|
- README.md
|
|
87
|
-
- Rakefile
|
|
88
|
-
- bin/console
|
|
89
|
-
- bin/setup
|
|
90
|
-
- lib/extensions/array.rb
|
|
91
|
-
- lib/extensions/hash.rb
|
|
92
77
|
- lib/generators/rspec/json_api/install/install_generator.rb
|
|
93
78
|
- lib/generators/rspec/json_api/install/templates/rspec/json_api/interfaces/.empty_directory
|
|
94
79
|
- lib/generators/rspec/json_api/install/templates/rspec/json_api/types/.empty_directory
|
|
95
80
|
- lib/generators/rspec/json_api/interface/interface_generator.rb
|
|
96
|
-
- lib/generators/rspec/json_api/interface/templates/interface.erb
|
|
97
81
|
- lib/generators/rspec/json_api/type/type_generator.rb
|
|
98
82
|
- lib/rspec/json_api.rb
|
|
99
|
-
- lib/rspec/json_api/
|
|
100
|
-
- lib/rspec/json_api/compare_hash.rb
|
|
83
|
+
- lib/rspec/json_api/constraints.rb
|
|
101
84
|
- lib/rspec/json_api/interfaces/example_interface.rb
|
|
102
85
|
- lib/rspec/json_api/matchers.rb
|
|
103
86
|
- lib/rspec/json_api/matchers/have_no_content.rb
|
|
104
87
|
- lib/rspec/json_api/matchers/match_json_schema.rb
|
|
88
|
+
- lib/rspec/json_api/schema_match.rb
|
|
89
|
+
- lib/rspec/json_api/traversal.rb
|
|
105
90
|
- lib/rspec/json_api/types/email.rb
|
|
106
91
|
- lib/rspec/json_api/types/uri.rb
|
|
107
92
|
- lib/rspec/json_api/types/uuid.rb
|
|
108
93
|
- lib/rspec/json_api/version.rb
|
|
109
|
-
- rspec-json_api.gemspec
|
|
110
94
|
homepage: https://github.com/nomtek/rspec-json_api
|
|
111
95
|
licenses:
|
|
112
96
|
- MIT
|
|
@@ -115,7 +99,6 @@ metadata:
|
|
|
115
99
|
source_code_uri: https://github.com/nomtek/rspec-json_api
|
|
116
100
|
changelog_uri: https://github.com/nomtek/rspec-json_api/blob/master/CHANGELOG.md
|
|
117
101
|
rubygems_mfa_required: 'true'
|
|
118
|
-
post_install_message:
|
|
119
102
|
rdoc_options: []
|
|
120
103
|
require_paths:
|
|
121
104
|
- lib
|
|
@@ -130,8 +113,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
130
113
|
- !ruby/object:Gem::Version
|
|
131
114
|
version: '0'
|
|
132
115
|
requirements: []
|
|
133
|
-
rubygems_version:
|
|
134
|
-
signing_key:
|
|
116
|
+
rubygems_version: 4.0.3
|
|
135
117
|
specification_version: 4
|
|
136
118
|
summary: RSpec extension to test JSON API response.
|
|
137
119
|
test_files: []
|
data/.github/workflows/main.yml
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
name: Ruby
|
|
2
|
-
|
|
3
|
-
on: [push,pull_request]
|
|
4
|
-
|
|
5
|
-
jobs:
|
|
6
|
-
build:
|
|
7
|
-
runs-on: ubuntu-latest
|
|
8
|
-
steps:
|
|
9
|
-
- uses: actions/checkout@v4
|
|
10
|
-
- name: Set up Ruby
|
|
11
|
-
uses: ruby/setup-ruby@v1
|
|
12
|
-
with:
|
|
13
|
-
ruby-version: 3.2.2
|
|
14
|
-
bundler: 4.0.4
|
|
15
|
-
- name: Bundle gems
|
|
16
|
-
run: bundle install
|
|
17
|
-
- name: Run rspec
|
|
18
|
-
run: bundle exec rspec
|
|
19
|
-
- name: Run rubocop
|
|
20
|
-
run: bundle exec rubocop
|
data/.gitignore
DELETED
data/.rspec
DELETED
data/.rubocop.yml
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
AllCops:
|
|
2
|
-
TargetRubyVersion: 3.2
|
|
3
|
-
NewCops: enable
|
|
4
|
-
SuggestExtensions: false
|
|
5
|
-
Exclude:
|
|
6
|
-
- "README.md"
|
|
7
|
-
|
|
8
|
-
Style/StringLiterals:
|
|
9
|
-
Enabled: true
|
|
10
|
-
EnforcedStyle: double_quotes
|
|
11
|
-
|
|
12
|
-
Style/StringLiteralsInInterpolation:
|
|
13
|
-
Enabled: true
|
|
14
|
-
EnforcedStyle: double_quotes
|
|
15
|
-
|
|
16
|
-
Layout/LineLength:
|
|
17
|
-
Max: 120
|
|
18
|
-
|
|
19
|
-
Metrics/BlockLength:
|
|
20
|
-
Exclude:
|
|
21
|
-
- "spec/**/*_spec.rb"
|
|
22
|
-
|
|
23
|
-
Metrics/MethodLength:
|
|
24
|
-
Exclude:
|
|
25
|
-
- "lib/rspec/json_api/compare_hash.rb"
|
|
26
|
-
- "lib/extensions/hash.rb"
|
|
27
|
-
|
|
28
|
-
Metrics/AbcSize:
|
|
29
|
-
Exclude:
|
|
30
|
-
- "lib/rspec/json_api/compare_hash.rb"
|
|
31
|
-
- "lib/rspec/json_api/matchers/match_json_schema.rb"
|
|
32
|
-
|
|
33
|
-
Metrics/CyclomaticComplexity:
|
|
34
|
-
Exclude:
|
|
35
|
-
- "lib/rspec/json_api/compare_hash.rb"
|
|
36
|
-
|
|
37
|
-
Metrics/PerceivedComplexity:
|
|
38
|
-
Exclude:
|
|
39
|
-
- "lib/rspec/json_api/compare_hash.rb"
|
|
40
|
-
|
|
41
|
-
Style/Documentation:
|
|
42
|
-
Enabled: false
|
|
43
|
-
|
|
44
|
-
Naming/PredicatePrefix:
|
|
45
|
-
Exclude:
|
|
46
|
-
- "lib/rspec/json_api/matchers.rb"
|
|
47
|
-
|
|
48
|
-
Naming/PredicateMethod:
|
|
49
|
-
Exclude:
|
|
50
|
-
- "lib/rspec/json_api/compare_hash.rb"
|
data/.ruby-version
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
3.2.2
|