ae-validates_timeliness 4.0.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 +7 -0
- data/Appraisals +11 -0
- data/CHANGELOG.rdoc +190 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +178 -0
- data/LICENSE +20 -0
- data/README.md +329 -0
- data/Rakefile +30 -0
- data/ae-validates_timeliness.gemspec +25 -0
- data/autotest/discover.rb +1 -0
- data/gemfiles/rails_4_0.gemfile +15 -0
- data/gemfiles/rails_4_0.gemfile.lock +152 -0
- data/gemfiles/rails_4_1.gemfile +15 -0
- data/gemfiles/rails_4_1.gemfile.lock +156 -0
- data/gemfiles/rails_4_2.gemfile +15 -0
- data/gemfiles/rails_4_2.gemfile.lock +178 -0
- data/init.rb +1 -0
- data/lib/ae-validates_timeliness.rb +1 -0
- data/lib/ae-validates_timeliness/version.rb +3 -0
- data/lib/generators/validates_timeliness/install_generator.rb +16 -0
- data/lib/generators/validates_timeliness/templates/en.yml +16 -0
- data/lib/generators/validates_timeliness/templates/validates_timeliness.rb +40 -0
- data/lib/validates_timeliness.rb +70 -0
- data/lib/validates_timeliness/attribute_methods.rb +97 -0
- data/lib/validates_timeliness/conversion.rb +70 -0
- data/lib/validates_timeliness/extensions.rb +14 -0
- data/lib/validates_timeliness/extensions/date_time_select.rb +61 -0
- data/lib/validates_timeliness/extensions/multiparameter_handler.rb +80 -0
- data/lib/validates_timeliness/helper_methods.rb +23 -0
- data/lib/validates_timeliness/orm/active_record.rb +94 -0
- data/lib/validates_timeliness/orm/mongoid.rb +63 -0
- data/lib/validates_timeliness/railtie.rb +15 -0
- data/lib/validates_timeliness/validator.rb +117 -0
- metadata +159 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module Validations
|
3
|
+
|
4
|
+
module HelperMethods
|
5
|
+
def validates_date(*attr_names)
|
6
|
+
timeliness_validation_for attr_names, :date
|
7
|
+
end
|
8
|
+
|
9
|
+
def validates_time(*attr_names)
|
10
|
+
timeliness_validation_for attr_names, :time
|
11
|
+
end
|
12
|
+
|
13
|
+
def validates_datetime(*attr_names)
|
14
|
+
timeliness_validation_for attr_names, :datetime
|
15
|
+
end
|
16
|
+
|
17
|
+
def timeliness_validation_for(attr_names, type)
|
18
|
+
validates_with TimelinessValidator, _merge_attributes(attr_names).merge(:type => type)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module ValidatesTimeliness
|
2
|
+
module ORM
|
3
|
+
module ActiveRecord
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
public
|
8
|
+
|
9
|
+
def timeliness_attribute_timezone_aware?(attr_name)
|
10
|
+
create_time_zone_conversion_attribute?(attr_name, timeliness_column_for_attribute(attr_name))
|
11
|
+
end
|
12
|
+
|
13
|
+
def timeliness_attribute_type(attr_name)
|
14
|
+
timeliness_column_for_attribute(attr_name).type
|
15
|
+
end
|
16
|
+
|
17
|
+
def timeliness_column_for_attribute(attr_name)
|
18
|
+
if ::ActiveRecord.version < ::Gem::Version.new('4.2')
|
19
|
+
columns_hash.fetch(attr_name.to_s) do |attr_name|
|
20
|
+
validation_type = _validators[attr_name.to_sym].find {|v| v.kind == :timeliness }.type
|
21
|
+
::ActiveRecord::ConnectionAdapters::Column.new(attr_name, nil, validation_type.to_s)
|
22
|
+
end
|
23
|
+
else
|
24
|
+
columns_hash.fetch(attr_name.to_s) do |attr_name|
|
25
|
+
validation_type = _validators[attr_name.to_sym].find {|v| v.kind == :timeliness }.type
|
26
|
+
connection = ::ActiveRecord::Base.connection
|
27
|
+
connection.new_column(attr_name, nil, connection.lookup_cast_type(validation_type.to_s), validation_type.to_s)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def define_attribute_methods
|
33
|
+
super.tap do |attribute_methods_generated|
|
34
|
+
define_timeliness_methods(true) if attribute_methods_generated
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
|
40
|
+
def timeliness_type_cast_code(attr_name, var_name)
|
41
|
+
type = timeliness_attribute_type(attr_name)
|
42
|
+
|
43
|
+
method_body = super
|
44
|
+
method_body << "\n#{var_name} = #{var_name}.to_date if #{var_name}" if type == :date
|
45
|
+
method_body
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def reload(*args)
|
50
|
+
_clear_timeliness_cache
|
51
|
+
super
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
module ActiveRecordLessThan42
|
57
|
+
module ClassMethods
|
58
|
+
def allocate
|
59
|
+
define_attribute_methods
|
60
|
+
super
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def init_internals
|
67
|
+
self.class.define_attribute_methods
|
68
|
+
super
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class ActiveRecord::Base
|
76
|
+
include ValidatesTimeliness::AttributeMethods
|
77
|
+
include ValidatesTimeliness::ORM::ActiveRecord
|
78
|
+
|
79
|
+
if ActiveRecord.version < Gem::Version.new('4.2')
|
80
|
+
# Rails 4.0 / 4.1 are lazy and wait until method_missing / respond_to? is called before
|
81
|
+
# calling define_attribute_methods. This is now quite complex and no longer works with
|
82
|
+
# validates timeliness when the first attribute access for a AR model is to a
|
83
|
+
# validates_timeliness attribute.
|
84
|
+
#
|
85
|
+
# In Rails 4.2, this has changes to be less lazy and probably more robust. These patches
|
86
|
+
# match Rails 4.2.
|
87
|
+
|
88
|
+
prepend ValidatesTimeliness::ORM::ActiveRecordLessThan42
|
89
|
+
|
90
|
+
class << self
|
91
|
+
prepend ValidatesTimeliness::ORM::ActiveRecordLessThan42::ClassMethods
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module ValidatesTimeliness
|
2
|
+
module ORM
|
3
|
+
module Mongoid
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
# You need define the fields before you define the validations.
|
6
|
+
# It is best to use the plugin parser to avoid errors on a bad
|
7
|
+
# field value in Mongoid. Parser will return nil rather than error.
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
public
|
11
|
+
|
12
|
+
# Mongoid has no bulk attribute method definition hook. It defines
|
13
|
+
# them with each field definition. So we likewise define them after
|
14
|
+
# each validation is defined.
|
15
|
+
#
|
16
|
+
def timeliness_validation_for(attr_names, type)
|
17
|
+
super
|
18
|
+
attr_names.each { |attr_name| define_timeliness_write_method(attr_name) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def timeliness_attribute_type(attr_name)
|
22
|
+
{
|
23
|
+
Date => :date,
|
24
|
+
Time => :time,
|
25
|
+
DateTime => :datetime
|
26
|
+
}[fields[attr_name.to_s].type] || :datetime
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def timeliness_type_cast_code(attr_name, var_name)
|
32
|
+
type = timeliness_attribute_type(attr_name)
|
33
|
+
|
34
|
+
"#{var_name} = Timeliness::Parser.parse(value, :#{type})"
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
module Reload
|
40
|
+
def reload(*args)
|
41
|
+
_clear_timeliness_cache
|
42
|
+
super
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
module Mongoid::Document
|
50
|
+
include ValidatesTimeliness::AttributeMethods
|
51
|
+
include ValidatesTimeliness::ORM::Mongoid
|
52
|
+
|
53
|
+
# Pre-2.3 reload
|
54
|
+
if (instance_methods & ['reload', :reload]).present?
|
55
|
+
def reload_with_timeliness
|
56
|
+
_clear_timeliness_cache
|
57
|
+
reload_without_timeliness
|
58
|
+
end
|
59
|
+
alias_method_chain :reload, :timeliness
|
60
|
+
else
|
61
|
+
include ValidatesTimeliness::ORM::Mongoid::Reload
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ValidatesTimeliness
|
2
|
+
class Railtie < Rails::Railtie
|
3
|
+
initializer "validates_timeliness.initialize_active_record", :after => 'active_record.initialize_timezone' do
|
4
|
+
ActiveSupport.on_load(:active_record) do
|
5
|
+
ValidatesTimeliness.default_timezone = ActiveRecord::Base.default_timezone
|
6
|
+
ValidatesTimeliness.extend_orms << :active_record
|
7
|
+
ValidatesTimeliness.load_orms
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
initializer "validates_timeliness.initialize_restriction_errors" do
|
12
|
+
ValidatesTimeliness.ignore_restriction_errors = !Rails.env.test?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
require 'active_model/validator'
|
3
|
+
|
4
|
+
module ValidatesTimeliness
|
5
|
+
class Validator < ActiveModel::EachValidator
|
6
|
+
include Conversion
|
7
|
+
|
8
|
+
attr_reader :type
|
9
|
+
|
10
|
+
RESTRICTIONS = {
|
11
|
+
:is_at => :==,
|
12
|
+
:before => :<,
|
13
|
+
:after => :>,
|
14
|
+
:on_or_before => :<=,
|
15
|
+
:on_or_after => :>=,
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
DEFAULT_ERROR_VALUE_FORMATS = {
|
19
|
+
:date => '%Y-%m-%d',
|
20
|
+
:time => '%H:%M:%S',
|
21
|
+
:datetime => '%Y-%m-%d %H:%M:%S'
|
22
|
+
}.freeze
|
23
|
+
|
24
|
+
RESTRICTION_ERROR_MESSAGE = "Error occurred validating %s for %s restriction:\n%s"
|
25
|
+
|
26
|
+
# Prior to version 4.1, Rails will call `#setup`, if defined. This method is deprecated in Rails 4.1 and removed
|
27
|
+
# altogether in 4.2.
|
28
|
+
SETUP_DEPRECATED = ActiveModel.respond_to?(:version) && ActiveModel.version >= Gem::Version.new('4.1')
|
29
|
+
|
30
|
+
def self.kind
|
31
|
+
:timeliness
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(options)
|
35
|
+
@type = options.delete(:type) || :datetime
|
36
|
+
@allow_nil, @allow_blank = options.delete(:allow_nil), options.delete(:allow_blank)
|
37
|
+
|
38
|
+
if range = options.delete(:between)
|
39
|
+
raise ArgumentError, ":between must be a Range or an Array" unless range.is_a?(Range) || range.is_a?(Array)
|
40
|
+
options[:on_or_after] = range.first
|
41
|
+
if range.is_a?(Range) && range.exclude_end?
|
42
|
+
options[:before] = range.last
|
43
|
+
else
|
44
|
+
options[:on_or_before] = range.last
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
@restrictions_to_check = RESTRICTIONS.keys & options.keys
|
49
|
+
super
|
50
|
+
setup_timeliness_validated_attributes(options[:class]) if options[:class]
|
51
|
+
end
|
52
|
+
|
53
|
+
def setup_timeliness_validated_attributes(model)
|
54
|
+
if model.respond_to?(:timeliness_validated_attributes)
|
55
|
+
model.timeliness_validated_attributes ||= []
|
56
|
+
model.timeliness_validated_attributes |= @attributes
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Provide backwards compatibility for Rails < 4.1, which expects `#setup` to be defined.
|
61
|
+
alias_method :setup, :setup_timeliness_validated_attributes unless SETUP_DEPRECATED
|
62
|
+
|
63
|
+
def validate_each(record, attr_name, value)
|
64
|
+
raw_value = attribute_raw_value(record, attr_name) || value
|
65
|
+
return if (@allow_nil && raw_value.nil?) || (@allow_blank && raw_value.blank?)
|
66
|
+
|
67
|
+
@timezone_aware = timezone_aware?(record, attr_name)
|
68
|
+
value = parse(raw_value) if value.is_a?(String) || options[:format]
|
69
|
+
value = type_cast_value(value, @type)
|
70
|
+
|
71
|
+
add_error(record, attr_name, :"invalid_#{@type}") and return if value.blank?
|
72
|
+
|
73
|
+
validate_restrictions(record, attr_name, value)
|
74
|
+
end
|
75
|
+
|
76
|
+
def validate_restrictions(record, attr_name, value)
|
77
|
+
@restrictions_to_check.each do |restriction|
|
78
|
+
begin
|
79
|
+
restriction_value = type_cast_value(evaluate_option_value(options[restriction], record), @type)
|
80
|
+
unless value.send(RESTRICTIONS[restriction], restriction_value)
|
81
|
+
add_error(record, attr_name, restriction, restriction_value) and break
|
82
|
+
end
|
83
|
+
rescue => e
|
84
|
+
unless ValidatesTimeliness.ignore_restriction_errors
|
85
|
+
message = RESTRICTION_ERROR_MESSAGE % [ attr_name, restriction.inspect, e.message ]
|
86
|
+
add_error(record, attr_name, message) and break
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def add_error(record, attr_name, message, value=nil)
|
93
|
+
value = format_error_value(value) if value
|
94
|
+
message_options = { :message => options[:"#{message}_message"], :restriction => value }
|
95
|
+
record.errors.add(attr_name, message, message_options)
|
96
|
+
end
|
97
|
+
|
98
|
+
def format_error_value(value)
|
99
|
+
format = I18n.t(@type, :default => DEFAULT_ERROR_VALUE_FORMATS[@type], :scope => 'validates_timeliness.error_value_formats')
|
100
|
+
value.strftime(format)
|
101
|
+
end
|
102
|
+
|
103
|
+
def attribute_raw_value(record, attr_name)
|
104
|
+
record.respond_to?(:_timeliness_raw_value_for) &&
|
105
|
+
record._timeliness_raw_value_for(attr_name.to_s)
|
106
|
+
end
|
107
|
+
|
108
|
+
def timezone_aware?(record, attr_name)
|
109
|
+
record.class.respond_to?(:timeliness_attribute_timezone_aware?) &&
|
110
|
+
record.class.timeliness_attribute_timezone_aware?(attr_name)
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Compatibility with ActiveModel validates method which matches option keys to their validator class
|
117
|
+
ActiveModel::Validations::TimelinessValidator = ValidatesTimeliness::Validator
|
metadata
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ae-validates_timeliness
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 4.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Paul Kmiec
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-07-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: timeliness
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.3.7
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.3.7
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: coveralls
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec-rails
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec-collection_matchers
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: Adds validation methods to ActiveModel for validating dates and times.
|
98
|
+
Works with multiple ORMS.
|
99
|
+
email: paul.kmiec@appfolio.com
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- Appraisals
|
105
|
+
- CHANGELOG.rdoc
|
106
|
+
- Gemfile
|
107
|
+
- Gemfile.lock
|
108
|
+
- LICENSE
|
109
|
+
- README.md
|
110
|
+
- Rakefile
|
111
|
+
- ae-validates_timeliness.gemspec
|
112
|
+
- autotest/discover.rb
|
113
|
+
- gemfiles/rails_4_0.gemfile
|
114
|
+
- gemfiles/rails_4_0.gemfile.lock
|
115
|
+
- gemfiles/rails_4_1.gemfile
|
116
|
+
- gemfiles/rails_4_1.gemfile.lock
|
117
|
+
- gemfiles/rails_4_2.gemfile
|
118
|
+
- gemfiles/rails_4_2.gemfile.lock
|
119
|
+
- init.rb
|
120
|
+
- lib/ae-validates_timeliness.rb
|
121
|
+
- lib/ae-validates_timeliness/version.rb
|
122
|
+
- lib/generators/validates_timeliness/install_generator.rb
|
123
|
+
- lib/generators/validates_timeliness/templates/en.yml
|
124
|
+
- lib/generators/validates_timeliness/templates/validates_timeliness.rb
|
125
|
+
- lib/validates_timeliness.rb
|
126
|
+
- lib/validates_timeliness/attribute_methods.rb
|
127
|
+
- lib/validates_timeliness/conversion.rb
|
128
|
+
- lib/validates_timeliness/extensions.rb
|
129
|
+
- lib/validates_timeliness/extensions/date_time_select.rb
|
130
|
+
- lib/validates_timeliness/extensions/multiparameter_handler.rb
|
131
|
+
- lib/validates_timeliness/helper_methods.rb
|
132
|
+
- lib/validates_timeliness/orm/active_record.rb
|
133
|
+
- lib/validates_timeliness/orm/mongoid.rb
|
134
|
+
- lib/validates_timeliness/railtie.rb
|
135
|
+
- lib/validates_timeliness/validator.rb
|
136
|
+
homepage: http://github.com/appfolio/validates_timeliness
|
137
|
+
licenses: []
|
138
|
+
metadata: {}
|
139
|
+
post_install_message:
|
140
|
+
rdoc_options: []
|
141
|
+
require_paths:
|
142
|
+
- lib
|
143
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
144
|
+
requirements:
|
145
|
+
- - ">="
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: '0'
|
148
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
requirements: []
|
154
|
+
rubyforge_project:
|
155
|
+
rubygems_version: 2.4.7
|
156
|
+
signing_key:
|
157
|
+
specification_version: 4
|
158
|
+
summary: Date and time validation plugin for Rails which allows custom formats
|
159
|
+
test_files: []
|