rspec_model_validations 1.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6c7eddb001578c400fb07e353dc90519a5a9003e62856cadb4de221060ba97bf
4
+ data.tar.gz: 0f7cdb19b649ea52717542a66614bff5a62f592000d7750df6c9103dfb611982
5
+ SHA512:
6
+ metadata.gz: 3325f11863d332b16dde60c6092dbeb19ca18b4ae7cfefbaf1b9fc6868816941c3310d8a0a2970a14680962454144207c05007d7521d558dd96228276a1e781e
7
+ data.tar.gz: ebe6d58e97a337e6c2dd4436073312251b94b66307fd7d3ee5acb2576a8b7515d77b50fdf1bc7971799d068227013d43dbe4967d5fe7fe90db3f64b258e67484
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /.local
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /.cache/
11
+ .irb_history
12
+ .bash_history
13
+ .byebug_history
14
+
15
+ # rspec failure tracking
16
+ .rspec_status
17
+
18
+ # Editor file
19
+ *.swp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,29 @@
1
+ AllCops:
2
+ NewCops: enable
3
+ Exclude:
4
+ - /bin/**
5
+
6
+ Style/SingleLineMethods:
7
+ Enabled: false
8
+
9
+ Style/MethodDefParentheses:
10
+ Enabled: false
11
+
12
+ Style/NestedParenthesizedCalls:
13
+ Enabled: false
14
+
15
+ Lint/AmbiguousRegexpLiteral:
16
+ Enabled: false
17
+
18
+ Lint/AmbiguousBlockAssociation:
19
+ Enabled: false
20
+
21
+ Metrics/BlockLength:
22
+ Exclude:
23
+ - /app/spec/**/**/**/**/**/**/*.rb
24
+
25
+ Style/ClassAndModuleChildren:
26
+ Enabled: false
27
+
28
+ Gemspec/RequiredRubyVersion:
29
+ Enabled: false
data/Dockerfile ADDED
@@ -0,0 +1,9 @@
1
+ ##
2
+ # Base - basic image use to run dev tools
3
+ #
4
+ FROM ruby:3.0.2
5
+
6
+ WORKDIR /app
7
+
8
+ ADD . .
9
+ RUN bundle install
data/Gemfile ADDED
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ ## CORE
6
+ # Include dependencies
7
+ gemspec
8
+
9
+ ## TEST
10
+ # Model framework in order to run validation
11
+ gem 'activemodel', '~> 7.0.0'
12
+ # Framework
13
+ gem 'rspec', '~> 3.10.0'
14
+ # Coverage
15
+ gem 'simplecov', '~> 0.19.1'
16
+
17
+ ## DEV TOOLS
18
+ # Breakpoint
19
+ gem 'byebug', '~> 11.1.3'
20
+ # Linter
21
+ gem 'rubocop', '~> 1.21.0'
22
+ # Documentation
23
+ gem 'yard', '~> 0.9.26'
data/Gemfile.lock ADDED
@@ -0,0 +1,79 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ rspec_model_validations (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ activemodel (7.0.4)
10
+ activesupport (= 7.0.4)
11
+ activesupport (7.0.4)
12
+ concurrent-ruby (~> 1.0, >= 1.0.2)
13
+ i18n (>= 1.6, < 2)
14
+ minitest (>= 5.1)
15
+ tzinfo (~> 2.0)
16
+ ast (2.4.2)
17
+ byebug (11.1.3)
18
+ concurrent-ruby (1.1.10)
19
+ diff-lcs (1.5.0)
20
+ docile (1.4.0)
21
+ i18n (1.12.0)
22
+ concurrent-ruby (~> 1.0)
23
+ minitest (5.16.3)
24
+ parallel (1.22.1)
25
+ parser (3.1.2.1)
26
+ ast (~> 2.4.1)
27
+ rainbow (3.1.1)
28
+ regexp_parser (2.6.0)
29
+ rexml (3.2.5)
30
+ rspec (3.10.0)
31
+ rspec-core (~> 3.10.0)
32
+ rspec-expectations (~> 3.10.0)
33
+ rspec-mocks (~> 3.10.0)
34
+ rspec-core (3.10.2)
35
+ rspec-support (~> 3.10.0)
36
+ rspec-expectations (3.10.2)
37
+ diff-lcs (>= 1.2.0, < 2.0)
38
+ rspec-support (~> 3.10.0)
39
+ rspec-mocks (3.10.3)
40
+ diff-lcs (>= 1.2.0, < 2.0)
41
+ rspec-support (~> 3.10.0)
42
+ rspec-support (3.10.3)
43
+ rubocop (1.21.0)
44
+ parallel (~> 1.10)
45
+ parser (>= 3.0.0.0)
46
+ rainbow (>= 2.2.2, < 4.0)
47
+ regexp_parser (>= 1.8, < 3.0)
48
+ rexml
49
+ rubocop-ast (>= 1.9.1, < 2.0)
50
+ ruby-progressbar (~> 1.7)
51
+ unicode-display_width (>= 1.4.0, < 3.0)
52
+ rubocop-ast (1.23.0)
53
+ parser (>= 3.1.1.0)
54
+ ruby-progressbar (1.11.0)
55
+ simplecov (0.19.1)
56
+ docile (~> 1.1)
57
+ simplecov-html (~> 0.11)
58
+ simplecov-html (0.12.3)
59
+ tzinfo (2.0.5)
60
+ concurrent-ruby (~> 1.0)
61
+ unicode-display_width (2.3.0)
62
+ webrick (1.7.0)
63
+ yard (0.9.28)
64
+ webrick (~> 1.7.0)
65
+
66
+ PLATFORMS
67
+ aarch64-linux
68
+
69
+ DEPENDENCIES
70
+ activemodel (~> 7.0.0)
71
+ byebug (~> 11.1.3)
72
+ rspec (~> 3.10.0)
73
+ rspec_model_validations!
74
+ rubocop (~> 1.21.0)
75
+ simplecov (~> 0.19.1)
76
+ yard (~> 0.9.26)
77
+
78
+ BUNDLED WITH
79
+ 2.2.22
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Pierre Guego
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/Makefile ADDED
@@ -0,0 +1,49 @@
1
+ ##
2
+ # Simplify docker usage
3
+ #
4
+ container = gem_rspec_model_validations
5
+ option = -ti --rm --user $(shell id -u):$(shell id -g) -v $(shell pwd):/app -e HOME=/app
6
+
7
+ .PHONY: doc
8
+ args = $(filter-out $@,$(MAKECMDGOALS))
9
+ %:
10
+ @:
11
+
12
+ # build the docker image
13
+ install:
14
+ @ docker build -t $(container) .
15
+
16
+ # run the test inside container
17
+ test:
18
+ @ docker run ${option} ${container} rspec $(args)
19
+
20
+ # display linter error
21
+ lint:
22
+ @ docker run $(option) ${container} rubocop ${args}
23
+
24
+ # display linter error
25
+ lintf:
26
+ @ docker run $(option) ${container} rubocop -A ${args}
27
+
28
+ # documentation compilation
29
+ doc:
30
+ @ docker run $(option) $(container) yardoc --list-undoc $(args)
31
+
32
+ # exec the commande in the container: make exec bash
33
+ exec:
34
+ @ docker run $(option) $(container) $(args)
35
+
36
+ # remove everything created by makefile command
37
+ clean:
38
+ - rm -rf doc
39
+ - rm -rf coverage
40
+ - rm -rf .bundle
41
+ - rm -rf .yardoc
42
+ - rm -rf .cache
43
+ - rm -rf .local
44
+ - rm .rspec_status
45
+ - rm .byebug_history
46
+ - rm .irb_history
47
+ - rm .bash_history
48
+ - docker image rm ruby:3.0.2
49
+ - docker image rm $(container)
data/README.md ADDED
@@ -0,0 +1,112 @@
1
+ # RspecModelValidations
2
+
3
+ *Extra matchers to improve testing of model validation*
4
+
5
+ Testing model validation can be a bit clunky:
6
+ * `model.valid?` test the entire model so it can lead to errors
7
+ * specific error on attribute can be test with `model.added?` or `errors[:attribute]` but options or message must be provided
8
+ * attribute setting and validation trigger must be call
9
+ * as validation are test through "raw code" failure message can be hard to understand
10
+
11
+ `rspec_model_validations` make testing smoother by adding matchers to focus test on specific attribute / validation.
12
+
13
+ ```ruby
14
+ # model
15
+ validates :attribute, numericality: true
16
+
17
+ # spec
18
+ expect(model).to invalidate(:attribute).with(:blank, :not_a_number).on nil
19
+
20
+ # equivalent to
21
+ model.attribute = nil
22
+ model.validate
23
+ expect(model.errors).to be_added :attribute, :blank
24
+ expect(model.errors).to be_added :attribute, :not_a_number, value: nil
25
+ ```
26
+
27
+ ## Requirements
28
+
29
+ * ~> 1.0: rails ~> 7.0
30
+
31
+ *Note: it should be able to run with older version of rails but behaviour is not garanted.*
32
+
33
+ ## Installation
34
+
35
+ 1. Add this gem to your application in :test env
36
+
37
+ ```ruby
38
+ gem 'rspec_model_validations', '~> 1.0', require: false, group: :test
39
+ ```
40
+
41
+ 2. Setup spec/rails_helper.rb file to access matchers
42
+
43
+ ```ruby
44
+ # Add additional requires below this line. Rails is not loaded until this point!
45
+ require 'rspec_model_validations'
46
+
47
+ # ...
48
+
49
+ RSpec.configure do |config|
50
+ config.include RspecModelValidations::Matchers
51
+ end
52
+ ```
53
+
54
+ ## Usage
55
+
56
+ ### Test validation errors
57
+
58
+ `invalidate :attribute` test errors on a specific attribute.
59
+ It run validation and test that the targeted attribute have at least one error.
60
+
61
+ ```ruby
62
+ model.attribute = nil
63
+ expect(model).to invalidate :attribute
64
+
65
+ # equivalent to
66
+ model.attribute = nil
67
+ model.validate
68
+ expect(model.errors[:attribute]).to be_present
69
+ ```
70
+
71
+ Options:
72
+
73
+ * `with` specify which errors type must be present. It accept single or multiple symbols.
74
+
75
+ ```ruby
76
+ model.attribute = nil
77
+ expect(model).to invalidate(:attribute).with :blank, :not_a_number
78
+
79
+ # equivalent to
80
+ model.attribute = nil
81
+ model.validate
82
+ expect(model.errors.group_by_attribute(:attribute).map(&:type)).to include(:blank, :not_a_number)
83
+ ```
84
+
85
+ * `on` set the attribute value
86
+
87
+ ```ruby
88
+ expect(model).to invalidate(:attribute).on nil
89
+
90
+ # equivalent to
91
+ model.attribute = nil
92
+ model.validate
93
+ expect(model.errors[:attribute]).to be_present
94
+ ```
95
+
96
+ ### Test successfull validation
97
+
98
+ `validate :attribute` test a specific attribute validity.
99
+ It run validation and then test that none errors are related to the given attribute.
100
+
101
+ ```ruby
102
+ model.attribute = 9
103
+ expect(model).to validate :attribute
104
+
105
+ # equivalent to
106
+ model.attribute = 9
107
+ model.validate
108
+ expect(model.errors[:attribute]).to be_empty
109
+ ```
110
+
111
+ Options:
112
+ * `on` see invalidate on option
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'rspec_model_validations'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Dry matcher code
4
+ module RspecModelValidations::Matchers::Base
5
+ # @param attribute [Symbol, String]
6
+ def initialize attribute
7
+ @attribute = attribute.to_s.to_sym
8
+ @model = nil
9
+ @errors = nil
10
+ end
11
+
12
+ # Store given value
13
+ # @param value [Object]
14
+ # @return [self]
15
+ def on value
16
+ @on = value
17
+
18
+ self
19
+ end
20
+
21
+ private
22
+
23
+ # Raise an error if model does not posses @attribute
24
+ # @param model [ActiveModel::Model]
25
+ def attribute_belongs_to! model
26
+ return if model.respond_to? @attribute
27
+
28
+ message = "#{@attribute.inspect} is not a #{model.class} attribute !"
29
+ raise RspecModelValidations::Error, message
30
+ end
31
+
32
+ # Run model validations and return attribute errors type
33
+ # Set model attribute with on value when on is set.
34
+ # @param model [ActiveModel::Model]
35
+ # @return [Array]
36
+ def attribute_errors model
37
+ model.instance_variable_set "@#{@attribute}", @on if defined? @on
38
+ model.validate
39
+ model.errors.group_by_attribute[@attribute]&.map(&:type) || []
40
+ end
41
+
42
+ # Return the model attribute value.
43
+ # Attribute must exist
44
+ # @param model [ActiveModel::Model]
45
+ # @return [Object]
46
+ def attribute_value model; model.instance_variable_get "@#{@attribute}" end
47
+
48
+ # Format a matcher expected / got faillure message
49
+ # @param expected [String] expected part of the message
50
+ # @param got [String] got part of the message
51
+ # @return [String]
52
+ def message expected, got; "\nexpected: #{expected}\n got: #{got}" end
53
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Test if model validation lead to errors on the given attribute.
4
+ #
5
+ # Option:
6
+ # * `with` test that the attribute have specific error rather than any
7
+ class RspecModelValidations::Matchers::Invalidate
8
+ include RspecModelValidations::Matchers::Base
9
+
10
+ def initialize attribute
11
+ super
12
+
13
+ @with = nil
14
+ end
15
+
16
+ # Set the with option
17
+ # @param errors [*Symbol] One or more error which should be in attribute errors
18
+ # @return [self]
19
+ def with *errors
20
+ @with = errors
21
+
22
+ self
23
+ end
24
+
25
+ # Run the test
26
+ # @param model[ActiveModel::Model]
27
+ # @return [Boolean] Test result
28
+ # @raise [RspecModelValidations::Error] When model does not posses the given attribute
29
+ def matches? model
30
+ attribute_belongs_to! model
31
+
32
+ @model = model
33
+ @errors = attribute_errors model
34
+
35
+ @errors.count != 0 && (@with.nil? || (@with & @errors) == @with)
36
+ end
37
+
38
+ # Explain why matches? fail
39
+ # @return [String]
40
+ def failure_message
41
+ attribute = "#{@model.class}##{@attribute}"
42
+ value = attribute_value(@model).inspect
43
+
44
+ expected = "#{value} on #{attribute} to be invalidated"
45
+ expected = "#{expected} with #{@with.map(&:inspect).join ', '}" unless @with.nil?
46
+
47
+ message expected, @errors
48
+ end
49
+
50
+ # Explain why matches? fail when negated
51
+ # @return [String]
52
+ def failure_message_when_negated
53
+ attribute = "#{@model.class}##{@attribute}"
54
+ value = attribute_value(@model).inspect
55
+
56
+ expected = "#{value} on #{attribute} to be validated"
57
+ expected = "#{value} on #{attribute} not to be invalidated with #{@with.map(&:inspect).join ', '}" unless @with.nil?
58
+
59
+ message expected, @errors
60
+ end
61
+
62
+ # One line syntax description
63
+ # @return [String]
64
+ def description
65
+ result = "invalidate #{@attribute.inspect} attribute"
66
+ result = "#{result} with #{@with.map(&:inspect).join ', '}" unless @with.nil?
67
+
68
+ result
69
+ end
70
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Test if model validation does not lead to errors on the given attribute.
4
+ class RspecModelValidations::Matchers::Validate
5
+ include RspecModelValidations::Matchers::Base
6
+
7
+ # Run the test
8
+ # @param model[ActiveModel::Model]
9
+ # @return [Boolean] Test result
10
+ # @raise [RspecModelValidations::Error] When model does not posses the given attribute
11
+ def matches? model
12
+ attribute_belongs_to! model
13
+
14
+ @model = model
15
+ @errors = attribute_errors model
16
+
17
+ @errors.empty?
18
+ end
19
+
20
+ # Explain why matches? fail and show errors
21
+ # @return [String]
22
+ def failure_message
23
+ message "#{attribute_value(@model).inspect} to be a valid value for #{@model.class}##{@attribute}", @errors
24
+ end
25
+
26
+ # Explain why matches? fail when negated
27
+ # @return [String]
28
+ def failure_message_when_negated
29
+ message "#{attribute_value(@model).inspect} to be an invalid value for #{@model.class}##{@attribute}", @errors
30
+ end
31
+
32
+ # One line syntax description
33
+ # @return [String]
34
+ def description; "validate #{@attribute.inspect} attribute" end
35
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Rspec 'alias' to run matchers.
4
+ # Include with rspec configuration method `include`
5
+ module RspecModelValidations::Matchers
6
+ # `validate` alias
7
+ # @return [Validate]
8
+ def validate attribute; Validate.new attribute end
9
+
10
+ # `invalidate` alias
11
+ # @return [Validate]
12
+ def invalidate attribute; Invalidate.new attribute end
13
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Root module
4
+ module RspecModelValidations
5
+ # RspecModelValidations version number: major.minor.maintenance
6
+ VERSION = '1.0.1'
7
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'rspec_model_validations/version'
4
+
5
+ require_relative 'rspec_model_validations/matchers'
6
+ require_relative 'rspec_model_validations/matchers/base'
7
+ require_relative 'rspec_model_validations/matchers/validate'
8
+ require_relative 'rspec_model_validations/matchers/invalidate'
9
+
10
+ module RspecModelValidations
11
+ class Error < StandardError; end
12
+ # Your code goes here...
13
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/rspec_model_validations/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'rspec_model_validations'
7
+ spec.version = RspecModelValidations::VERSION
8
+ spec.authors = ['Pierre Guego']
9
+ spec.email = ['pierre.guego@champagne-terroir.fr']
10
+
11
+ spec.summary = 'Extra matchers to test model validation'
12
+ spec.homepage = 'https://github.com/faljie/rspec_model_validations'
13
+ spec.license = 'MIT'
14
+ spec.required_ruby_version = '>= 3.0.0'
15
+
16
+ spec.metadata['homepage_uri'] = spec.homepage
17
+ spec.metadata['source_code_uri'] = spec.homepage
18
+
19
+ # Specify which files should be added to the gem when it is released.
20
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
22
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
23
+ end
24
+ spec.bindir = 'exe'
25
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
26
+ spec.require_paths = ['lib']
27
+
28
+ # For more information and examples about making a new gem, checkout our
29
+ # guide at: https://bundler.io/guides/creating_gem.html
30
+ end
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rspec_model_validations
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Pierre Guego
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-11-05 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ - pierre.guego@champagne-terroir.fr
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".gitignore"
21
+ - ".rspec"
22
+ - ".rubocop.yml"
23
+ - Dockerfile
24
+ - Gemfile
25
+ - Gemfile.lock
26
+ - LICENSE.txt
27
+ - Makefile
28
+ - README.md
29
+ - bin/console
30
+ - lib/rspec_model_validations.rb
31
+ - lib/rspec_model_validations/matchers.rb
32
+ - lib/rspec_model_validations/matchers/base.rb
33
+ - lib/rspec_model_validations/matchers/invalidate.rb
34
+ - lib/rspec_model_validations/matchers/validate.rb
35
+ - lib/rspec_model_validations/version.rb
36
+ - rspec_model_validations.gemspec
37
+ homepage: https://github.com/faljie/rspec_model_validations
38
+ licenses:
39
+ - MIT
40
+ metadata:
41
+ homepage_uri: https://github.com/faljie/rspec_model_validations
42
+ source_code_uri: https://github.com/faljie/rspec_model_validations
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: 3.0.0
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubygems_version: 3.2.22
59
+ signing_key:
60
+ specification_version: 4
61
+ summary: Extra matchers to test model validation
62
+ test_files: []