Merge pull request #134 from houdiniproject/ruby_param_validation
Add ruby-param-validation to repo
This commit is contained in:
commit
e695c7cbcf
8 changed files with 559 additions and 9 deletions
3
Gemfile
3
Gemfile
|
@ -47,8 +47,7 @@ gem 'dalli'
|
||||||
gem 'memcachier'
|
gem 'memcachier'
|
||||||
|
|
||||||
|
|
||||||
gem 'param_validation', git: 'https://github.com/commitchange/ruby-param-validation.git'
|
gem 'param_validation', path: 'gems/ruby-param-validation'
|
||||||
#gem 'param_validation', path: '../ruby-param-validation'
|
|
||||||
|
|
||||||
# Print colorized text lol
|
# Print colorized text lol
|
||||||
gem 'colorize'
|
gem 'colorize'
|
||||||
|
|
14
Gemfile.lock
14
Gemfile.lock
|
@ -1,10 +1,3 @@
|
||||||
GIT
|
|
||||||
remote: https://github.com/commitchange/ruby-param-validation.git
|
|
||||||
revision: 4269cdef83eb95eea749f05c22a9b747b8f1f256
|
|
||||||
specs:
|
|
||||||
param_validation (0.0.2)
|
|
||||||
chronic
|
|
||||||
|
|
||||||
GIT
|
GIT
|
||||||
remote: https://github.com/commitchange/stripe-ruby-mock.git
|
remote: https://github.com/commitchange/stripe-ruby-mock.git
|
||||||
revision: ee4471a8f654672d5596218c2b68a2913ea3f4cc
|
revision: ee4471a8f654672d5596218c2b68a2913ea3f4cc
|
||||||
|
@ -33,6 +26,12 @@ GIT
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
multi_json (>= 1.3.2)
|
multi_json (>= 1.3.2)
|
||||||
|
|
||||||
|
PATH
|
||||||
|
remote: gems/ruby-param-validation
|
||||||
|
specs:
|
||||||
|
param_validation (0.0.2)
|
||||||
|
chronic
|
||||||
|
|
||||||
PATH
|
PATH
|
||||||
remote: gems/ruby-qx
|
remote: gems/ruby-qx
|
||||||
specs:
|
specs:
|
||||||
|
@ -40,6 +39,7 @@ PATH
|
||||||
activerecord (>= 3.0)
|
activerecord (>= 3.0)
|
||||||
colorize (~> 0.8)
|
colorize (~> 0.8)
|
||||||
|
|
||||||
|
|
||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
|
|
21
gems/ruby-param-validation/LICENSE
Normal file
21
gems/ruby-param-validation/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2016 Jay R Bolton, CommitChange
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
162
gems/ruby-param-validation/README.md
Normal file
162
gems/ruby-param-validation/README.md
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
# ParamValidation
|
||||||
|
|
||||||
|
A standalone and simple ruby hash validation lib, useful for validating the data passed to your functions.
|
||||||
|
|
||||||
|
```rb
|
||||||
|
new_charge_validation = {
|
||||||
|
amount: {
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
stripe_card_token: {
|
||||||
|
required: true,
|
||||||
|
format: /^tok_.*$/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def update_database(data)
|
||||||
|
ParamValidation.new(data, new_charge_validation)
|
||||||
|
# do stuff
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
The above checks the `:amount` and `:stripe_card_token` keys inside the `data`
|
||||||
|
hash and runs validations on them. If a value is invalid, an exception is
|
||||||
|
thrown. The exception can be handled outside your function call, typically in a
|
||||||
|
controller/router or in a test suite.
|
||||||
|
|
||||||
|
An exception is thrown for each failure.
|
||||||
|
|
||||||
|
## ParamValidation::Error
|
||||||
|
|
||||||
|
The ParamValidation::Error object has the following information on it:
|
||||||
|
|
||||||
|
```rb
|
||||||
|
begin
|
||||||
|
update_database(data)
|
||||||
|
rescue ParamValidation::Error => e
|
||||||
|
e.message # string validation failure message
|
||||||
|
e.val # value that failed validation
|
||||||
|
e.key # key name of the above value inside the data hash
|
||||||
|
e.name # name of the validator that failed
|
||||||
|
rescue Exception => e
|
||||||
|
# a non-validation exception
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
## Using in Rails
|
||||||
|
|
||||||
|
To handle validation exceptions from the controller, you can add a custom helper function in your ApplicationController like this:
|
||||||
|
|
||||||
|
```rb
|
||||||
|
def render_json(&block)
|
||||||
|
begin
|
||||||
|
result = yield block
|
||||||
|
rescue ParamValidation::Error => e
|
||||||
|
return {status: 422, json: {error: e.message, key: e.key}}
|
||||||
|
rescue Error => e # a non-validation related exception
|
||||||
|
return {status: 500, json: e}
|
||||||
|
end
|
||||||
|
return {status: 200, json: result}
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
With the above, you can simply call render_json on your validated function call:
|
||||||
|
|
||||||
|
```rb
|
||||||
|
UsersController < ApplicationController
|
||||||
|
def update
|
||||||
|
render_json{ update_user(params[:user]) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
```rb
|
||||||
|
update_validation = {
|
||||||
|
email: {
|
||||||
|
presence: :optional,
|
||||||
|
format: email_regex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def update_user(params)
|
||||||
|
ParamValidation.new(params, update_validation)
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### built-in validators
|
||||||
|
|
||||||
|
- required: value must be non-nil
|
||||||
|
- absent: value must be nil
|
||||||
|
- not_included_in: value must not be in array
|
||||||
|
- included_in: value must be in array
|
||||||
|
- format: value must match regex
|
||||||
|
- is_integer: value must look like an integer (can be a string)
|
||||||
|
- is_float: value must look like a float (can be a string)
|
||||||
|
- min_length: array value must have length >= min
|
||||||
|
- max_length: array value must have length <= max
|
||||||
|
- length_range: array value must have length within given range
|
||||||
|
- length_equals: array value length must equal given arg
|
||||||
|
- equals: value must equal given arg
|
||||||
|
- min: value must be >= arg
|
||||||
|
- max: value must be <= arg
|
||||||
|
- in_range: value must be within the given range
|
||||||
|
|
||||||
|
### custom validators
|
||||||
|
|
||||||
|
ParamValidation.add_validator takes a name and a block. That block performs the
|
||||||
|
validations and simply returns true/false. The block takes three params: the
|
||||||
|
actual value to validate, and the argument provided in the validation hash, and
|
||||||
|
the entire data hash being validated.
|
||||||
|
|
||||||
|
```rb
|
||||||
|
# You can use other validators inside a new validator
|
||||||
|
ParamValidation.add_validator(:dollars) do |val, arg, data|
|
||||||
|
ParamValidation.validators[:format](val, /^\$\d+\.(\d\d)$?, data)
|
||||||
|
end
|
||||||
|
|
||||||
|
# # Validators that don't need an argument typically just get 'true' passed in
|
||||||
|
# ParamValidation.new(params, {
|
||||||
|
# amount: { dollars: true }
|
||||||
|
# })
|
||||||
|
|
||||||
|
# Other examples
|
||||||
|
|
||||||
|
# Uniqueness validation (of course it may be better to use the UNIQUE constraint in sql)
|
||||||
|
ParamValidation.add_validator(:unique) do |val, arg, data|
|
||||||
|
Qx.select("COUNT(*)").from(:table).where(name: val).first['count'] == 0
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### custom validation messages
|
||||||
|
|
||||||
|
Within a validation instance, you can set a custom message with the :message key.
|
||||||
|
|
||||||
|
```rb
|
||||||
|
ParamValidation.new(params, {
|
||||||
|
amount: {
|
||||||
|
dollars: true,
|
||||||
|
message: 'Please enter a dollar amount'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
To change the global default message, simply use ParamValidation.set_message(:validation_name, &block).
|
||||||
|
|
||||||
|
```rb
|
||||||
|
ParamValidation.set_message(:dollars) do |h|
|
||||||
|
"#{h[:key]} must be in dollars"
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
The `set_message` block receives a hash with some data:
|
||||||
|
|
||||||
|
* :key - name of the key in the hash that failed this validation
|
||||||
|
* :arg - argument to validator (eg format regex)
|
||||||
|
* :val - actual value that failed validation
|
||||||
|
* :data - entire data hash that is being validated
|
||||||
|
|
||||||
|
|
||||||
|
#### internationalization -- TODO!
|
||||||
|
|
||||||
|
Internationalization support is not yet in place; please make a PR for it!
|
9
gems/ruby-param-validation/Rakefile
Normal file
9
gems/ruby-param-validation/Rakefile
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
require 'rake/testtask'
|
||||||
|
|
||||||
|
Rake::TestTask.new do |t|
|
||||||
|
t.libs << 'test'
|
||||||
|
t.test_files = FileList['test/test*.rb', 'test/*test.rb']
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "Run tests"
|
||||||
|
task :default => :test
|
130
gems/ruby-param-validation/lib/param_validation.rb
Normal file
130
gems/ruby-param-validation/lib/param_validation.rb
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
require 'json'
|
||||||
|
require 'chronic'
|
||||||
|
|
||||||
|
class ParamValidation
|
||||||
|
|
||||||
|
# Given a hash of data and a validation hash, check all the validations, raising an Error on the first invalid key
|
||||||
|
# @raise [ValidationError] if one or more of the validations fail.
|
||||||
|
def initialize(data, validations)
|
||||||
|
errors = []
|
||||||
|
validations.each do |key, validators|
|
||||||
|
val = key === :root ? data : (data[key] || data[key.to_s] || data[key.to_sym])
|
||||||
|
next if validators[:required].nil? && val.nil?
|
||||||
|
validators.each do |name, arg|
|
||||||
|
validator = @@validators[name]
|
||||||
|
msg = validations[key][:message]
|
||||||
|
next unless validator
|
||||||
|
is_valid = @@validators[name].call(val, arg, data)
|
||||||
|
msg_proc = @@messages[name]
|
||||||
|
msg ||= @@messages[name].call({key: key, data: data, val: val, arg: arg}) if msg_proc
|
||||||
|
errors.push({msg: msg, data: {key: key, val: val, name: name, msg: msg}}) unless is_valid
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if errors.length == 1
|
||||||
|
raise ValidationError.new(errors[0][:msg], errors[0][:data])
|
||||||
|
elsif errors.length > 1
|
||||||
|
msg = errors.collect {|e| e[:msg]}.join('\n')
|
||||||
|
raise ValidationError.new(msg, errors.collect{|e| e[:data]})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.messages; @@messages; end
|
||||||
|
def self.set_message(name, &block)
|
||||||
|
@@messages[name] = block
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.validators; @@validators; end
|
||||||
|
def self.add_validator(name, &block)
|
||||||
|
@@validators[name] = block
|
||||||
|
end
|
||||||
|
def self.structure_validators; @@structure_validators; end
|
||||||
|
def self.add_structure_validator(name, &block)
|
||||||
|
@@structure_validators[name] = block
|
||||||
|
end
|
||||||
|
|
||||||
|
# In each Proc
|
||||||
|
# - val is the value we are actually validating from the data passed in
|
||||||
|
# - arg is the argument passed into the validator (eg for {required: true}, it is `true`)
|
||||||
|
# - data is the entire set of data
|
||||||
|
@@validators = {
|
||||||
|
required: lambda {|val, arg, data| !val.nil?},
|
||||||
|
absent: lambda {|val, arg, data| val.nil?},
|
||||||
|
not_blank: lambda {|val, arg, data| val.is_a?(String) && val.length > 0},
|
||||||
|
not_included_in: lambda {|val, arg, data| !arg.include?(val) rescue false},
|
||||||
|
included_in: lambda {|val, arg, data| arg.include?(val) rescue false},
|
||||||
|
format: lambda {|val, arg, data| val =~ arg rescue false},
|
||||||
|
is_integer: lambda {|val, arg, data| val.is_a?(Integer) || val =~ /\A[+-]?\d+\Z/},
|
||||||
|
is_float: lambda {|val, arg, data| val.is_a?(Float) || (!!Float(val) rescue false) },
|
||||||
|
min_length: lambda {|val, arg, data| val.length >= arg rescue false},
|
||||||
|
max_length: lambda {|val, arg, data| val.length <= arg rescue false},
|
||||||
|
length_range: lambda {|val, arg, data| arg.cover?(val.length) rescue false},
|
||||||
|
length_equals: lambda {|val, arg, data| val.length == arg},
|
||||||
|
is_reference: lambda{|val, arg, data| (val.is_a?(Integer)&& val >=0) || val =~ /\A\d+\Z/ || val == ''},
|
||||||
|
equals: lambda {|val, arg, data| val == arg},
|
||||||
|
min: lambda {|val, arg, data| val >= arg rescue false},
|
||||||
|
max: lambda {|val, arg, data| val <= arg rescue false},
|
||||||
|
is_array: lambda {|val, arg, data| val.is_a?(Array)},
|
||||||
|
is_hash: lambda {|val, arg, data| val.is_a?(Hash)},
|
||||||
|
is_json: lambda {|val, arg, data| ParamValidation.is_valid_json?(val)},
|
||||||
|
in_range: lambda {|val, arg, data| arg.cover?(val) rescue false},
|
||||||
|
is_a: lambda {|val, arg, data| arg.kind_of?(Enumerable) ? arg.any? {|i| val.is_a?(i)} : val.is_a?(arg)},
|
||||||
|
can_be_date: lambda {|val, arg, data| val.is_a?(Date) || val.is_a?(DateTime) || Chronic.parse(val)},
|
||||||
|
array_of_hashes: lambda {|val, arg, data| data.is_a?(Array) && data.map{|pair| ParamValidation.new(pair.to_h, arg)}.all?}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@messages = {
|
||||||
|
required: lambda {|h| "#{h[:key]} is required"},
|
||||||
|
absent: lambda {|h| "#{h[:key]} must not be present"},
|
||||||
|
not_blank: lambda {|h| "#{h[:key]} must not be blank"},
|
||||||
|
not_included_in: lambda {|h| "#{h[:key]} must not be included in #{h[:arg].join(", ")}"},
|
||||||
|
included_in: lambda {|h|"#{h[:key]} must be one of #{h[:arg].join(", ")}"},
|
||||||
|
format: lambda {|h|"#{h[:key]} doesn't have the right format"},
|
||||||
|
is_integer: lambda {|h|"#{h[:key]} should be an integer"},
|
||||||
|
is_float: lambda {|h|"#{h[:key]} should be a float"},
|
||||||
|
min_length: lambda {|h|"#{h[:key]} has a minimum length of #{h[:arg]}"},
|
||||||
|
max_length: lambda {|h|"#{h[:key]} has a maximum length of #{h[:arg]}"},
|
||||||
|
length_range: lambda {|h|"#{h[:key]} should have a length within #{h[:arg]}"},
|
||||||
|
length_equals: lambda {|h|"#{h[:key]} should have a length of #{h[:arg]}"},
|
||||||
|
is_reference: lambda{|h| "#{h[:key]} should be an integer or blank"},
|
||||||
|
equals: lambda {|h|"#{h[:key]} should equal #{h[:arg]}"},
|
||||||
|
min: lambda {|h|"#{h[:key]} must be at least #{h[:arg]}"},
|
||||||
|
max: lambda {|h|"#{h[:key]} cannot be more than #{h[:arg]}"},
|
||||||
|
in_range: lambda {|h|"#{h[:key]} should be within #{h[:arg]}"},
|
||||||
|
is_json: lambda {|h| "#{h[:key]} should be valid JSON"},
|
||||||
|
is_hash: lambda {|h| "#{h[:key]} should be a hash"},
|
||||||
|
is_a: lambda {|h| "#{h[:key]} should be of the type(s): #{h[:arg].kind_of?(Enumerable) ? h[:arg].join(', '): h[:arg]}"},
|
||||||
|
can_be_date: lambda {|h| "#{h[:key]} should be a datetime or be parsable as one"},
|
||||||
|
array_of_hashes: lambda {|h| "Please pass in an array of hashes"}
|
||||||
|
}
|
||||||
|
|
||||||
|
# small utility for testing json validity
|
||||||
|
def self.is_valid_json?(str)
|
||||||
|
begin
|
||||||
|
JSON.parse(str)
|
||||||
|
return true
|
||||||
|
rescue => e
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Special error class that holds all the error data for reference
|
||||||
|
class ValidationError < TypeError
|
||||||
|
attr_reader :data
|
||||||
|
|
||||||
|
# @param [String] msg message for the validation error(s). Multiple error
|
||||||
|
# messages are split by new lines (\n)
|
||||||
|
# @param [Hash, Array<Hash>] data information about the validation failure
|
||||||
|
# or failures. If one failure, a single failure hash is returned, if multiple, an array is returned.
|
||||||
|
# Each failure hash has the following:
|
||||||
|
# * :key - the [Symbol] of the key in the hash where verification failed
|
||||||
|
# * :val - the value of pair in the hash selected by :key
|
||||||
|
# * :name - the [Symbol] for the verification which failed
|
||||||
|
# * :msg - the [String] for the msg for the verifications which failed
|
||||||
|
def initialize(msg, data)
|
||||||
|
@data = data
|
||||||
|
super(msg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
14
gems/ruby-param-validation/param_validation.gemspec
Normal file
14
gems/ruby-param-validation/param_validation.gemspec
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
Gem::Specification.new do |s|
|
||||||
|
s.name = 'param_validation'
|
||||||
|
s.version = '0.0.2'
|
||||||
|
s.date = '2017-07-21'
|
||||||
|
s.summary = 'Simple hash validator'
|
||||||
|
s.description = 'A hash validator that throws exceptions, with a lot of customization options'
|
||||||
|
s.authors = ['Jay R Bolton']
|
||||||
|
s.email = 'jayrbolton@gmail.com'
|
||||||
|
s.files = 'lib/param_validation.rb'
|
||||||
|
s.homepage = 'https://github.com/jayrbolton/ruby-param-validation'
|
||||||
|
s.license = 'MIT'
|
||||||
|
|
||||||
|
s.add_runtime_dependency 'chronic'
|
||||||
|
end
|
215
gems/ruby-param-validation/test/param_validation_test.rb
Normal file
215
gems/ruby-param-validation/test/param_validation_test.rb
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
require './lib/param_validation.rb'
|
||||||
|
require 'minitest/autorun'
|
||||||
|
|
||||||
|
class ParamValidationTest < Minitest::Test
|
||||||
|
|
||||||
|
def setup
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_required
|
||||||
|
begin; ParamValidation.new({}, {x: {required: true}})
|
||||||
|
rescue ParamValidation::ValidationError => e; e; end
|
||||||
|
assert_equal :x, e.data[:key]
|
||||||
|
end
|
||||||
|
# If a key is not required, then don't run the tests on it
|
||||||
|
def test_not_required_and_absent_then_tests_do_not_run
|
||||||
|
ParamValidation.new({}, {x: {max: 100}})
|
||||||
|
assert true
|
||||||
|
end
|
||||||
|
def test_not_blank_fail
|
||||||
|
begin; ParamValidation.new({x: ''}, {x: {not_blank: true}})
|
||||||
|
rescue ParamValidation::ValidationError => e; e; end
|
||||||
|
assert_equal :x, e.data[:key]
|
||||||
|
end
|
||||||
|
def test_not_blank_fail_nil
|
||||||
|
begin; ParamValidation.new({x: nil}, {x: {not_blank: true, required: true}})
|
||||||
|
rescue ParamValidation::ValidationError => e; e; end
|
||||||
|
assert(e.data.one?{|i| i[:name] == :not_blank && i[:key] == :x})
|
||||||
|
assert(e.data.one?{|i| i[:name] == :required && i[:key] == :x})
|
||||||
|
end
|
||||||
|
def test_not_blank_succeed
|
||||||
|
ParamValidation.new({x: 'x'}, {x: {not_blank: true}})
|
||||||
|
assert true
|
||||||
|
end
|
||||||
|
def test_require_no_err
|
||||||
|
begin; ParamValidation.new({x: 1}, {x: {required: true}})
|
||||||
|
rescue ParamValidation::ValidationError => e; end
|
||||||
|
assert e.nil?
|
||||||
|
end
|
||||||
|
def test_absent
|
||||||
|
begin; ParamValidation.new({x: 1}, {x: {absent: true}})
|
||||||
|
rescue ParamValidation::ValidationError => e; e; end
|
||||||
|
assert_equal :x, e.data[:key]
|
||||||
|
end
|
||||||
|
def test_not_included_in
|
||||||
|
begin; ParamValidation.new({x: 1}, {x: {not_included_in: [1]}})
|
||||||
|
rescue ParamValidation::ValidationError => e; e; end
|
||||||
|
assert_equal :x, e.data[:key]
|
||||||
|
end
|
||||||
|
def test_included_in
|
||||||
|
begin; ParamValidation.new({x: 1}, {x: {included_in: [2]}})
|
||||||
|
rescue ParamValidation::ValidationError => e; e; end
|
||||||
|
assert_equal :x, e.data[:key]
|
||||||
|
end
|
||||||
|
def test_format
|
||||||
|
begin; ParamValidation.new({x: 'x'}, {x: {format: /y/}})
|
||||||
|
rescue ParamValidation::ValidationError => e; e; end
|
||||||
|
assert_equal :x, e.data[:key]
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_is_reference_string
|
||||||
|
begin; ParamValidation.new({x: '-0'}, {x: {is_reference: true}})
|
||||||
|
rescue ParamValidation::ValidationError => e; e; end
|
||||||
|
assert_equal :x, e.data[:key]
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_is_reference_negative_integer
|
||||||
|
begin; ParamValidation.new({x: -1}, {x: {is_reference: true}})
|
||||||
|
rescue ParamValidation::ValidationError => e; e; end
|
||||||
|
assert_equal :x, e.data[:key]
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_is_reference_passes
|
||||||
|
ParamValidation.new({x: '0'}, {x: {is_reference: true}})
|
||||||
|
ParamValidation.new({x: 1}, {x: {is_reference: true}})
|
||||||
|
ParamValidation.new({x: ''}, {x: {is_reference: true}})
|
||||||
|
pass()
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_is_integer
|
||||||
|
begin; ParamValidation.new({x: 'x'}, {x: {is_integer: true}})
|
||||||
|
rescue ParamValidation::ValidationError => e; e; end
|
||||||
|
assert_equal :x, e.data[:key]
|
||||||
|
end
|
||||||
|
def test_is_float
|
||||||
|
begin; ParamValidation.new({x: 'x'}, {x: {is_float: true}})
|
||||||
|
rescue ParamValidation::ValidationError => e; e; end
|
||||||
|
assert_equal :x, e.data[:key]
|
||||||
|
end
|
||||||
|
def test_min_length
|
||||||
|
begin; ParamValidation.new({x: []}, {x: {min_length: 2}})
|
||||||
|
rescue ParamValidation::ValidationError => e; e; end
|
||||||
|
assert_equal :x, e.data[:key]
|
||||||
|
end
|
||||||
|
def test_max_length
|
||||||
|
begin; ParamValidation.new({x: [1,2,3]}, {x: {max_length: 2}})
|
||||||
|
rescue ParamValidation::ValidationError => e; e; end
|
||||||
|
assert_equal e.data[:key], :x
|
||||||
|
end
|
||||||
|
def test_length_range
|
||||||
|
begin; ParamValidation.new({x: [1,2,3,4]}, {x: {length_range: 1..3}})
|
||||||
|
rescue ParamValidation::ValidationError => e; e; end
|
||||||
|
assert_equal e.data[:key], :x
|
||||||
|
end
|
||||||
|
def test_length_equals
|
||||||
|
begin; ParamValidation.new({x: [1,2]}, {x: {length_equals: 1}})
|
||||||
|
rescue ParamValidation::ValidationError => e; e; end
|
||||||
|
assert_equal e.data[:key], :x
|
||||||
|
end
|
||||||
|
def test_min
|
||||||
|
begin; ParamValidation.new({x: 1}, {x: {min: 2}})
|
||||||
|
rescue ParamValidation::ValidationError => e; e; end
|
||||||
|
assert_equal e.data[:key], :x
|
||||||
|
end
|
||||||
|
def test_max
|
||||||
|
begin; ParamValidation.new({x: 4}, {x: {max: 2}})
|
||||||
|
rescue ParamValidation::ValidationError => e; e; end
|
||||||
|
assert_equal e.data[:name], :max
|
||||||
|
end
|
||||||
|
def test_in_range
|
||||||
|
begin; ParamValidation.new({x: 1}, {x: {in_range: 2..4}})
|
||||||
|
rescue ParamValidation::ValidationError => e; e; end
|
||||||
|
assert_equal e.data[:val], 1
|
||||||
|
end
|
||||||
|
def test_equals
|
||||||
|
begin; ParamValidation.new({x: 1}, {x: {equals: 2}})
|
||||||
|
rescue ParamValidation::ValidationError => e; e; end
|
||||||
|
assert_equal "x should equal #{2}", e.to_s
|
||||||
|
end
|
||||||
|
def test_root_array_of_hashes
|
||||||
|
begin; ParamValidation.new({x: 1}, {root: {array_of_hashes: {x: {required: true}}}})
|
||||||
|
rescue ParamValidation::ValidationError => e; e; end
|
||||||
|
assert_equal "Please pass in an array of hashes", e.to_s
|
||||||
|
end
|
||||||
|
def test_root_array_of_hashes_with_nesting_ok
|
||||||
|
v = ParamValidation.new([{'x' => 1}, {x: 1}], {root: {array_of_hashes: {x: {is_integer: true}}}})
|
||||||
|
assert_equal v, v # test that it does not raise
|
||||||
|
end
|
||||||
|
def test_root_array_of_hashes_with_nesting
|
||||||
|
begin; ParamValidation.new([{x: 1}, {x: 'hi'}], {root: {array_of_hashes: {x: {is_integer: true}}}})
|
||||||
|
rescue ParamValidation::ValidationError => e; e; end
|
||||||
|
assert_equal "x should be an integer", e.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_is_json_with_string
|
||||||
|
begin; ParamValidation.new({x: '[[[[[[['}, {x: {is_json: true}})
|
||||||
|
rescue ParamValidation::ValidationError => e; e; end
|
||||||
|
assert_equal "x should be valid JSON", e.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_is_json_without_string
|
||||||
|
begin; ParamValidation.new({x: {}}, {x: {is_json: true}})
|
||||||
|
rescue ParamValidation::ValidationError => e; e; end
|
||||||
|
assert_equal "x should be valid JSON", e.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_is_a_single
|
||||||
|
ParamValidation.new({x: 5.6}, {x: {is_a: Float}})
|
||||||
|
begin
|
||||||
|
ParamValidation.new({x: 5.6}, {x: {is_a: Integer}})
|
||||||
|
rescue ParamValidation::ValidationError => e
|
||||||
|
e
|
||||||
|
end
|
||||||
|
assert_equal 'x should be of the type(s): Integer', e.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_a_multiple
|
||||||
|
ParamValidation.new({x: 5.6}, {x: {is_a: [Integer,Float]}})
|
||||||
|
begin
|
||||||
|
ParamValidation.new({x: 5.6}, {x: {is_a: [Integer, Array]}})
|
||||||
|
rescue ParamValidation::ValidationError => e
|
||||||
|
e
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal 'x should be of the type(s): Integer, Array', e.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_can_be_date
|
||||||
|
ParamValidation.new({x: Date.new()}, {x: {can_be_date: true}})
|
||||||
|
ParamValidation.new({x: DateTime.new()}, {x: {can_be_date: true}})
|
||||||
|
ParamValidation.new({x: '2017-05-15T12:00:00.000Z'}, {x: {can_be_date: true}})
|
||||||
|
ParamValidation.new({x: '2017-05-15'}, {x: {can_be_date: true}})
|
||||||
|
|
||||||
|
begin
|
||||||
|
ParamValidation.new({x: 'not_a _date'}, {x: {can_be_date: true}})
|
||||||
|
rescue ParamValidation::ValidationError => e
|
||||||
|
e
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal 'x should be a datetime or be parsable as one', e.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_add_validator
|
||||||
|
ParamValidation.add_validator(:dollars){|val, arg, data| val =~ /^\d+(\.\d\d)?$/}
|
||||||
|
begin
|
||||||
|
ParamValidation.new({x: 'hi'}, {x: {dollars: true}})
|
||||||
|
rescue ParamValidation::ValidationError => e
|
||||||
|
e
|
||||||
|
end
|
||||||
|
assert_equal :dollars, e.data[:name]
|
||||||
|
end
|
||||||
|
def test_set_message
|
||||||
|
ParamValidation.add_validator(:dollars){|val, arg, data| val =~ /^\d+(\.\d\d)?$/}
|
||||||
|
ParamValidation.set_message(:dollars){|h| "#{h[:key]} must be a dollar amount"}
|
||||||
|
begin
|
||||||
|
ParamValidation.new({x: 'hi'}, {x: {dollars: true}})
|
||||||
|
rescue ParamValidation::ValidationError => e
|
||||||
|
e
|
||||||
|
end
|
||||||
|
assert_equal "x must be a dollar amount", e.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_custom_validator
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue