media_types 0.6.2 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/debian.yml +42 -0
  3. data/.github/workflows/ruby.yml +22 -0
  4. data/.gitignore +10 -10
  5. data/CHANGELOG.md +76 -41
  6. data/Gemfile +6 -6
  7. data/Gemfile.lock +17 -83
  8. data/LICENSE +21 -0
  9. data/README.md +364 -91
  10. data/Rakefile +12 -12
  11. data/lib/media_types.rb +58 -2
  12. data/lib/media_types/constructable.rb +36 -10
  13. data/lib/media_types/dsl.rb +110 -29
  14. data/lib/media_types/dsl/errors.rb +18 -0
  15. data/lib/media_types/errors.rb +19 -0
  16. data/lib/media_types/scheme.rb +153 -2
  17. data/lib/media_types/scheme/errors.rb +66 -0
  18. data/lib/media_types/scheme/links.rb +15 -0
  19. data/lib/media_types/scheme/missing_validation.rb +12 -4
  20. data/lib/media_types/scheme/output_empty_guard.rb +5 -4
  21. data/lib/media_types/scheme/output_iterator_with_predicate.rb +13 -2
  22. data/lib/media_types/scheme/output_type_guard.rb +1 -1
  23. data/lib/media_types/scheme/rules.rb +53 -1
  24. data/lib/media_types/scheme/rules_exhausted_guard.rb +15 -4
  25. data/lib/media_types/scheme/validation_options.rb +17 -5
  26. data/lib/media_types/testing/assertions.rb +20 -0
  27. data/lib/media_types/validations.rb +15 -5
  28. data/lib/media_types/version.rb +1 -1
  29. data/media_types.gemspec +4 -7
  30. metadata +20 -62
  31. data/.travis.yml +0 -19
  32. data/lib/media_types/defaults.rb +0 -31
  33. data/lib/media_types/integrations.rb +0 -32
  34. data/lib/media_types/integrations/actionpack.rb +0 -21
  35. data/lib/media_types/integrations/http.rb +0 -47
  36. data/lib/media_types/minitest/assert_media_type_format.rb +0 -10
  37. data/lib/media_types/minitest/assert_media_types_registered.rb +0 -166
  38. data/lib/media_types/registrar.rb +0 -148
data/Rakefile CHANGED
@@ -1,12 +1,12 @@
1
- # frozen_string_literal: true
2
-
3
- require 'bundler/gem_tasks'
4
- require 'rake/testtask'
5
-
6
- Rake::TestTask.new(:test) do |t|
7
- t.libs << 'test'
8
- t.libs << 'lib'
9
- t.test_files = FileList['test/**/*_test.rb']
10
- end
11
-
12
- task default: :test
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << 'test'
8
+ t.libs << 'lib'
9
+ t.test_files = FileList['test/**/*_test.rb']
10
+ end
11
+
12
+ task default: :test
data/lib/media_types.rb CHANGED
@@ -7,11 +7,67 @@ require 'media_types/hash'
7
7
  require 'media_types/object'
8
8
  require 'media_types/scheme'
9
9
  require 'media_types/dsl'
10
+ require 'media_types/errors'
10
11
 
11
12
  require 'media_types/views'
12
- require 'media_types/integrations'
13
13
 
14
14
  module MediaTypes
15
- end
15
+ def self.set_organisation(mod, organisation)
16
+ @organisation_prefixes ||= {}
17
+ @organisation_prefixes[mod.name] = organisation
18
+ end
19
+
20
+ def self.expect_string_keys(mod)
21
+ set_key_expectation(mod, false)
22
+ end
23
+
24
+ def self.expect_symbol_keys(mod)
25
+ set_key_expectation(mod, true)
26
+ end
27
+
28
+ # Keep track of modules setting their key expectations
29
+ def self.set_key_expectation(mod, expect_symbol_keys)
30
+ @key_expectations ||= {}
31
+ @key_expectations_used ||= {}
32
+
33
+ raise KeyExpectationSetError.new(mod: mod) unless @key_expectations[mod.name].nil?
34
+ raise KeyExpectationUsedError.new(mod: mod) if @key_expectations_used[mod.name]
35
+
36
+ @key_expectations[mod.name] = expect_symbol_keys
37
+ end
38
+
39
+ SYMBOL_KEYS_DEFAULT = true
40
+
41
+ def self.get_key_expectation(mod)
42
+ @key_expectations ||= {}
43
+ @key_expectations_used ||= {}
16
44
 
45
+ expect_symbol = find_key_expectation(mod)
17
46
 
47
+ expect_symbol.nil? ? SYMBOL_KEYS_DEFAULT : expect_symbol
48
+ end
49
+
50
+ def self.find_key_expectation(mod)
51
+ modules = mod.name.split('::')
52
+ expect_symbol = nil
53
+
54
+ while modules.any? && expect_symbol.nil?
55
+ current_module = modules.join('::')
56
+ expect_symbol = @key_expectations[current_module]
57
+ @key_expectations_used[current_module] = true
58
+ modules.pop
59
+ end
60
+
61
+ expect_symbol
62
+ end
63
+
64
+ def self.get_organisation(mod)
65
+ name = mod.name
66
+ prefixes = @organisation_prefixes.keys.select { |p| name.start_with? p }
67
+ return nil unless prefixes.any?
68
+
69
+ best = prefixes.max_by { |p| p.length }
70
+
71
+ @organisation_prefixes[best]
72
+ end
73
+ end
@@ -28,11 +28,6 @@ module MediaTypes
28
28
  with(view: view)
29
29
  end
30
30
 
31
- def suffix(suffix = NO_ARG)
32
- return opts[:suffix] if suffix == NO_ARG
33
- with(suffix: suffix)
34
- end
35
-
36
31
  def collection
37
32
  view(COLLECTION_VIEW)
38
33
  end
@@ -73,20 +68,46 @@ module MediaTypes
73
68
  to_str.split(pattern, *limit)
74
69
  end
75
70
 
71
+ def as_key
72
+ [type, view&.to_s, version]
73
+ end
74
+
76
75
  def hash
77
- to_str.hash
76
+ as_key.hash
77
+ end
78
+
79
+ def override_suffix(suffix)
80
+ with(suffix: suffix)
81
+ end
82
+
83
+ def suffix
84
+ return opts[:suffix] if opts.key?(:suffix)
85
+
86
+ schema = schema_for(self)
87
+ schema.type_attributes.fetch(:suffix, 'json')
78
88
  end
79
89
 
80
90
  def to_str(qualifier = nil)
81
- # TODO: remove warning by slicing out these arguments if they don't appear in the format
82
91
  qualified(
83
92
  qualifier,
84
- Formatter.call(opts)
93
+ __getobj__.media_type_name_for.call(
94
+ type: opts[:type],
95
+ view: opts[:view],
96
+ version: opts[:version],
97
+ suffix: suffix
98
+ )
85
99
  )
86
100
  end
87
101
 
102
+ def available_validations
103
+ return [] if !validatable?
104
+ [self]
105
+ end
106
+
88
107
  def valid?(output, **validation_opts)
89
- __getobj__.valid?(
108
+ raise ArgumentError, "Unable to validate #{to_s} type without a corresponding validation. Please mark objects that should be empty with 'empty'." unless validatable?
109
+
110
+ __getobj__.valid_unsafe?(
90
111
  output,
91
112
  self,
92
113
  **validation_opts
@@ -94,7 +115,9 @@ module MediaTypes
94
115
  end
95
116
 
96
117
  def validate!(output, **validation_opts)
97
- __getobj__.validate!(
118
+ raise ArgumentError, "Unable to validate #{to_s} type without a corresponding validation. Please mark objects that should be empty with 'empty'." unless validatable?
119
+
120
+ __getobj__.validate_unsafe!(
98
121
  output,
99
122
  self,
100
123
  **validation_opts
@@ -102,11 +125,14 @@ module MediaTypes
102
125
  end
103
126
 
104
127
  def validatable?
128
+ return false unless media_type_combinations.include? as_key
129
+
105
130
  __getobj__.validatable?(self)
106
131
  end
107
132
 
108
133
  alias inspect to_str
109
134
  alias to_s to_str
135
+ alias identifier to_str
110
136
 
111
137
  private
112
138
 
@@ -1,43 +1,72 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'media_types/constructable'
4
- require 'media_types/defaults'
5
- require 'media_types/registrar'
6
4
  require 'media_types/validations'
7
5
 
6
+ require 'media_types/dsl/errors'
7
+
8
8
  module MediaTypes
9
9
  module Dsl
10
10
  def self.included(base)
11
11
  base.extend ClassMethods
12
12
  base.class_eval do
13
13
  class << self
14
+ attr_accessor :media_type_name_for, :media_type_combinations, :media_type_validations, :symbol_keys
15
+
14
16
  private
15
17
 
16
- attr_accessor :media_type_constructable, :symbol_base, :media_type_registrar, :media_type_validations
18
+ attr_accessor :media_type_constructable, :symbol_base, :media_type_registrar
17
19
  end
20
+ base.media_type_combinations = Set.new
18
21
  end
19
22
  end
20
23
 
21
24
  module ClassMethods
22
-
23
25
  def to_constructable
26
+ raise UninitializedConstructable if media_type_constructable.nil?
27
+
24
28
  media_type_constructable.dup.tap do |constructable|
25
29
  constructable.__setobj__(self)
26
30
  end
27
31
  end
28
32
 
29
- def valid?(output, media_type = to_constructable, **opts)
30
- validations.find(String(media_type)).valid?(output, backtrace: ['.'], **opts)
33
+ def symbol_keys?
34
+ if symbol_keys.nil?
35
+ MediaTypes.get_key_expectation(self)
36
+ else
37
+ symbol_keys
38
+ end
39
+ end
40
+
41
+ def string_keys?
42
+ !symbol_keys?
43
+ end
44
+
45
+ def valid?(output, **opts)
46
+ to_constructable.valid?(output, **opts)
47
+ end
48
+
49
+ def valid_unsafe?(output, media_type = to_constructable, **opts)
50
+ opts[:expected_key_type] = string_keys? ? String : Symbol
51
+ validations.find(media_type).valid?(output, backtrace: ['.'], **opts)
52
+ end
53
+
54
+ def validate!(output, **opts)
55
+ assert_sane!
56
+ to_constructable.validate!(output, **opts)
31
57
  end
32
58
 
33
- def validate!(output, media_type = to_constructable, **opts)
34
- validations.find(String(media_type)).validate(output, backtrace: ['.'], **opts)
59
+ def validate_unsafe!(output, media_type = to_constructable, **opts)
60
+ opts[:expected_key_type] = string_keys? ? String : Symbol
61
+ validations.find(media_type).validate(output, backtrace: ['.'], **opts)
35
62
  end
36
63
 
37
64
  def validatable?(media_type = to_constructable)
38
65
  return false unless validations
39
66
 
40
- validations.find(String(media_type), -> { nil })
67
+ resolved = validations.find(media_type, -> { nil })
68
+
69
+ !resolved.nil?
41
70
  end
42
71
 
43
72
  def register
@@ -47,43 +76,95 @@ module MediaTypes
47
76
  end
48
77
  end
49
78
 
50
- private
79
+ def view(v)
80
+ to_constructable.view(v)
81
+ end
51
82
 
52
- def media_type(name, defaults: {})
83
+ def version(v)
84
+ to_constructable.version(v)
85
+ end
53
86
 
54
- unless defined?(:base_format)
55
- define_method(:base_format) do
56
- raise format('Implement the class method "base_format" in %<klass>s', klass: self)
57
- end
87
+ def identifier_format
88
+ self.media_type_name_for = proc do |type:, view:, version:, suffix:|
89
+ yield(type: type, view: view, version: version, suffix: suffix)
58
90
  end
91
+ end
59
92
 
60
- self.media_type_constructable = Constructable.new(self, format: base_format, type: name)
61
- .version(defaults.fetch(:version) { nil })
62
- .suffix(defaults.fetch(:suffix) { nil })
63
- .view(defaults.fetch(:view) { nil })
64
- self
93
+ def identifier
94
+ to_constructable.to_s
65
95
  end
66
96
 
67
- def defaults(&block)
68
- return media_type_constructable unless block_given?
69
- self.media_type_constructable = Defaults.new(to_constructable, &block).to_constructable
97
+ def available_validations
98
+ media_type_combinations.map do |a|
99
+ _, view, version = a
100
+ view(view).version(version)
101
+ end
102
+ end
70
103
 
71
- self
104
+ def schema_for(constructable)
105
+ validations.find(constructable)
72
106
  end
73
107
 
74
- def registrations(symbol = nil, &block)
75
- return media_type_registrar unless block_given?
76
- self.media_type_registrar = Registrar.new(self, symbol: symbol, &block)
108
+ def assert_sane!
109
+ return if media_type_validations.scheme.asserted_sane?
77
110
 
78
- self
111
+ media_type_validations.run_fixture_validations(symbol_keys?)
112
+ end
113
+
114
+ private
115
+
116
+ def use_name(name)
117
+ if media_type_name_for.nil?
118
+ self.media_type_name_for = proc do |type:, view:, version:, suffix:|
119
+ resolved_org = nil
120
+ if defined?(organisation)
121
+ resolved_org = organisation
122
+ else
123
+ resolved_org = MediaTypes.get_organisation(self)
124
+
125
+ if resolved_org.nil?
126
+ raise OrganisationNotSetError,
127
+ format('Implement the class method "organisation" in %<klass>s or specify a global organisation using MediaTypes::set_organisation', klass: self)
128
+ end
129
+ end
130
+ raise ArgumentError, 'Unable to create a name for a schema with a nil name.' if type.nil?
131
+ raise ArgumentError, 'Unable to create a name for a schema with a nil organisation.' if resolved_org.nil?
132
+
133
+ result = "application/vnd.#{resolved_org}.#{type}"
134
+ result += ".v#{version}" unless version.nil?
135
+ result += ".#{view}" unless view.nil?
136
+ result += "+#{suffix}" unless suffix.nil?
137
+ result
138
+ end
139
+ end
140
+ self.media_type_constructable = Constructable.new(self, type: name)
141
+ end
142
+
143
+ def expect_string_keys
144
+ raise KeyTypeExpectationError, 'Key expectation already set' unless symbol_keys.nil?
145
+
146
+ self.symbol_keys = false
147
+ end
148
+
149
+ def expect_symbol_keys
150
+ raise KeyTypeExpectationError, 'Key expectation already set' unless symbol_keys.nil?
151
+
152
+ self.symbol_keys = true
79
153
  end
80
154
 
81
155
  def validations(&block)
82
- return media_type_validations unless block_given?
156
+ return lookup_validations unless block_given?
157
+
83
158
  self.media_type_validations = Validations.new(to_constructable, &block)
84
159
 
85
160
  self
86
161
  end
162
+
163
+ def lookup_validations
164
+ raise MissingValidationError, "No validations defined for #{name}" if media_type_validations.nil?
165
+
166
+ media_type_validations
167
+ end
87
168
  end
88
169
  end
89
170
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MediaTypes
4
+ module Dsl
5
+ class UninitializedConstructable < RuntimeError
6
+ def message
7
+ 'Unable to generate constructable without a name, make sure to have called `use_name(name)` before.'
8
+ end
9
+ end
10
+
11
+ # Raised when an error occurs during setting expected key type
12
+ class KeyTypeExpectationError < StandardError; end
13
+
14
+ class MissingValidationError < StandardError; end
15
+
16
+ class OrganisationNotSetError < StandardError; end
17
+ end
18
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MediaTypes
4
+ module Errors
5
+ # Raised when trying to set a module key expectation twice
6
+ class KeyExpectationSetError < StandardError
7
+ def initialize(mod:)
8
+ super(format('%<mod>s already has a key expectation set', mod: mod.name))
9
+ end
10
+ end
11
+
12
+ # Raised when trying to set a module key expectation while default expectation already used
13
+ class KeyExpectationUsedError < StandardError
14
+ def initialize(mod:)
15
+ super(format('Unable to change key type expectation for %<mod>s since its current expectation is already used', mod: mod.name))
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'json'
4
+
3
5
  require 'media_types/scheme/validation_options'
4
6
  require 'media_types/scheme/enumeration_context'
5
7
  require 'media_types/scheme/errors'
@@ -18,6 +20,48 @@ require 'media_types/scheme/output_type_guard'
18
20
  require 'media_types/scheme/rules_exhausted_guard'
19
21
 
20
22
  module MediaTypes
23
+ class AssertionError < StandardError
24
+ def initialize(errors)
25
+ @fixture_errors = errors
26
+ end
27
+
28
+ def message
29
+ fixture_errors.map(&:message).join(', ')
30
+ end
31
+
32
+ attr_reader :fixture_errors
33
+ end
34
+
35
+ class UnexpectedValidationResultError < StandardError
36
+ def initialize(fixture_caller, error)
37
+ self.fixture_caller = fixture_caller
38
+ self.error = error
39
+ end
40
+
41
+ def message
42
+ format(
43
+ '%<caller_path>s:%<caller_line>s -> %<error>s',
44
+ caller_path: fixture_caller.path,
45
+ caller_line: fixture_caller.lineno,
46
+ error: error.is_a?(MediaTypes::Scheme::ValidationError) ? "#{error.class}:#{error.message}" : error
47
+ )
48
+ end
49
+
50
+ attr_accessor :fixture_caller, :error
51
+ end
52
+
53
+ class FixtureData
54
+ def initialize(caller:, fixture:, expect_to_pass:)
55
+ self.caller = caller
56
+ self.fixture = fixture
57
+ self.expect_to_pass = expect_to_pass
58
+ end
59
+
60
+ attr_accessor :caller, :fixture, :expect_to_pass
61
+
62
+ alias expect_to_pass? expect_to_pass
63
+ end
64
+
21
65
  ##
22
66
  # Media Type Schemes can validate content to a media type, by itself. Used by the `validations` dsl.
23
67
  #
@@ -51,10 +95,18 @@ module MediaTypes
51
95
  #
52
96
  def initialize(allow_empty: false, expected_type: ::Object, &block)
53
97
  self.rules = Rules.new(allow_empty: allow_empty, expected_type: expected_type)
98
+ self.type_attributes = {}
99
+ self.fixtures = []
100
+ self.asserted_sane = false
54
101
 
55
102
  instance_exec(&block) if block_given?
56
103
  end
57
104
 
105
+ attr_accessor :type_attributes, :fixtures
106
+ attr_reader :rules, :asserted_sane
107
+
108
+ alias asserted_sane? asserted_sane
109
+
58
110
  ##
59
111
  # Checks if the +output+ is valid
60
112
  #
@@ -93,6 +145,7 @@ module MediaTypes
93
145
  #
94
146
  def validate(output, options = nil, **opts)
95
147
  options ||= ValidationOptions.new(**opts)
148
+ options.context = output
96
149
 
97
150
  catch(:end) do
98
151
  validate!(output, options, context: nil)
@@ -149,7 +202,11 @@ module MediaTypes
149
202
  # MyMedia.valid?({ foo: { bar: 'my-string' }})
150
203
  # # => true
151
204
  #
152
- def attribute(key, type = ::Object, optional: false, **opts, &block)
205
+ def attribute(key, type = nil, optional: false, **opts, &block)
206
+ raise ConflictingTypeDefinitionError, 'You cannot apply a block to a non-hash typed attribute, either remove the type or the block' if type != ::Hash && block_given? && !type.nil?
207
+
208
+ type ||= ::Object
209
+
153
210
  if block_given?
154
211
  return collection(key, expected_type: ::Hash, optional: optional, **opts, &block)
155
212
  end
@@ -202,6 +259,8 @@ module MediaTypes
202
259
  # # => true
203
260
  #
204
261
  def any(scheme = nil, expected_type: ::Hash, allow_empty: false, &block)
262
+ raise ConflictingTypeDefinitionError, 'You cannot apply a block to a non-hash typed property, either remove the type or the block' if scheme != ::Hash && block_given? && !scheme.nil?
263
+
205
264
  unless block_given?
206
265
  if scheme.is_a?(Scheme)
207
266
  return rules.default = scheme
@@ -289,6 +348,8 @@ module MediaTypes
289
348
  # # => true
290
349
  #
291
350
  def collection(key, scheme = nil, allow_empty: false, expected_type: ::Array, optional: false, &block)
351
+ raise ConflictingTypeDefinitionError, 'You cannot apply a block to a non-hash typed collection, either remove the type or the block' if scheme != ::Hash && block_given? && !scheme.nil?
352
+
292
353
  unless block_given?
293
354
  return rules.add(
294
355
  key,
@@ -346,6 +407,21 @@ module MediaTypes
346
407
  end.link(*args, **opts, &block)
347
408
  end
348
409
 
410
+ ##
411
+ # Mark object as a valid empty object
412
+ #
413
+ # @example Empty object
414
+ #
415
+ # class MyMedia
416
+ # include MediaTypes::Dsl
417
+ #
418
+ # validations do
419
+ # empty
420
+ # end
421
+ # end
422
+ def empty
423
+ end
424
+
349
425
  def inspect(indentation = 0)
350
426
  tabs = ' ' * indentation
351
427
  [
@@ -355,8 +431,83 @@ module MediaTypes
355
431
  ].join("\n")
356
432
  end
357
433
 
434
+ def assert_pass(fixture)
435
+ reduced_stack = remove_current_dir_from_stack(caller_locations)
436
+ @fixtures << FixtureData.new(caller: reduced_stack.first, fixture: fixture, expect_to_pass: true)
437
+ end
438
+
439
+ def assert_fail(fixture)
440
+ reduced_stack = remove_current_dir_from_stack(caller_locations)
441
+ @fixtures << FixtureData.new(caller: reduced_stack.first, fixture: fixture, expect_to_pass: false)
442
+ end
443
+
444
+ # Removes all calls originating in current dir from given stack
445
+ # We need this so that we find out the caller of an assert_pass/fail in the caller_locations
446
+ # Which gets polluted by Scheme consecutively executing blocks within the validation blocks
447
+ def remove_current_dir_from_stack(stack)
448
+ stack.reject { |location| location.path.include?(__dir__) }
449
+ end
450
+
451
+ def validate_scheme_fixtures(expect_symbol_keys, backtrace)
452
+ @fixtures.map do |fixture_data|
453
+ begin
454
+ validate_fixture(fixture_data, expect_symbol_keys, backtrace)
455
+ nil
456
+ rescue UnexpectedValidationResultError => e
457
+ e
458
+ end
459
+ end.compact
460
+ end
461
+
462
+ def validate_nested_scheme_fixtures(expect_symbol_keys, backtrace)
463
+ @rules.flat_map do |key, rule|
464
+ next unless rule.is_a?(Scheme) || rule.is_a?(Links)
465
+
466
+ begin
467
+ rule.run_fixture_validations(expect_symbol_keys, backtrace.dup.append(key))
468
+ nil
469
+ rescue AssertionError => e
470
+ e.fixture_errors
471
+ end
472
+ end.compact
473
+ end
474
+
475
+ def validate_default_scheme_fixtures(expect_symbol_keys, backtrace)
476
+ return [] unless @rules.default.is_a?(Scheme)
477
+
478
+ @rules.default.run_fixture_validations(expect_symbol_keys, backtrace.dup.append('*'))
479
+ []
480
+ rescue AssertionError => e
481
+ e.fixture_errors
482
+ end
483
+
484
+ def run_fixture_validations(expect_symbol_keys, backtrace = [])
485
+ fixture_errors = validate_scheme_fixtures(expect_symbol_keys, backtrace)
486
+ fixture_errors += validate_nested_scheme_fixtures(expect_symbol_keys, backtrace)
487
+ fixture_errors += validate_default_scheme_fixtures(expect_symbol_keys, backtrace)
488
+
489
+ raise AssertionError, fixture_errors unless fixture_errors.empty?
490
+
491
+ self.asserted_sane = true
492
+ end
493
+
494
+ def validate_fixture(fixture_data, expect_symbol_keys, backtrace = [])
495
+ json = JSON.parse(fixture_data.fixture, { symbolize_names: expect_symbol_keys })
496
+ expected_key_type = expect_symbol_keys ? Symbol : String
497
+
498
+ begin
499
+ validate(json, expected_key_type: expected_key_type, backtrace: backtrace)
500
+ unless fixture_data.expect_to_pass?
501
+ raise UnexpectedValidationResultError.new(fixture_data.caller, 'No error encounterd whilst expecting to')
502
+ end
503
+ rescue MediaTypes::Scheme::ValidationError => e
504
+ raise UnexpectedValidationResultError.new(fixture_data.caller, e) if fixture_data.expect_to_pass?
505
+ end
506
+ end
507
+
358
508
  private
359
509
 
360
- attr_accessor :rules
510
+ attr_writer :rules, :asserted_sane
511
+
361
512
  end
362
513
  end