├── .gitignore ├── .travis.yml ├── Gemfile ├── LICENSE ├── README.rdoc ├── Rakefile ├── dm-validations.gemspec ├── lib ├── data_mapper │ ├── core.rb │ ├── support │ │ ├── assertions.rb │ │ ├── equalizer.rb │ │ └── ordered_set.rb │ ├── validation.rb │ └── validation │ │ ├── backward.rb │ │ ├── context.rb │ │ ├── contextual_rule_set.rb │ │ ├── exceptions.rb │ │ ├── inferred.rb │ │ ├── macros.rb │ │ ├── message_transformer.rb │ │ ├── model_extensions.rb │ │ ├── resource_extensions.rb │ │ ├── rule.rb │ │ ├── rule │ │ ├── absence.rb │ │ ├── acceptance.rb │ │ ├── block.rb │ │ ├── confirmation.rb │ │ ├── format.rb │ │ ├── format │ │ │ ├── proc.rb │ │ │ └── regexp.rb │ │ ├── formats │ │ │ ├── email.rb │ │ │ └── url.rb │ │ ├── length.rb │ │ ├── length │ │ │ ├── equal.rb │ │ │ ├── maximum.rb │ │ │ ├── minimum.rb │ │ │ └── range.rb │ │ ├── method.rb │ │ ├── numericalness.rb │ │ ├── numericalness │ │ │ ├── equal.rb │ │ │ ├── greater_than.rb │ │ │ ├── greater_than_or_equal.rb │ │ │ ├── integer.rb │ │ │ ├── less_than.rb │ │ │ ├── less_than_or_equal.rb │ │ │ ├── not_equal.rb │ │ │ └── numeric.rb │ │ ├── presence.rb │ │ ├── primitive_type.rb │ │ ├── uniqueness.rb │ │ ├── within.rb │ │ └── within │ │ │ ├── range.rb │ │ │ ├── range │ │ │ ├── bounded.rb │ │ │ ├── unbounded_begin.rb │ │ │ └── unbounded_end.rb │ │ │ └── set.rb │ │ ├── rule_set.rb │ │ ├── support │ │ ├── object.rb │ │ └── ordered_hash.rb │ │ ├── version.rb │ │ ├── violation.rb │ │ └── violation_set.rb └── dm-validations.rb ├── spec ├── data_mapper │ └── validation │ │ └── resource_extensions │ │ ├── save_spec.rb │ │ └── validate_spec.rb ├── fixtures │ ├── barcode.rb │ ├── basketball_court.rb │ ├── basketball_player.rb │ ├── beta_tester_account.rb │ ├── bill_of_landing.rb │ ├── boat_dock.rb │ ├── city.rb │ ├── company.rb │ ├── corporate_world.rb │ ├── country.rb │ ├── ethernet_frame.rb │ ├── event.rb │ ├── g3_concert.rb │ ├── integer_dumped_as_string_property.rb │ ├── jabberwock.rb │ ├── kayak.rb │ ├── lernean_hydra.rb │ ├── llama_spaceship.rb │ ├── mathematical_function.rb │ ├── memory_object.rb │ ├── mittelschnauzer.rb │ ├── motor_launch.rb │ ├── multibyte.rb │ ├── page.rb │ ├── phone_number.rb │ ├── pirogue.rb │ ├── programming_language.rb │ ├── reservation.rb │ ├── scm_operation.rb │ ├── sms_message.rb │ └── udp_packet.rb ├── integration │ ├── absent_field_validator │ │ ├── absent_field_validator_spec.rb │ │ └── spec_helper.rb │ ├── acceptance_validator │ │ ├── acceptance_validator_spec.rb │ │ └── spec_helper.rb │ ├── automatic_validation │ │ ├── custom_messages_for_inferred_validation_spec.rb │ │ ├── disabling_inferred_validation_spec.rb │ │ ├── inferred_boolean_properties_validation_spec.rb │ │ ├── inferred_float_property_validation_spec.rb │ │ ├── inferred_format_validation_spec.rb │ │ ├── inferred_integer_properties_validation_spec.rb │ │ ├── inferred_length_validation_spec.rb │ │ ├── inferred_presence_validation_spec.rb │ │ ├── inferred_primitive_validation_spec.rb │ │ ├── inferred_uniqueness_validation_spec.rb │ │ ├── inferred_within_validation_spec.rb │ │ └── spec_helper.rb │ ├── block_validator │ │ └── spec_helper.rb │ ├── conditional_validation │ │ ├── if_condition_spec.rb │ │ └── spec_helper.rb │ ├── confirmation_validator │ │ ├── confirmation_validator_spec.rb │ │ └── spec_helper.rb │ ├── datamapper_models │ │ ├── association_validation_spec.rb │ │ └── inheritance_spec.rb │ ├── dirty_attributes │ │ └── dirty_attributes_spec.rb │ ├── duplicated_validations │ │ ├── duplicated_validations_spec.rb │ │ └── spec_helper.rb │ ├── format_validator │ │ ├── email_format_validator_spec.rb │ │ ├── format_validator_spec.rb │ │ ├── regexp_validator_spec.rb │ │ ├── spec_helper.rb │ │ └── url_format_validator_spec.rb │ ├── length_validator │ │ ├── default_value_spec.rb │ │ ├── equality_spec.rb │ │ ├── error_message_spec.rb │ │ ├── maximum_spec.rb │ │ ├── minimum_spec.rb │ │ ├── range_spec.rb │ │ └── spec_helper.rb │ ├── method_validator │ │ ├── method_validator_spec.rb │ │ └── spec_helper.rb │ ├── numeric_validator │ │ ├── equality_with_float_type_spec.rb │ │ ├── equality_with_integer_type_spec.rb │ │ ├── float_type_spec.rb │ │ ├── gt_with_float_type_spec.rb │ │ ├── gte_with_float_type_spec.rb │ │ ├── integer_only_true_spec.rb │ │ ├── integer_type_spec.rb │ │ ├── lt_with_float_type_spec.rb │ │ ├── lte_with_float_type_spec.rb │ │ └── spec_helper.rb │ ├── primitive_validator │ │ ├── primitive_validator_spec.rb │ │ └── spec_helper.rb │ ├── pure_ruby_objects │ │ └── plain_old_ruby_object_validation_spec.rb │ ├── required_field_validator │ │ ├── association_spec.rb │ │ ├── boolean_type_value_spec.rb │ │ ├── date_type_value_spec.rb │ │ ├── datetime_type_value_spec.rb │ │ ├── float_type_value_spec.rb │ │ ├── integer_type_value_spec.rb │ │ ├── plain_old_ruby_object_spec.rb │ │ ├── shared_examples.rb │ │ ├── spec_helper.rb │ │ ├── string_type_value_spec.rb │ │ └── text_type_value_spec.rb │ ├── shared │ │ ├── default_validation_context.rb │ │ └── valid_and_invalid_model.rb │ ├── uniqueness_validator │ │ ├── spec_helper.rb │ │ └── uniqueness_validator_spec.rb │ └── within_validator │ │ ├── spec_helper.rb │ │ └── within_validator_spec.rb ├── public │ └── resource_spec.rb ├── spec_helper.rb └── unit │ ├── contextual_validators │ ├── emptiness_spec.rb │ ├── execution_spec.rb │ └── spec_helper.rb │ ├── generic_validator │ ├── equality_operator_spec.rb │ └── optional_spec.rb │ ├── validators │ └── within_validator_spec.rb │ └── violation_set │ ├── adding_spec.rb │ ├── emptiness_spec.rb │ ├── enumerable_spec.rb │ ├── reading_spec.rb │ └── respond_to_spec.rb └── tasks ├── spec.rake ├── yard.rake └── yardstick.rake /.gitignore: -------------------------------------------------------------------------------- 1 | ## MAC OS 2 | .DS_Store 3 | 4 | ## TEXTMATE 5 | *.tmproj 6 | tmtags 7 | 8 | ## EMACS 9 | *~ 10 | \#* 11 | .\#* 12 | 13 | ## VIM 14 | *.swp 15 | 16 | ## Rubinius 17 | *.rbc 18 | 19 | ## PROJECT::GENERAL 20 | *.gem 21 | coverage 22 | rdoc 23 | pkg 24 | tmp 25 | doc 26 | log 27 | .yardoc 28 | measurements 29 | 30 | ## BUNDLER 31 | .bundle 32 | Gemfile.* 33 | 34 | ## PROJECT::SPECIFIC 35 | spec/db/ 36 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | 3 | rvm: 4 | - 2.0 5 | - 2.1 6 | - 2.2 7 | - ruby-head 8 | - jruby-19mode 9 | - jruby-head 10 | - rbx-19mode 11 | 12 | env: 13 | global: 14 | - JRUBY_OPTS="$JRUBY_OPTS -J-Xmx1g --debug" 15 | matrix: 16 | - "ADAPTER=in_memory" 17 | - "ADAPTER=yaml" 18 | - "ADAPTER=sqlite" 19 | - "ADAPTER=mysql DM_DB_USER=root DM_DB_PASSWORD=''" 20 | - "ADAPTER=postgres DM_DB_USER=postgres DM_DB_PASSWORD=''" 21 | 22 | cache: bundler 23 | 24 | sudo: true 25 | 26 | services: 27 | - mysql 28 | - postgresql 29 | 30 | before_install: 31 | - travis_retry sudo apt-get update -qq 32 | - sudo apt-get install -qq postgresql-server-dev-all 33 | 34 | bundler_args: --without yard guard metrics benchmarks --retry 3 35 | 36 | before_script: 37 | - mysql -e "create database datamapper_alternate_tests;" 38 | - mysql -e "create database datamapper_default_tests;" 39 | - psql -c "create database datamapper_default_tests;" -U postgres 40 | - psql -c "create database datamapper_alternate_tests;" -U postgres 41 | 42 | script: "bundle exec rake spec" 43 | 44 | matrix: 45 | allow_failures: 46 | - rvm: ruby-head 47 | - rvm: jruby-19mode 48 | - rvm: jruby-head 49 | 50 | notifications: 51 | irc: "irc.freenode.org#datamapper" 52 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | 5 | DM_VERSION = '~> 1.3.0.beta' 6 | DO_VERSION = '~> 0.10.15' 7 | DM_DO_ADAPTERS = %w[sqlite postgres mysql oracle sqlserver] 8 | GIT_BRANCH = ENV.fetch('GIT_BRANCH', 'master') 9 | 10 | gem 'dm-core', DM_VERSION, github: 'datamapper/dm-core', branch: GIT_BRANCH 11 | 12 | group :datamapper do 13 | adapters = ENV['ADAPTER'] || ENV['ADAPTERS'] 14 | adapters = adapters.to_s.tr(',', ' ').split.uniq - %w[in_memory] 15 | 16 | if (do_adapters = DM_DO_ADAPTERS & adapters).any? 17 | do_options = {} 18 | do_options[:github] = 'datamapper/do' if ENV['DO_GIT'] == 'true' 19 | 20 | gem 'data_objects', DO_VERSION, do_options.dup 21 | 22 | do_adapters.each do |adapter| 23 | adapter = 'sqlite3' if adapter == 'sqlite' 24 | gem "do_#{adapter}", DO_VERSION, do_options.dup 25 | end 26 | 27 | gem 'dm-do-adapter', DM_VERSION, github: 'datamapper/dm-do-adapter', branch: GIT_BRANCH 28 | end 29 | 30 | adapters.each do |adapter| 31 | gem "dm-#{adapter}-adapter", DM_VERSION, github: "datamapper/dm-#{adapter}-adapter", branch: GIT_BRANCH 32 | end 33 | 34 | plugins = ENV['PLUGINS'] || ENV['PLUGIN'] 35 | plugins = plugins.to_s.tr(',', ' ').split.uniq << 'dm-types' << 'dm-migrations' 36 | 37 | plugins.each do |plugin| 38 | gem plugin, DM_VERSION, github: "datamapper/#{plugin}", branch: GIT_BRANCH 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2007 Guy van den Berg 2 | Copyright (c) 2011 DataMapper development team 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'rake' 3 | 4 | FileList['tasks/**/*.rake'].each { |task| import task } 5 | -------------------------------------------------------------------------------- /dm-validations.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | require File.expand_path('../lib/data_mapper/validation/version', __FILE__) 3 | 4 | Gem::Specification.new do |gem| 5 | gem.authors = [ 'Guy van den Berg', 'Emmanuel Gomez' ] 6 | gem.email = [ "emmanuel.gomez@gmail.com" ] 7 | gem.summary = "Library for performing validations on DataMapper resources and plain Ruby objects" 8 | gem.description = gem.summary 9 | gem.homepage = "http://datamapper.org" 10 | 11 | gem.files = `git ls-files`.split("\n") 12 | gem.test_files = `git ls-files -- {spec}/*`.split("\n") 13 | gem.extra_rdoc_files = %w[LICENSE README.rdoc] 14 | 15 | gem.name = "dm-validations" 16 | gem.require_paths = [ "lib" ] 17 | gem.version = DataMapper::Validation::VERSION 18 | 19 | gem.add_runtime_dependency('dm-core', '~> 1.3.0.beta') 20 | 21 | gem.add_development_dependency('rake', '~> 0.9.2') 22 | gem.add_development_dependency('rspec', '~> 1.3.2') 23 | end 24 | -------------------------------------------------------------------------------- /lib/data_mapper/core.rb: -------------------------------------------------------------------------------- 1 | require 'dm-core' 2 | -------------------------------------------------------------------------------- /lib/data_mapper/support/assertions.rb: -------------------------------------------------------------------------------- 1 | require 'dm-core/support/assertions' 2 | -------------------------------------------------------------------------------- /lib/data_mapper/support/equalizer.rb: -------------------------------------------------------------------------------- 1 | require 'dm-core/support/equalizer' 2 | -------------------------------------------------------------------------------- /lib/data_mapper/support/ordered_set.rb: -------------------------------------------------------------------------------- 1 | # temporary shim until I restructure dm-core 2 | require "dm-core/support/ordered_set" 3 | -------------------------------------------------------------------------------- /lib/data_mapper/validation.rb: -------------------------------------------------------------------------------- 1 | require 'data_mapper/validation/violation_set' 2 | require 'data_mapper/validation/contextual_rule_set' 3 | require 'data_mapper/validation/macros' 4 | 5 | module DataMapper 6 | module Validation 7 | 8 | def self.included(base) 9 | base.extend ClassMethods 10 | end 11 | 12 | # Check if a resource is valid in a given context 13 | # 14 | # @api public 15 | def valid?(context_name = default_validation_context) 16 | validate(context_name).errors.empty? 17 | end 18 | 19 | # Command a resource to populate its ViolationSet with any violations of 20 | # its validation Rules in +context_name+ 21 | # 22 | # @api public 23 | def validate(context_name = default_validation_context) 24 | errors.clear 25 | validation_violations(context_name).each { |v| errors.add(v) } 26 | 27 | self 28 | end 29 | 30 | # Get a list of violations for the receiver *without* mutating it 31 | # 32 | # @api private 33 | def validation_violations(context_name = default_validation_context) 34 | validation_rules.validate(self, context_name) 35 | end 36 | 37 | # @return [ViolationSet] 38 | # the collection of current validation errors for this resource 39 | # 40 | # @api public 41 | def errors 42 | @errors ||= ViolationSet.new(self) 43 | end 44 | 45 | # The default validation context for this Resource. 46 | # This Resource's default context can be overridden by implementing 47 | # #default_validation_context 48 | # 49 | # @return [Symbol] 50 | # the current validation context from the context stack 51 | # (if valid for this model), or :default 52 | # 53 | # @api public 54 | def default_validation_context 55 | validation_rules.current_context 56 | end 57 | 58 | # @api private 59 | def validation_rules 60 | self.class.validation_rules 61 | end 62 | 63 | # Retrieve the value of the given property name for the purpose of validation. 64 | # Default implementation is to send the attribute name arg to the receiver 65 | # and use the resulting value as the attribute value for validation 66 | # 67 | # @param [Symbol] attribute_name 68 | # the name of the attribute for which to retrieve 69 | # the attribute value for validation. 70 | # 71 | # @api public 72 | def validation_property_value(attribute_name) 73 | __send__(attribute_name) if respond_to?(attribute_name, true) 74 | end 75 | 76 | # Mark this resource as validatable. When we validate associations of a 77 | # resource we can check if they respond to validatable? before trying to 78 | # recursively validate them 79 | # 80 | # @api public 81 | def validatable? 82 | true 83 | end 84 | 85 | module ClassMethods 86 | 87 | include Validation::Macros 88 | 89 | # Return the ContextualRuleSet for this model 90 | # 91 | # @api public 92 | def validation_rules 93 | @validation_rules ||= ContextualRuleSet.new(self) 94 | end 95 | 96 | # @api private 97 | def inherited(base) 98 | super 99 | base.validation_rules.concat(validation_rules) 100 | end 101 | 102 | end # module ClassMethods 103 | 104 | end # module Validation 105 | end # module DataMapper 106 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/context.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | module DataMapper 4 | module Validation 5 | 6 | module Context 7 | # Module with validation context functionality. 8 | # 9 | # Contexts are implemented using a thread-local array-based stack. 10 | 11 | 12 | # Execute a block of code within a specific validation context 13 | # 14 | # @param [Symbol] context 15 | # the context to execute the block of code within 16 | # 17 | # @api semipublic 18 | def self.in_context(context) 19 | stack << context 20 | return_value = yield 21 | ensure 22 | stack.pop 23 | return_value 24 | end 25 | 26 | # Get the current validation context or nil (if no context is on the stack). 27 | # 28 | # @return [Symbol, NilClass] 29 | # The current validation context (for the current thread), 30 | # or nil if no current context is on the stack 31 | def self.current 32 | stack.last 33 | end 34 | 35 | # Are there any contexts on the stack? 36 | # 37 | # @return [Boolean] 38 | # true/false whether there are any contexts on the context stack 39 | # 40 | # @api semipublic 41 | def self.any?(&block) 42 | stack.any?(&block) 43 | end 44 | 45 | # The (thread-local) validation context stack 46 | # This allows object graphs to be saved within potentially nested contexts 47 | # without having to pass the validation context throughout 48 | # 49 | # @api private 50 | def self.stack 51 | Thread.current[:dm_validations_context_stack] ||= [] 52 | end 53 | 54 | end # module Context 55 | 56 | end # module Validation 57 | end # module DataMapper 58 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/exceptions.rb: -------------------------------------------------------------------------------- 1 | module DataMapper 2 | module Validation 3 | 4 | class InvalidContextError < StandardError; end 5 | 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/model_extensions.rb: -------------------------------------------------------------------------------- 1 | module DataMapper 2 | module Validation 3 | module ModelExtensions 4 | 5 | # @api public 6 | def create(attributes = {}, *args) 7 | resource = new(attributes) 8 | resource.save(*args) 9 | resource 10 | end 11 | 12 | end # module ModelExtensions 13 | end # module Validation 14 | 15 | Model.append_extensions Validation::ModelExtensions 16 | 17 | end # module DataMapper 18 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/absence.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | 9 | class Absence < Rule 10 | 11 | def initialize(attribute_name, options = {}) 12 | super 13 | 14 | @allow_nil = false 15 | @allow_blank = false 16 | end 17 | 18 | def valid?(resource) 19 | value = resource.validation_property_value(attribute_name) 20 | DataMapper::Ext.blank?(value) 21 | end 22 | 23 | def violation_type(resource) 24 | :absent 25 | end 26 | 27 | end # class Absence 28 | 29 | end # class Rule 30 | end # module Validation 31 | end # module DataMapper 32 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/acceptance.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | 9 | # TODO: update this to inherit from Rule::Within::Set 10 | class Acceptance < Rule 11 | 12 | EQUALIZE_ON = superclass::EQUALIZE_ON.dup << :accept 13 | 14 | equalize *EQUALIZE_ON 15 | 16 | DEFAULT_ACCEPTED_VALUES = [ '1', 1, 'true', true, 't' ] 17 | 18 | attr_reader :accept 19 | 20 | def initialize(attribute_name, options = {}) 21 | super 22 | 23 | @accept = Array(options.fetch(:accept, DEFAULT_ACCEPTED_VALUES)) 24 | 25 | allow_nil! unless defined?(@allow_nil) 26 | end 27 | 28 | def valid?(resource) 29 | value = resource.validation_property_value(attribute_name) 30 | return true if exempt_value?(value) 31 | accept.include?(value) 32 | end 33 | 34 | def violation_type(resource) 35 | :accepted 36 | end 37 | 38 | private 39 | 40 | # TODO: isn't this superfluous considering Rule#optional? 41 | def exempt_value?(value) 42 | allow_nil? && value.nil? 43 | end 44 | 45 | end # class Acceptance 46 | 47 | end # class Rule 48 | end # module Validation 49 | end # module DataMapper 50 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/block.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | 9 | class Block < Rule 10 | 11 | attr_reader :block 12 | 13 | def initialize(attribute_name, options, &block) 14 | unless block_given? 15 | raise ArgumentError, 'cannot initialize a Block validator without a block' 16 | end 17 | 18 | super 19 | 20 | @block = block 21 | end 22 | 23 | def validate(resource) 24 | result, error_message = resource.instance_eval(&self.block) 25 | 26 | if result 27 | nil 28 | else 29 | Violation.new(resource, error_message, self) 30 | end 31 | end 32 | 33 | end # class Block 34 | 35 | end # class Rule 36 | end # module Validation 37 | end # module DataMapper 38 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/confirmation.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | 9 | class Confirmation < Rule 10 | 11 | EQUALIZE_ON = superclass::EQUALIZE_ON.dup << :confirmation_attribute 12 | 13 | attr_reader :confirmation_attribute 14 | 15 | 16 | def initialize(attribute_name, options = {}) 17 | super 18 | 19 | @confirm_attribute_name = options.fetch(:confirm) do 20 | :"#{attribute_name}_confirmation" 21 | end 22 | 23 | allow_nil! unless defined?(@allow_nil) 24 | allow_blank! unless defined?(@allow_blank) 25 | end 26 | 27 | def valid?(resource) 28 | value = resource.validation_property_value(attribute_name) 29 | return true if optional?(value) 30 | 31 | if resource.model.properties.named?(attribute_name) 32 | return true unless resource.attribute_dirty?(attribute_name) 33 | end 34 | 35 | confirm_value = resource.instance_variable_get("@#{@confirm_attribute_name}") 36 | value == confirm_value 37 | end 38 | 39 | def violation_type(resource) 40 | :confirmation 41 | end 42 | 43 | end # class Confirmation 44 | 45 | end # class Rule 46 | end # module Validation 47 | end # module DataMapper 48 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/format.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule' 4 | 5 | require 'data_mapper/validation/rule/formats/email' 6 | require 'data_mapper/validation/rule/formats/url' 7 | 8 | module DataMapper 9 | module Validation 10 | class UnknownValidationFormat < ::ArgumentError; end 11 | 12 | class Rule 13 | 14 | module Format 15 | 16 | FORMATS = { 17 | :email_address => Formats::EmailAddress, 18 | :url => Formats::Url 19 | } 20 | # TODO: evaluate re-implementing custom error messages per format type 21 | # previously these strings were wrapped in lambdas, which were, at one 22 | # point, invoked with #try_call with the humanized attribute name and value 23 | FORMAT_MESSAGES = { 24 | :email_address => '%s is not a valid email address', 25 | :url => '%s is not a valid URL', 26 | } 27 | 28 | 29 | def self.rules_for(attribute_name, options) 30 | Array(new(attribute_name, options)) 31 | end 32 | 33 | # @raise [UnknownValidationFormat] 34 | # if the :as (or :with) option is a Symbol that is not a key in FORMATS, 35 | # or if the provided format is not a Regexp, Symbol or Proc 36 | def self.new(attribute_name, options) 37 | format = options.delete(:as) || options.delete(:with) 38 | 39 | case format 40 | when Symbol 41 | regexp = FORMATS.fetch(format) do 42 | raise UnknownValidationFormat, "No such predefined format '#{format}'" 43 | end 44 | self::Regexp.new(attribute_name, options.merge(:format => regexp, :format_name => format)) 45 | when ::Regexp 46 | self::Regexp.new(attribute_name, options.merge(:format => format)) 47 | when ::Proc 48 | self::Proc.new(attribute_name, options.merge(:format => format)) 49 | else 50 | raise UnknownValidationFormat, "Expected a Regexp, Symbol, or Proc format. Got: #{format.inspect}" 51 | end 52 | end 53 | 54 | 55 | attr_reader :format 56 | 57 | def initialize(attribute_name, options) 58 | super 59 | 60 | @format = options.fetch(:format) 61 | 62 | allow_nil! unless defined?(@allow_nil) 63 | allow_blank! unless defined?(@allow_blank) 64 | end 65 | 66 | def violation_type(resource) 67 | :invalid 68 | end 69 | 70 | # TODO: integrate format into error message key? 71 | # def error_message_args 72 | # if format.is_a?(Symbol) 73 | # [ :"invalid_#{format}", attribute_name ] 74 | # else 75 | # [ :invalid, attribute_name ] 76 | # end 77 | # end 78 | 79 | end # class Format 80 | 81 | end # class Rule 82 | end # module Validation 83 | end # module DataMapper 84 | 85 | require 'data_mapper/validation/rule/format/proc' 86 | require 'data_mapper/validation/rule/format/regexp' 87 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/format/proc.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule/format' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | module Format 9 | 10 | class Proc < Rule 11 | 12 | include Format 13 | 14 | EQUALIZE_ON = superclass::EQUALIZE_ON.dup << :format 15 | 16 | equalize *EQUALIZE_ON 17 | 18 | 19 | def valid?(resource) 20 | value = resource.validation_property_value(attribute_name) 21 | return true if optional?(value) 22 | 23 | self.format.call(value) 24 | # rescue ::Encoding::CompatibilityError 25 | # # This is to work around a bug in jruby - see formats/email.rb 26 | # false 27 | end 28 | 29 | end # class Proc 30 | 31 | end # module Format 32 | end # class Rule 33 | end # module Validation 34 | end # module DataMapper 35 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/format/regexp.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule/format' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | module Format 9 | 10 | class Regexp < Rule 11 | 12 | include Format 13 | 14 | EQUALIZE_ON = superclass::EQUALIZE_ON.dup << :format << :format_name 15 | 16 | equalize *EQUALIZE_ON 17 | 18 | 19 | attr_reader :format_name 20 | 21 | def initialize(attribute_name, options = {}) 22 | super 23 | 24 | @format_name = options.fetch(:format_name, nil) 25 | end 26 | 27 | def valid?(resource) 28 | value = resource.validation_property_value(attribute_name) 29 | return true if optional?(value) 30 | 31 | value ? value.to_s =~ self.format : false 32 | rescue ::Encoding::CompatibilityError 33 | # This is to work around a bug in jruby - see formats/email.rb 34 | false 35 | end 36 | 37 | # TODO: integrate format into error message key? 38 | # def error_message_args 39 | # if format_name.is_a?(Symbol) 40 | # [ :"invalid_#{format_name}", attribute_name ] 41 | # else 42 | # [ :invalid, attribute_name ] 43 | # end 44 | # end 45 | 46 | end # class Regexp 47 | 48 | end # module Format 49 | end # class Rule 50 | end # module Validation 51 | end # module DataMapper 52 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/formats/email.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | 3 | module DataMapper 4 | module Validation 5 | class Rule 6 | module Formats 7 | 8 | # Almost RFC2822 (No attribution reference available). 9 | # 10 | # This differs in that it does not allow local domains (test@localhost). 11 | # 99% of the time you do not want to allow these email addresses 12 | # in a public web application. 13 | EmailAddress = begin 14 | if (RUBY_VERSION == '1.9.2' && RUBY_ENGINE == 'jruby' && JRUBY_VERSION <= '1.6.3') || RUBY_VERSION == '1.9.3' 15 | # There is an obscure bug in jruby 1.6 that prevents matching 16 | # on unicode properties here. Remove this logic branch once 17 | # a stable jruby release fixes this. 18 | # 19 | # http://jira.codehaus.org/browse/JRUBY-5622 20 | # 21 | # There is a similar bug in preview releases of 1.9.3 22 | # 23 | # http://redmine.ruby-lang.org/issues/5126 24 | letter = 'a-zA-Z' 25 | else 26 | letter = 'a-zA-Z\p{L}' # Changed from RFC2822 to include unicode chars 27 | end 28 | digit = '0-9' 29 | atext = "[#{letter}#{digit}\!\#\$\%\&\'\*+\/\=\?\^\_\`\{\|\}\~\-]" 30 | dot_atom_text = "#{atext}+([.]#{atext}*)+" 31 | dot_atom = dot_atom_text 32 | no_ws_ctl = '\x01-\x08\x11\x12\x14-\x1f\x7f' 33 | qtext = "[^#{no_ws_ctl}\\x0d\\x22\\x5c]" # Non-whitespace, non-control character except for \ and " 34 | text = '[\x01-\x09\x11\x12\x14-\x7f]' 35 | quoted_pair = "(\\x5c#{text})" 36 | qcontent = "(?:#{qtext}|#{quoted_pair})" 37 | quoted_string = "[\"]#{qcontent}+[\"]" 38 | atom = "#{atext}+" 39 | word = "(?:#{atom}|#{quoted_string})" 40 | obs_local_part = "#{word}([.]#{word})*" 41 | local_part = "(?:#{dot_atom}|#{quoted_string}|#{obs_local_part})" 42 | dtext = "[#{no_ws_ctl}\\x21-\\x5a\\x5e-\\x7e]" 43 | dcontent = "(?:#{dtext}|#{quoted_pair})" 44 | domain_literal = "\\[#{dcontent}+\\]" 45 | obs_domain = "#{atom}([.]#{atom})+" 46 | domain = "(?:#{dot_atom}|#{domain_literal}|#{obs_domain})" 47 | addr_spec = "#{local_part}\@#{domain}" 48 | pattern = /\A#{addr_spec}\z/u 49 | end 50 | 51 | end # module Formats 52 | end # class Rule 53 | end # module Validation 54 | end # module DataMapper 55 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/formats/url.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | module DataMapper 4 | module Validation 5 | class Rule 6 | module Formats 7 | 8 | Url = %r{\Ahttps?://[a-z\d](?:[-.]?[a-z\d])*\.[a-z]{2,6}(?::\d{1,5})?/?.*\z}ix.freeze 9 | 10 | end # module Formats 11 | end # class Rule 12 | end # module Validation 13 | end # module DataMapper 14 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/length.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | 9 | module Length 10 | 11 | attr_reader :expected 12 | 13 | # TODO: DRY this up (also implemented in Rule) 14 | def self.rules_for(attribute_name, options) 15 | Array(new(attribute_name, options)) 16 | end 17 | 18 | # TODO: move options normalization into the validator macros 19 | def self.new(attribute_name, options) 20 | options = options.dup 21 | 22 | equal = options.delete(:is) || options.delete(:equals) 23 | range = options.delete(:within) || options.delete(:in) 24 | minimum = options.delete(:minimum) || options.delete(:min) 25 | maximum = options.delete(:maximum) || options.delete(:max) 26 | 27 | if minimum && maximum 28 | range ||= minimum..maximum 29 | end 30 | 31 | if equal 32 | Length::Equal.new(attribute_name, options.merge(:equal => equal)) 33 | elsif range 34 | Length::Range.new(attribute_name, options.merge(:range => range)) 35 | elsif minimum 36 | Length::Minimum.new(attribute_name, options.merge(:minimum => minimum)) 37 | elsif maximum 38 | Length::Maximum.new(attribute_name, options.merge(:maximum => maximum)) 39 | else 40 | # raise ArgumentError, "expected one of :is, :equals, :within, :in, :minimum, :min, :maximum, or :max; got #{options.keys.inspect}" 41 | warn "expected length specification: one of :is, :equals, :within, :in, :minimum, :min, :maximum, or :max; got #{options.keys.inspect}" 42 | Length::Dummy.new(attribute_name, options) 43 | end 44 | end 45 | 46 | class Dummy < Rule 47 | include Length 48 | end 49 | 50 | def valid?(resource) 51 | value = resource.validation_property_value(attribute_name) 52 | 53 | if optional?(value) 54 | true 55 | else 56 | length = value_length(value.to_s) 57 | valid_length?(length) 58 | end 59 | end 60 | 61 | private 62 | 63 | def valid_length?(length) 64 | raise NotImplementedError, "#{self.class}#valid_length? must be implemented" 65 | end 66 | 67 | # Return the length in characters 68 | # 69 | # @param [#to_str] value 70 | # the string to get the number of characters for 71 | # 72 | # @return [Integer] 73 | # the number of characters in the string 74 | # 75 | # @api private 76 | def value_length(value) 77 | value.to_str.length 78 | end 79 | 80 | if RUBY_VERSION < '1.9' 81 | def value_length(value) 82 | value.to_str.scan(/./u).size 83 | end 84 | end 85 | 86 | end # module Length 87 | 88 | end # class Rule 89 | end # module Validation 90 | end # module DataMapper 91 | 92 | # meh, I don't like doing this, but the superclass must be loaded before subclasses 93 | require 'data_mapper/validation/rule/length/equal' 94 | require 'data_mapper/validation/rule/length/range' 95 | require 'data_mapper/validation/rule/length/minimum' 96 | require 'data_mapper/validation/rule/length/maximum' 97 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/length/equal.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule/length' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | module Length 9 | 10 | class Equal < Rule 11 | 12 | include Length 13 | 14 | def initialize(attribute_name, options) 15 | super 16 | 17 | @expected = options.fetch(:equal) 18 | end 19 | 20 | def violation_type(resource) 21 | :wrong_length 22 | end 23 | 24 | def violation_data(resource) 25 | [ [ :expected, expected ] ] 26 | end 27 | 28 | private 29 | 30 | # Validate the value length is equal to the expected length 31 | # 32 | # @param [Integer] length 33 | # the value length 34 | # 35 | # @return [String, nil] 36 | # the error message if invalid, nil if not 37 | # 38 | # @api private 39 | def valid_length?(length) 40 | expected == length 41 | end 42 | 43 | end # class Equal 44 | 45 | end # module Length 46 | end # class Rule 47 | end # module Validation 48 | end # module DataMapper 49 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/length/maximum.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule/length' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | module Length 9 | 10 | class Maximum < Rule 11 | 12 | include Length 13 | 14 | attr_reader :expected 15 | 16 | def initialize(attribute_name, options) 17 | super 18 | 19 | @expected = options.fetch(:maximum) 20 | end 21 | 22 | def violation_type(resource) 23 | :too_long 24 | end 25 | 26 | def violation_data(resource) 27 | [ [ :maximum, expected ] ] 28 | end 29 | 30 | private 31 | 32 | # Validate the maximum expected value length 33 | # 34 | # @param [Integer] length 35 | # the value length 36 | # 37 | # @return [String, NilClass] 38 | # the error message if invalid, nil if valid 39 | # 40 | # @api private 41 | def valid_length?(length) 42 | expected >= length 43 | end 44 | 45 | end # class Maximum 46 | 47 | end # module Length 48 | end # class Rule 49 | end # module Validation 50 | end # module DataMapper 51 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/length/minimum.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule/length' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | module Length 9 | 10 | class Minimum < Rule 11 | 12 | include Length 13 | 14 | attr_reader :expected 15 | 16 | def initialize(attribute_name, options) 17 | super 18 | 19 | @expected = options.fetch(:minimum) 20 | end 21 | 22 | def violation_type(resource) 23 | :too_short 24 | end 25 | 26 | def violation_data(resource) 27 | [ [ :minimum, expected ] ] 28 | end 29 | 30 | private 31 | 32 | # Validate the minimum expected value length 33 | # 34 | # @param [Integer] length 35 | # the value length 36 | # 37 | # @return [String, NilClass] 38 | # the error message if invalid, nil if valid 39 | # 40 | # @api private 41 | def valid_length?(length) 42 | expected <= length 43 | end 44 | 45 | end # class Minimum 46 | 47 | end # module Length 48 | end # class Rule 49 | end # module Validation 50 | end # module DataMapper 51 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/length/range.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule/length' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | module Length 9 | 10 | class Range < Rule 11 | 12 | include Length 13 | 14 | attr_reader :expected 15 | 16 | def initialize(attribute_name, options) 17 | super 18 | 19 | @expected = options.fetch(:range) 20 | end 21 | 22 | def violation_type(resource) 23 | :length_between 24 | end 25 | 26 | def violation_data(resource) 27 | [ [ :min, expected.begin ], [ :max, expected.end ] ] 28 | end 29 | 30 | private 31 | 32 | # Validate the value length is within expected range 33 | # 34 | # @param [Integer] length 35 | # the value length 36 | # 37 | # @return [String, NilClass] 38 | # the error message if invalid, nil if valid 39 | # 40 | # @api private 41 | def valid_length?(length) 42 | expected.include?(length) 43 | end 44 | 45 | end # class Range 46 | 47 | end # module Length 48 | end # class Rule 49 | end # module Validation 50 | end # module DataMapper 51 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/method.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | 9 | class Method < Rule 10 | 11 | EQUALIZE_ON = superclass::EQUALIZE_ON.dup << :method 12 | 13 | equalize *EQUALIZE_ON 14 | 15 | attr_reader :method 16 | 17 | def initialize(attribute_name, options={}) 18 | super 19 | 20 | @method = options.fetch(:method, attribute_name) 21 | @violation_type = options.fetch(:violation_type, :unsatisfied_condition) 22 | end 23 | 24 | def validate(resource) 25 | result, error_message = resource.__send__(method) 26 | 27 | if result 28 | nil 29 | else 30 | Violation.new(resource, error_message, self) 31 | end 32 | end 33 | 34 | def violation_type(resource) 35 | @violation_type 36 | end 37 | 38 | end # class Method 39 | 40 | end # class Rule 41 | end # module Validation 42 | end # module DataMapper 43 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/numericalness.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | 9 | module Numericalness 10 | 11 | def self.included(validator) 12 | validator.class_eval do 13 | const_set(:EQUALIZE_ON, superclass::EQUALIZE_ON.dup << :expected) 14 | 15 | equalize *self::EQUALIZE_ON 16 | end 17 | end 18 | 19 | # TODO: move options normalization into the validator macros? 20 | def self.rules_for(attribute_name, options) 21 | options = options.dup 22 | 23 | int = scour_options_of_keys(options, [:only_integer, :integer_only]) 24 | 25 | gt = scour_options_of_keys(options, [:gt, :greater_than]) 26 | lt = scour_options_of_keys(options, [:lt, :less_than]) 27 | gte = scour_options_of_keys(options, [:gte, :greater_than_or_equal_to]) 28 | lte = scour_options_of_keys(options, [:lte, :less_than_or_equal_to]) 29 | eq = scour_options_of_keys(options, [:eq, :equal, :equals, :exactly, :equal_to]) 30 | ne = scour_options_of_keys(options, [:ne, :not_equal_to]) 31 | 32 | rules = [] 33 | rules << Integer.new(attribute_name, options) if int 34 | rules << Numeric.new(attribute_name, options) if !int 35 | rules << GreaterThan.new(attribute_name, options.merge(:expected => gt)) if gt 36 | rules << LessThan.new(attribute_name, options.merge(:expected => lt)) if lt 37 | rules << GreaterThanOrEqual.new(attribute_name, options.merge(:expected => gte)) if gte 38 | rules << LessThanOrEqual.new(attribute_name, options.merge(:expected => lte)) if lte 39 | rules << Equal.new(attribute_name, options.merge(:expected => eq)) if eq 40 | rules << NotEqual.new(attribute_name, options.merge(:expected => ne)) if ne 41 | rules 42 | end 43 | 44 | def self.scour_options_of_keys(options, keys) 45 | keys.map { |key| options.delete(key) }.compact.first 46 | end 47 | 48 | attr_reader :expected 49 | 50 | def initialize(attribute_name, options) 51 | super 52 | 53 | @expected = options[:expected] 54 | end 55 | 56 | def valid?(resource) 57 | # TODO: is it even possible for expected to be nil? 58 | # if so, return a dummy validator when expected is nil 59 | return true if expected.nil? 60 | 61 | value = resource.validation_property_value(attribute_name) 62 | 63 | optional?(value) || valid_numericalness?(value) 64 | end 65 | 66 | private 67 | 68 | def value_as_string(value) 69 | case value 70 | # Avoid Scientific Notation in Float to_s 71 | when Float then value.to_d.to_s('F') 72 | when BigDecimal then value.to_s('F') 73 | else value.to_s 74 | end 75 | end 76 | 77 | end # class Numericalness 78 | 79 | end # class Rule 80 | end # module Validation 81 | end # module DataMapper 82 | 83 | require 'data_mapper/validation/rule/numericalness/integer' 84 | require 'data_mapper/validation/rule/numericalness/numeric' 85 | 86 | require 'data_mapper/validation/rule/numericalness/equal' 87 | require 'data_mapper/validation/rule/numericalness/greater_than' 88 | require 'data_mapper/validation/rule/numericalness/greater_than_or_equal' 89 | require 'data_mapper/validation/rule/numericalness/less_than' 90 | require 'data_mapper/validation/rule/numericalness/less_than_or_equal' 91 | require 'data_mapper/validation/rule/numericalness/not_equal' 92 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/numericalness/equal.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule/numericalness' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | module Numericalness 9 | 10 | class Equal < Rule 11 | 12 | include Numericalness 13 | 14 | def valid_numericalness?(value) 15 | value == expected 16 | rescue ArgumentError 17 | # TODO: figure out better solution for: can't compare String with Integer 18 | true 19 | end 20 | 21 | def violation_type(resource) 22 | :equal_to 23 | end 24 | 25 | def violation_data(resource) 26 | [ [ :expected, expected ] ] 27 | end 28 | 29 | end # class Equal 30 | 31 | end # module Numericalness 32 | end # class Rule 33 | end # module Validation 34 | end # module DataMapper 35 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/numericalness/greater_than.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule/numericalness' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | module Numericalness 9 | 10 | class GreaterThan < Rule 11 | 12 | include Numericalness 13 | 14 | def valid_numericalness?(value) 15 | value > expected 16 | rescue ArgumentError 17 | # TODO: figure out better solution for: can't compare String with Integer 18 | true 19 | end 20 | 21 | def violation_type(resource) 22 | :greater_than 23 | end 24 | 25 | def violation_data(resource) 26 | [ [ :minimum, expected ] ] 27 | end 28 | 29 | end # class GreaterThan 30 | 31 | end # module Numericalness 32 | end # class Rule 33 | end # module Validation 34 | end # module DataMapper 35 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/numericalness/greater_than_or_equal.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule/numericalness' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | module Numericalness 9 | 10 | class GreaterThanOrEqual < Rule 11 | 12 | include Numericalness 13 | 14 | def valid_numericalness?(value) 15 | value >= expected 16 | rescue ArgumentError 17 | # TODO: figure out better solution for: can't compare String with Integer 18 | true 19 | end 20 | 21 | def violation_type(resource) 22 | :greater_than_or_equal_to 23 | end 24 | 25 | def violation_data(resource) 26 | [ [ :minimum, expected ] ] 27 | end 28 | 29 | end # class GreaterThanOrEqual 30 | 31 | end # module Numericalness 32 | end # class Rule 33 | end # module Validation 34 | end # module DataMapper 35 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/numericalness/integer.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule/numericalness' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | module Numericalness 9 | 10 | class Integer < Rule 11 | 12 | include Numericalness 13 | 14 | def expected 15 | /\A[+-]?\d+\z/ 16 | end 17 | 18 | def valid_numericalness?(value) 19 | # XXX: workaround for jruby. This is needed because the jruby 20 | # compiler optimizes a bit too far with magic variables like $~. 21 | # the value.send line sends $~. Inserting this line makes sure the 22 | # jruby compiler does not optimise here. 23 | # see http://jira.codehaus.org/browse/JRUBY-3765 24 | $~ = nil if RUBY_PLATFORM[/java/] 25 | 26 | value_as_string(value) =~ expected 27 | rescue ArgumentError 28 | # TODO: figure out better solution for: can't compare String with Integer 29 | true 30 | end 31 | 32 | def violation_type(resource) 33 | :not_an_integer 34 | end 35 | 36 | end # class Equal 37 | 38 | end # module Numericalness 39 | end # class Rule 40 | end # module Validation 41 | end # module DataMapper 42 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/numericalness/less_than.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule/numericalness' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | module Numericalness 9 | 10 | class LessThan < Rule 11 | 12 | include Numericalness 13 | 14 | def valid_numericalness?(value) 15 | value < expected 16 | rescue ArgumentError 17 | # TODO: figure out better solution for: can't compare String with Integer 18 | true 19 | end 20 | 21 | def violation_type(resource) 22 | :less_than 23 | end 24 | 25 | def violation_data(resource) 26 | [ [ :maximum, expected ] ] 27 | end 28 | 29 | end # class LessThan 30 | 31 | end # module Numericalness 32 | end # class Rule 33 | end # module Validation 34 | end # module DataMapper 35 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/numericalness/less_than_or_equal.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule/numericalness' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | module Numericalness 9 | 10 | class LessThanOrEqual < Rule 11 | 12 | include Numericalness 13 | 14 | def valid_numericalness?(value) 15 | value <= expected 16 | rescue ArgumentError 17 | # TODO: figure out better solution for: can't compare String with Integer 18 | true 19 | end 20 | 21 | def violation_type(resource) 22 | :less_than_or_equal_to 23 | end 24 | 25 | def violation_data(resource) 26 | [ [ :maximum, expected ] ] 27 | end 28 | 29 | end # class LessThanOrEqual 30 | 31 | end # module Numericalness 32 | end # class Rule 33 | end # module Validation 34 | end # module DataMapper 35 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/numericalness/not_equal.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule/numericalness' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | module Numericalness 9 | 10 | class NotEqual < Rule 11 | 12 | include Numericalness 13 | 14 | def valid_numericalness?(value) 15 | value != expected 16 | rescue ArgumentError 17 | # TODO: figure out better solution for: can't compare String with Integer 18 | true 19 | end 20 | 21 | def violation_type(resource) 22 | :not_equal_to 23 | end 24 | 25 | def violation_data(resource) 26 | [ [ :not_expected, expected ] ] 27 | end 28 | 29 | end # class NotEqual 30 | 31 | end # module Numericalness 32 | end # class Rule 33 | end # module Validation 34 | end # module DataMapper 35 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/numericalness/numeric.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule/numericalness' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | module Numericalness 9 | 10 | class Numeric < Rule 11 | 12 | include Numericalness 13 | 14 | attr_reader :precision 15 | attr_reader :scale 16 | 17 | def initialize(attribute_name, options) 18 | super 19 | 20 | @precision = options.fetch(:precision, nil) 21 | @scale = options.fetch(:scale, nil) 22 | 23 | unless expected # validate precision and scale attrs 24 | raise ArgumentError, "Invalid precision #{precision.inspect} and scale #{scale.inspect} for #{attribute_name}" 25 | end 26 | end 27 | 28 | def expected(precision = @precision, scale = @scale) 29 | if precision && scale 30 | if precision > scale && scale == 0 31 | /\A[+-]?(?:\d{1,#{precision}}(?:\.0)?)\z/ 32 | elsif precision > scale 33 | delta = precision - scale 34 | /\A[+-]?(?:\d{1,#{delta}}|\d{0,#{delta}}\.\d{1,#{scale}})\z/ 35 | elsif precision == scale 36 | /\A[+-]?(?:0(?:\.\d{1,#{scale}})?)\z/ 37 | else 38 | nil 39 | end 40 | else 41 | /\A[+-]?(?:\d+|\d*\.\d+)\z/ 42 | end 43 | end 44 | 45 | def valid_numericalness?(value) 46 | # XXX: workaround for jruby. This is needed because the jruby 47 | # compiler optimizes a bit too far with magic variables like $~. 48 | # the value.send line sends $~. Inserting this line makes sure the 49 | # jruby compiler does not optimise here. 50 | # see http://jira.codehaus.org/browse/JRUBY-3765 51 | $~ = nil if RUBY_PLATFORM[/java/] 52 | 53 | value_as_string(value) =~ expected 54 | rescue ArgumentError 55 | # TODO: figure out better solution for: can't compare String with Integer 56 | true 57 | end 58 | 59 | def violation_type(resource) 60 | :not_a_number 61 | end 62 | 63 | end # class Numeric 64 | 65 | end # module Numericalness 66 | end # class Rule 67 | end # module Validation 68 | end # module DataMapper 69 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/presence.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | 9 | class Presence < Rule 10 | 11 | def initialize(attribute_name, options = {}) 12 | super 13 | 14 | @allow_nil = false 15 | @allow_blank = false 16 | end 17 | 18 | # Boolean property types are considered present if non-nil. 19 | # Other property types are considered present if non-blank. 20 | # Non-properties are considered present if non-blank. 21 | def valid?(resource) 22 | value = resource.validation_property_value(attribute_name) 23 | 24 | boolean_type?(resource) ? !value.nil? : !DataMapper::Ext.blank?(value) 25 | end 26 | 27 | def violation_type(resource) 28 | boolean_type?(resource) ? :nil : :blank 29 | end 30 | 31 | # Is the property a boolean property? 32 | # 33 | # @return [Boolean] 34 | # Returns true for Boolean, ParanoidBoolean, TrueClass and other 35 | # properties. Returns false for other property types or for 36 | # non-properties. 37 | # 38 | # @api private 39 | # 40 | # TODO: break this into concrete types and move the property check 41 | # into #initialize. Will require adding model to signature of #initialize 42 | def boolean_type?(resource) 43 | property = get_resource_property(resource, attribute_name) 44 | 45 | property ? property.load_as == TrueClass : false 46 | end 47 | 48 | end # class Presence 49 | 50 | end # class Rule 51 | end # module Validation 52 | end # module DataMapper 53 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/primitive_type.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | 9 | class PrimitiveType < Rule 10 | 11 | def valid?(resource) 12 | property = get_resource_property(resource, attribute_name) 13 | value = resource.validation_property_value(attribute_name) 14 | 15 | value.nil? || property.value_loaded?(value) 16 | end 17 | 18 | def violation_type(resource) 19 | :primitive 20 | end 21 | 22 | def violation_data(resource) 23 | property = get_resource_property(resource, attribute_name) 24 | 25 | [ [ :primitive, property.load_as ] ] 26 | end 27 | 28 | end # class PrimitiveType 29 | 30 | end # class Rule 31 | end # module Validation 32 | end # module DataMapper 33 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/uniqueness.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/support/assertions' 4 | require 'data_mapper/validation/rule' 5 | 6 | module DataMapper 7 | module Validation 8 | class Rule 9 | class Uniqueness < Rule 10 | 11 | include DataMapper::Assertions 12 | 13 | EQUALIZE_ON = superclass::EQUALIZE_ON.dup << :scope 14 | 15 | equalize *EQUALIZE_ON 16 | 17 | attr_reader :scope 18 | 19 | def initialize(attribute_name, options = {}) 20 | if options.include?(:scope) 21 | assert_kind_of('scope', options[:scope], Array, Symbol) 22 | end 23 | 24 | super 25 | 26 | @scope = Array(options.fetch(:scope, nil)) 27 | 28 | allow_nil! unless defined?(@allow_nil) 29 | allow_blank! unless defined?(@allow_blank) 30 | end 31 | 32 | def valid?(resource) 33 | value = resource.validation_property_value(attribute_name) 34 | return true if optional?(value) 35 | 36 | opts = { 37 | :fields => resource.model.key(resource.repository.name), 38 | attribute_name => value, 39 | } 40 | 41 | scope.each { |subject| 42 | unless resource.respond_to?(subject) 43 | raise(ArgumentError,"Could not find property to scope by: #{subject}. Note that :unique does not currently support arbitrarily named groups, for that you should use :unique_index with an explicit validates_uniqueness_of.") 44 | end 45 | 46 | opts[subject] = resource.__send__(subject) 47 | } 48 | 49 | other_resource = DataMapper.repository(resource.repository.name) do 50 | resource.model.first(opts) 51 | end 52 | 53 | return true if other_resource.nil? 54 | resource.saved? && other_resource.key == resource.key 55 | end 56 | 57 | def violation_type(resource) 58 | :taken 59 | end 60 | 61 | end # class Uniqueness 62 | end # class Rule 63 | end # module Validation 64 | end # module DataMapper 65 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/within.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | 9 | module Within 10 | 11 | # TODO: DRY this up (also implemented in Rule) 12 | def self.rules_for(attribute_name, options) 13 | Array(new(attribute_name, options)) 14 | end 15 | 16 | # TODO: move options normalization into the validator macros 17 | def self.new(attribute_name, options) 18 | if options.fetch(:set).is_a?(::Range) 19 | Within::Range.new(attribute_name, options) 20 | else 21 | Within::Set.new(attribute_name, options) 22 | end 23 | end 24 | 25 | end # module Within 26 | 27 | end # class Rule 28 | end # module Validation 29 | end # module DataMapper 30 | 31 | require 'data_mapper/validation/rule/within/range' 32 | require 'data_mapper/validation/rule/within/set' 33 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/within/range.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule/within' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | module Within 9 | 10 | module Range 11 | 12 | include Within 13 | 14 | attr_reader :range 15 | 16 | def self.rules_for(attribute_name, options) 17 | Array(new(attribute_name, options)) 18 | end 19 | 20 | def self.new(attribute_name, options) 21 | super if Within::Range != self 22 | 23 | range = options.fetch(:range) { options.fetch(:set) } 24 | 25 | if range.first != -Infinity && range.last != Infinity 26 | Bounded.new(attribute_name, options) 27 | elsif range.first == -Infinity 28 | UnboundedBegin.new(attribute_name, options) 29 | elsif range.last == Infinity 30 | UnboundedEnd.new(attribute_name, options) 31 | end 32 | end 33 | 34 | def initialize(attribute_name, options={}) 35 | super 36 | 37 | @range = options.fetch(:range) { options.fetch(:set) } 38 | end 39 | 40 | def valid?(resource) 41 | value = resource.validation_property_value(attribute_name) 42 | 43 | optional?(value) || range.include?(value) 44 | end 45 | 46 | end # module Range 47 | 48 | end # module Within 49 | end # class Rule 50 | end # module Validation 51 | end # module DataMapper 52 | 53 | require 'data_mapper/validation/rule/within/range/bounded' 54 | require 'data_mapper/validation/rule/within/range/unbounded_begin' 55 | require 'data_mapper/validation/rule/within/range/unbounded_end' 56 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/within/range/bounded.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule/within/range' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | module Within 9 | module Range 10 | 11 | class Bounded < Rule 12 | 13 | include Range 14 | 15 | def violation_type(resource) 16 | :value_between 17 | end 18 | 19 | def violation_data(resource) 20 | [ [ :minimum, range.begin ], [ :maximum, range.end ] ] 21 | end 22 | 23 | end # class Bounded 24 | 25 | end # module Range 26 | end # module Within 27 | end # class Rule 28 | end # module Validation 29 | end # module DataMapper 30 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/within/range/unbounded_begin.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule/within/range' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | module Within 9 | module Range 10 | 11 | class UnboundedBegin < Rule 12 | 13 | include Range 14 | 15 | def violation_type(resource) 16 | :less_than_or_equal_to 17 | end 18 | 19 | def violation_data(resource) 20 | [ [ :maximum, range.max ] ] 21 | end 22 | 23 | end # class UnboundedBegin 24 | 25 | end # module Range 26 | end # module Within 27 | end # class Rule 28 | end # module Validation 29 | end # module DataMapper 30 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/within/range/unbounded_end.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule/within/range' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | module Within 9 | module Range 10 | 11 | class UnboundedEnd < Rule 12 | 13 | include Range 14 | 15 | def violation_type(resource) 16 | :greater_than_or_equal_to 17 | end 18 | 19 | def violation_data(resource) 20 | [ [ :minimum, range.begin ] ] 21 | end 22 | 23 | end # class UnboundedBegin 24 | 25 | end # module Range 26 | end # module Within 27 | end # class Rule 28 | end # module Validation 29 | end # module DataMapper 30 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/rule/within/set.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | require 'data_mapper/validation/rule/within' 4 | 5 | module DataMapper 6 | module Validation 7 | class Rule 8 | module Within 9 | 10 | class Set < Rule 11 | 12 | EQUALIZE_ON = superclass::EQUALIZE_ON.dup << :set 13 | 14 | equalize *EQUALIZE_ON 15 | 16 | include Within 17 | 18 | attr_reader :set 19 | 20 | def initialize(attribute_name, options={}) 21 | super 22 | 23 | @set = options.fetch(:set, []) 24 | end 25 | 26 | def valid?(resource) 27 | value = resource.validation_property_value(attribute_name) 28 | 29 | optional?(value) || set.include?(value) 30 | end 31 | 32 | def violation_type(resource) 33 | :inclusion 34 | end 35 | 36 | def violation_data(resource) 37 | [ [ :set, set.to_a.join(', ') ] ] 38 | end 39 | 40 | end # class Set 41 | 42 | end # module Within 43 | end # class Rule 44 | end # module Validation 45 | end # module DataMapper 46 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/support/object.rb: -------------------------------------------------------------------------------- 1 | # TODO: remove Object#try_call 2 | class Object 3 | # If receiver is callable, calls it and returns result. 4 | # If not, just returns receiver itself 5 | # 6 | # @return [Object] 7 | # @api private 8 | def try_call(*args) 9 | if self.respond_to?(:call) 10 | self.call(*args) 11 | else 12 | self 13 | end 14 | end 15 | 16 | def validatable? 17 | false 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/version.rb: -------------------------------------------------------------------------------- 1 | module DataMapper 2 | module Validation 3 | VERSION = '1.3.0.beta' 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /lib/data_mapper/validation/violation_set.rb: -------------------------------------------------------------------------------- 1 | 2 | require 'data_mapper/validation/support/ordered_hash' 3 | require 'data_mapper/validation/violation' 4 | 5 | module DataMapper 6 | module Validation 7 | 8 | class ViolationSet 9 | 10 | include Enumerable 11 | 12 | # @api private 13 | attr_reader :resource 14 | 15 | # @api private 16 | attr_reader :violations 17 | # TODO: why was this private? 18 | private :violations 19 | 20 | # TODO: replace OrderedHash with OrderedSet and remove vendor'd OrderedHash 21 | def initialize(resource) 22 | @resource = resource 23 | @violations = OrderedHash.new { |h,k| h[k] = [] } 24 | end 25 | 26 | # Clear existing validation violations. 27 | # 28 | # @api public 29 | def clear 30 | violations.clear 31 | end 32 | 33 | # Add a validation error. Use the attribute_name :general if the violations 34 | # does not apply to a specific field of the Resource. 35 | # 36 | # @param [Symbol, Violation] attribute_name_or_violation 37 | # The name of the field that caused the violation, or 38 | # the Violation which describes the validation violation 39 | # @param [NilClass, String, #call, Hash] message 40 | # The message to add. 41 | # 42 | # @see Violation#initialize 43 | # 44 | # @api public 45 | def add(attribute_name_or_violation, message = nil) 46 | violation = 47 | if attribute_name_or_violation.kind_of?(Violation) 48 | attribute_name_or_violation 49 | else 50 | Violation.new(resource, message, nil, attribute_name_or_violation) 51 | end 52 | 53 | violations[violation.attribute_name] << violation 54 | end 55 | 56 | # Collect all violations into a single list. 57 | # 58 | # @api public 59 | def full_messages 60 | violations.inject([]) do |list, (attribute_name, violations)| 61 | messages = violations 62 | messages = violations.full_messages if violations.respond_to?(:full_messages) 63 | list += messages 64 | end 65 | end 66 | 67 | # Return validation violations for a particular attribute_name. 68 | # 69 | # @param [Symbol] attribute_name 70 | # The name of the field you want an violation for. 71 | # 72 | # @return [Array(Violation, String), NilClass] 73 | # Array of Violations, if there are violations on +attribute_name+ 74 | # nil if there are no violations on +attribute_name+ 75 | # 76 | # @api public 77 | # 78 | # TODO: use a data structure that ensures uniqueness 79 | def on(attribute_name) 80 | attribute_violations = violations[attribute_name] 81 | attribute_violations.empty? ? nil : attribute_violations.uniq 82 | end 83 | 84 | # @api public 85 | def each 86 | violations.each_value do |v| 87 | yield(v) unless DataMapper::Ext.blank?(v) 88 | end 89 | end 90 | 91 | # @api public 92 | def empty? 93 | violations.all? { |attribute_name, violations| violations.empty? } 94 | end 95 | 96 | # @api public 97 | # 98 | # FIXME: calling #to_sym on uncontrolled input is an 99 | # invitation for a memory leak 100 | def [](attribute_name) 101 | violations[attribute_name.to_sym] 102 | end 103 | 104 | def method_missing(meth, *args, &block) 105 | violations.send(meth, *args, &block) 106 | end 107 | 108 | def respond_to?(method) 109 | super || violations.respond_to?(method) 110 | end 111 | 112 | end # class ViolationSet 113 | 114 | end # module Validation 115 | end # module DataMapper 116 | -------------------------------------------------------------------------------- /lib/dm-validations.rb: -------------------------------------------------------------------------------- 1 | require 'dm-core' 2 | 3 | require 'data_mapper/validation/support/ordered_hash' 4 | require 'data_mapper/validation/support/object' 5 | 6 | require 'data_mapper/validation' 7 | 8 | require 'data_mapper/validation/exceptions' 9 | require 'data_mapper/validation/context' 10 | require 'data_mapper/validation/violation' 11 | require 'data_mapper/validation/violation_set' 12 | 13 | require 'data_mapper/validation/rule' 14 | require 'data_mapper/validation/rule_set' 15 | require 'data_mapper/validation/contextual_rule_set' 16 | 17 | require 'data_mapper/validation/resource_extensions' 18 | require 'data_mapper/validation/model_extensions' 19 | require 'data_mapper/validation/inferred' 20 | 21 | # TODO: eventually drop this from here and let it be an opt-in require 22 | require 'data_mapper/validation/backward' 23 | # TODO: consider moving to a version-specific backwards-compatibility file: 24 | # require 'data_mapper/validation/backward/1_1' 25 | -------------------------------------------------------------------------------- /spec/data_mapper/validation/resource_extensions/save_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'data_mapper/validation/resource_extensions' 3 | 4 | describe DataMapper::Validation::ResourceExtensions, '#save' do 5 | before :all do 6 | class SaveTestResource 7 | include DataMapper::Resource 8 | 9 | property :id, Serial 10 | 11 | def _persist 12 | self 13 | end 14 | end 15 | 16 | SaveTestResource.finalize 17 | end 18 | 19 | subject { SaveTestResource.new } 20 | 21 | it 'returns false when #valid? returns false' do 22 | subject.should_receive(:valid?).and_return(false) 23 | 24 | subject.save.should be_false 25 | end 26 | 27 | it 'calls #validation_rules.assert_valid_context with its #default_validation_context' do 28 | context_name = :default 29 | contextual_rule_set = mock(DataMapper::Validation::ContextualRuleSet) 30 | contextual_rule_set.stub(:current_context) 31 | subject.stub(:save_self) 32 | subject.stub(:validation_rules => contextual_rule_set) 33 | 34 | subject.should_receive(:default_validation_context).and_return(context_name) 35 | contextual_rule_set.should_receive(:assert_valid_context).with(context_name) 36 | 37 | subject.save 38 | end 39 | 40 | it 'calls #save_self' do 41 | subject.should_receive(:save_self) 42 | 43 | subject.save 44 | end 45 | 46 | it 'pushes its default_validation_context on the Context stack' do 47 | context_name = :default 48 | subject.stub(:default_validation_context => context_name) 49 | subject.should_receive(:_save) do 50 | DataMapper::Validation::Context.current.should be(context_name) 51 | end 52 | 53 | subject.save 54 | end 55 | 56 | end 57 | -------------------------------------------------------------------------------- /spec/data_mapper/validation/resource_extensions/validate_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'data_mapper/validation/resource_extensions' 3 | 4 | describe DataMapper::Validation::ResourceExtensions, '#validate' do 5 | before :all do 6 | class Base 7 | include DataMapper::Resource 8 | 9 | property :id, Serial 10 | property :required, String, :required => true, :default => "value" 11 | 12 | belongs_to :parent, "Parent", :child_key => [ :parent_id ], :required => false 13 | has n, :children, "Child" 14 | end 15 | 16 | class Parent 17 | include DataMapper::Resource 18 | 19 | property :id, Serial 20 | property :required, String, :required => true, :default => "value" 21 | 22 | has 1, :base, "Base", :child_key => [ :parent_id ] 23 | end 24 | 25 | class Child 26 | include DataMapper::Resource 27 | 28 | property :id, Serial 29 | property :required, String, :required => true, :default => "value" 30 | 31 | belongs_to :base, "Base", :child_key => [ :base_id ], :required => false 32 | end 33 | 34 | Base.finalize 35 | Parent.finalize 36 | Child.finalize 37 | end 38 | 39 | subject { Base.new(:parent => parent, :children => children) } 40 | 41 | context 'when self, parent(s) and child(ren) are valid' do 42 | let(:parent) { Parent.new } 43 | let(:children) { [ Child.new, Child.new ] } 44 | 45 | it 'does not append errors' do 46 | subject.validate.errors.should be_empty 47 | end 48 | end 49 | 50 | context 'when a parent is invalid' do 51 | let(:parent) { Parent.new(:required => nil) } 52 | let(:children) { [ Child.new, Child.new ] } 53 | 54 | before { pending } 55 | 56 | it 'does append violations' do 57 | subject.validate.errors.should_not be_empty 58 | end 59 | 60 | it 'appends a violation on :parent' do 61 | subject.validate.errors.on(:parent).should_not be_empty 62 | end 63 | 64 | it 'appends a single violation on :parent' do 65 | subject.validate.errors.on(:parent).size.should eql(1) 66 | end 67 | end 68 | 69 | context 'when a child is invalid' do 70 | let(:parent) { Parent.new } 71 | let(:children) { [ Child.new, Child.new(:required => nil) ] } 72 | 73 | before { pending } 74 | 75 | it 'does append violations' do 76 | subject.validate.errors.should_not be_empty 77 | end 78 | 79 | it 'appends a violation on :children' do 80 | subject.validate.errors.on(:children).should_not be_empty 81 | end 82 | 83 | it 'appends a single violation on :children' do 84 | subject.validate.errors.on(:children).size.should eql(1) 85 | end 86 | end 87 | 88 | context 'when both children are invalid in the same way' do 89 | let(:parent) { Parent.new } 90 | let(:children) { [ Child.new(:required => nil), Child.new(:required => nil) ] } 91 | 92 | before { pending } 93 | 94 | it 'does append violations' do 95 | subject.validate.errors.should_not be_empty 96 | end 97 | 98 | it 'appends a single violation on :children' do 99 | subject.validate.errors.on(:children).size.should eql(1) 100 | end 101 | end 102 | 103 | end 104 | -------------------------------------------------------------------------------- /spec/fixtures/barcode.rb: -------------------------------------------------------------------------------- 1 | module DataMapper 2 | module Validation 3 | module Fixtures 4 | class Barcode 5 | attr_accessor :valid_hook_call_count 6 | 7 | # 8 | # Behaviors 9 | # 10 | 11 | include DataMapper::Resource 12 | 13 | # 14 | # Properties 15 | # 16 | 17 | without_auto_validations do 18 | property :code, String, :key => true 19 | end 20 | 21 | # 22 | # Validations 23 | # 24 | 25 | validates_length_of :code, :max => 10 26 | 27 | def self.valid_instance 28 | new(:code => "3600029145") 29 | end 30 | 31 | # measure the number of times #valid? is executed 32 | before :valid? do 33 | @valid_hook_call_count ||= 0 34 | @valid_hook_call_count += 1 35 | end 36 | 37 | end # Barcode 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /spec/fixtures/basketball_court.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | module DataMapper 4 | module Validation 5 | module Fixtures 6 | class BasketballCourt 7 | # 8 | # Behaviors 9 | # 10 | 11 | include DataMapper::Resource 12 | 13 | # 14 | # Properties 15 | # 16 | 17 | property :id, Serial 18 | 19 | without_auto_validations do 20 | property :name, String 21 | 22 | property :length, Float 23 | property :width, Float 24 | 25 | property :three_point_line_distance, Float 26 | property :free_throw_line_distance, Float 27 | property :rim_height, Float 28 | end 29 | 30 | # 31 | # Validations 32 | # 33 | 34 | # obviously these are all metrics 35 | validates_numericality_of :length, :gte => 15.0, :lte => 15.24 36 | validates_numericality_of :width, :gte => 25.28, :lte => 28.65 37 | 38 | # 3 pt line distance may use :gte and :lte, but for 39 | # sake of spec example we make it up a little 40 | validates_numericality_of :three_point_line_distance, :gt => 6.7, :lt => 7.24 41 | validates_numericality_of :free_throw_line_distance, :equals => 4.57 42 | validates_numericality_of :rim_height, :eq => 3.05 43 | 44 | def self.valid_instance(overrides = {}) 45 | defaults = { 46 | :length => 15.24, 47 | :width => 28.65, 48 | :free_throw_line_distance => 4.57, 49 | :rim_height => 3.05, 50 | :three_point_line_distance => 6.9 51 | } 52 | 53 | new(defaults.merge(overrides)) 54 | end 55 | end 56 | end # Fixtures 57 | end # Validations 58 | end # DataMapper 59 | -------------------------------------------------------------------------------- /spec/fixtures/basketball_player.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | module DataMapper 4 | module Validation 5 | module Fixtures 6 | class BasketballPlayer 7 | # 8 | # Behaviors 9 | # 10 | 11 | include DataMapper::Resource 12 | 13 | # 14 | # Properties 15 | # 16 | 17 | property :id, Serial 18 | 19 | without_auto_validations do 20 | property :name, String 21 | property :height, Float 22 | property :weight, Float 23 | end 24 | 25 | # 26 | # Validations 27 | # 28 | 29 | # precision and scale need to be defined for length to be validated 30 | validates_numericality_of :height, :weight, :precision => 10 31 | end 32 | end # Fixtures 33 | end # Validations 34 | end # DataMapper 35 | -------------------------------------------------------------------------------- /spec/fixtures/beta_tester_account.rb: -------------------------------------------------------------------------------- 1 | module DataMapper 2 | module Validation 3 | module Fixtures 4 | class BetaTesterAccount 5 | # 6 | # Behaviors 7 | # 8 | 9 | include ::DataMapper::Resource 10 | 11 | # 12 | # Properties 13 | # 14 | 15 | property :id, Serial 16 | property :full_name, String, :auto_validation => false 17 | property :email, String, :auto_validation => false 18 | 19 | property :user_agreement, Boolean, :auto_validation => false 20 | property :newsletter_signup, String, :auto_validation => false 21 | property :privacy_agreement, String, :auto_validation => false 22 | 23 | # 24 | # Validations 25 | # 26 | 27 | validates_acceptance_of :user_agreement, :allow_nil => false 28 | validates_acceptance_of :newsletter_signup 29 | validates_acceptance_of :privacy_agreement, :accept => %w(agreed accept), :message => "You must accept this agreement in order to proceed" 30 | end # BetaTesterAccount 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /spec/fixtures/bill_of_landing.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | module DataMapper 4 | module Validation 5 | module Fixtures 6 | class BillOfLading 7 | # 8 | # Behaviors 9 | # 10 | 11 | include DataMapper::Resource 12 | 13 | # 14 | # Properties 15 | # 16 | 17 | property :id, Serial 18 | 19 | property :doc_no, String, :auto_validation => false 20 | property :email, String, :auto_validation => false 21 | property :username, String, :auto_validation => false 22 | property :url, String, :auto_validation => false 23 | property :bank_url, URI, :auto_validation => false 24 | property :code, String, :auto_validation => false, :default => "123456" 25 | 26 | # 27 | # Validations 28 | # 29 | 30 | # this is a trivial example 31 | validates_format_of :doc_no, :with => lambda { |code| 32 | code =~ /\AA\d{4}\z/ || code =~ /\A[B-Z]\d{6}X12\z/ 33 | } 34 | 35 | validates_format_of :email, :as => :email_address 36 | validates_format_of :url, :as => :url, :allow_nil => false, :allow_blank => false 37 | 38 | validates_format_of :username, :with => /[a-z]/, :message => 'Username must have at least one letter', :allow_nil => true 39 | validates_format_of :code, :with => /\d{5,6}/, :message => 'Code format is invalid' 40 | end 41 | 42 | class SurrenderBillOfLading < BillOfLading 43 | validates_format_of :bank_url, :as => :url, :allow_nil => false, :allow_blank => false 44 | end 45 | end # Fixtures 46 | end # Validations 47 | end # DataMapper 48 | -------------------------------------------------------------------------------- /spec/fixtures/boat_dock.rb: -------------------------------------------------------------------------------- 1 | module DataMapper 2 | module Validation 3 | module Fixtures 4 | class BoatDock 5 | # 6 | # Behaviors 7 | # 8 | 9 | include DataMapper::Resource 10 | 11 | # 12 | # Properties 13 | # 14 | 15 | property :id, Serial 16 | property :name, String, :auto_validation => false, :default => "I'm a long string" 17 | 18 | # 19 | # Validations 20 | # 21 | 22 | validates_length_of :name, :min => 3 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /spec/fixtures/city.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | class City 4 | # 5 | # Behaviors 6 | # 7 | 8 | include DataMapper::Resource 9 | 10 | # 11 | # Properties 12 | # 13 | 14 | property :id, Serial 15 | property :name, String 16 | 17 | property :founded_in, Integer, :auto_validation => false 18 | 19 | # 20 | # Validations 21 | # 22 | 23 | validates_numericality_of :founded_in, :message => "Foundation year must be an integer" 24 | end 25 | -------------------------------------------------------------------------------- /spec/fixtures/company.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | module DataMapper 4 | module Validation 5 | module Fixtures 6 | class Company 7 | # 8 | # Behaviors 9 | # 10 | 11 | include DataMapper::Resource 12 | 13 | # 14 | # Properties 15 | # 16 | 17 | property :id, Serial 18 | property :title, String 19 | property :type, Discriminator 20 | 21 | 22 | # 23 | # Validations 24 | # 25 | 26 | validates_presence_of :title, :message => "Company name is a required field" 27 | 28 | end 29 | 30 | class ServiceCompany < Company 31 | 32 | # 33 | # Properties 34 | # 35 | 36 | without_auto_validations do 37 | property :area_of_expertise, String, :length => (1..60) 38 | end 39 | 40 | # 41 | # Validations 42 | # 43 | 44 | validates_presence_of :area_of_expertise 45 | end 46 | 47 | class ProductCompany < Company 48 | 49 | # 50 | # Properties 51 | # 52 | 53 | without_auto_validations do 54 | property :flagship_product, String, :length => (1..60) 55 | end 56 | 57 | # 58 | # Validations 59 | # 60 | 61 | validates_presence_of :title, :message => "Product company must have a name" 62 | validates_presence_of :flagship_product 63 | end 64 | 65 | class Product 66 | # 67 | # Behaviors 68 | # 69 | 70 | include DataMapper::Resource 71 | 72 | # 73 | # Properties 74 | # 75 | 76 | property :id, Serial 77 | property :name, String, :required => true 78 | 79 | # 80 | # Associations 81 | # 82 | 83 | belongs_to :company, :model => DataMapper::Validations::Fixtures::ProductCompany 84 | 85 | # 86 | # Validations 87 | # 88 | 89 | validates_presence_of :company 90 | end 91 | end 92 | end 93 | end 94 | -------------------------------------------------------------------------------- /spec/fixtures/corporate_world.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | module DataMapper 4 | module Validation 5 | module Fixtures 6 | class Organisation 7 | include DataMapper::Resource 8 | 9 | property :id, Serial 10 | property :name, String 11 | property :domain, String, :unique_index => true 12 | 13 | validates_uniqueness_of :domain, :allow_nil => true 14 | end 15 | 16 | class Department 17 | include DataMapper::Resource 18 | 19 | property :id, Serial 20 | property :name, String, :unique_index => true 21 | 22 | validates_uniqueness_of :name 23 | end 24 | 25 | class User 26 | include DataMapper::Resource 27 | 28 | property :id, Serial 29 | property :user_name, String 30 | 31 | belongs_to :organisation 32 | belongs_to :department 33 | 34 | validates_uniqueness_of :user_name, :when => :signing_up_for_department_account, :scope => [:department] 35 | validates_uniqueness_of :user_name, :when => :signing_up_for_organization_account, :scope => [:organisation] 36 | end 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /spec/fixtures/country.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | class Country 4 | # 5 | # Behaviors 6 | # 7 | 8 | include DataMapper::Resource 9 | 10 | # 11 | # Properties 12 | # 13 | 14 | property :id, Serial 15 | property :name, String 16 | 17 | property :area, Integer 18 | 19 | # 20 | # Validations 21 | # 22 | 23 | validates_numericality_of :area, :message => "Please use integers to specify area" 24 | end 25 | -------------------------------------------------------------------------------- /spec/fixtures/ethernet_frame.rb: -------------------------------------------------------------------------------- 1 | module DataMapper 2 | module Validation 3 | module Fixtures 4 | 5 | # for pedants: we refer to DIX Ethernet here 6 | class EthernetFrame 7 | 8 | # 9 | # Behaviors 10 | # 11 | 12 | include DataMapper::Resource 13 | 14 | # 15 | # Properties 16 | # 17 | 18 | attr_accessor :link_support_fragmentation 19 | 20 | # we have to have a key in a DM resource 21 | property :id, Serial 22 | 23 | without_auto_validations do 24 | property :destination_mac, String 25 | property :source_mac, String 26 | property :ether_type, String 27 | property :payload, Text 28 | property :crc, String 29 | end 30 | 31 | # 32 | # Validations 33 | # 34 | 35 | validates_length_of :destination_mac, :source_mac, :equals => 6 36 | validates_length_of :ether_type, :equals => 2 37 | validates_length_of :payload, :min => 46, :max => 1500, :unless => :link_support_fragmentation 38 | # :is is alias for :equal 39 | validates_length_of :crc, :is => 4 40 | 41 | def self.valid_instance 42 | # these are obvisouly not bits, and not in hexadecimal 43 | # format either, but give fixture models some slack 44 | attributes = { 45 | :destination_mac => "7b7d93", 46 | :source_mac => "abe763", 47 | :ether_type => "88", 48 | :payload => "Imagine yourself a beautiful bag full of bits here", 49 | :crc => "4132" 50 | } 51 | new(attributes) 52 | end 53 | end # EthernetFrame 54 | end 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /spec/fixtures/event.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | module DataMapper 4 | module Validation 5 | module Fixtures 6 | 7 | class Event 8 | # 9 | # Behaviors 10 | # 11 | 12 | include ::DataMapper::Resource 13 | 14 | # 15 | # Properties 16 | # 17 | 18 | property :id, Serial 19 | property :name, String, :required => true 20 | 21 | property :starts_at, DateTime 22 | property :ends_at, DateTime 23 | 24 | # 25 | # Validations 26 | # 27 | 28 | validates_with_method :starts_at, :method => :ensure_dates_order_is_correct 29 | 30 | # 31 | # API 32 | # 33 | 34 | def ensure_dates_order_is_correct 35 | if starts_at && ends_at && (starts_at <= ends_at) 36 | true 37 | else 38 | [false, "Start time cannot be after end time"] 39 | end 40 | end 41 | end # Event 42 | end # Fixtures 43 | end # Validations 44 | end # DataMapper 45 | -------------------------------------------------------------------------------- /spec/fixtures/g3_concert.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | module DataMapper 4 | module Validation 5 | module Fixtures 6 | class G3Concert 7 | # 8 | # Bahaviors 9 | # 10 | 11 | include ::DataMapper::Validations 12 | 13 | # 14 | # Attributes 15 | # 16 | 17 | attr_accessor :year, :participants, :city, :planned 18 | 19 | # 20 | # Validations 21 | # 22 | 23 | validates_with_block :participants, :unless => :planned do 24 | if self.class.known_performances.any? { |perf| perf == self } 25 | true 26 | else 27 | [false, "this G3 is probably yet to take place"] 28 | end 29 | end 30 | 31 | # 32 | # API 33 | # 34 | 35 | def initialize(attributes = {}) 36 | attributes.each do |key, value| 37 | self.send("#{key}=", value) 38 | end 39 | end 40 | 41 | def ==(other) 42 | other.year == self.year && other.participants == self.participants && other.city == self.city 43 | end 44 | 45 | # obvisouly this is intentionally shortened list ;) 46 | def self.known_performances 47 | [ 48 | new(:year => 2004, :participants => "Joe Satriani, Steve Vai, Yngwie Malmsteen", :city => "Denver"), 49 | new(:year => 1996, :participants => "Joe Satriani, Steve Vai, Eric Johnson", :city => "San Francisco"), 50 | new(:year => 2001, :participants => "Joe Satriani, Steve Vai, John Petrucci", :city => "Los Angeles"), 51 | new(:year => 2002, :participants => "Joe Satriani, Steve Vai, John Petrucci", :city => "Los Angeles") 52 | ] 53 | end 54 | end # G3Concert 55 | end # Fixtures 56 | end # Validations 57 | end # DataMapper 58 | -------------------------------------------------------------------------------- /spec/fixtures/integer_dumped_as_string_property.rb: -------------------------------------------------------------------------------- 1 | # Property to test dumped_as != loaded_as behaviour 2 | module DataMapper 3 | class Property 4 | class IntegerDumpedAsStringProperty < DataMapper::Property::Object 5 | load_as ::Integer 6 | dump_as ::String 7 | 8 | accept_options :length 9 | 10 | DEFAULT_LENGTH = 50 11 | length(DEFAULT_LENGTH) 12 | 13 | attr_reader :length 14 | 15 | def dump(value) 16 | value.nil? ? nil : value.to_s 17 | end 18 | 19 | def load(value) 20 | value.nil? ? nil : value.to_i 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /spec/fixtures/jabberwock.rb: -------------------------------------------------------------------------------- 1 | module DataMapper 2 | module Validation 3 | module Fixtures 4 | 5 | class Jabberwock 6 | # 7 | # Behaviors 8 | # 9 | 10 | include DataMapper::Resource 11 | 12 | # 13 | # Properties 14 | # 15 | 16 | property :id, Serial 17 | property :snickersnack, String 18 | 19 | # 20 | # Validations 21 | # 22 | 23 | validates_length_of :snickersnack, :within => 3..40, :message => "worble warble" 24 | end # Jabberwock 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/fixtures/kayak.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | module DataMapper 4 | module Validation 5 | module Fixtures 6 | class Kayak 7 | # 8 | # Behaviors 9 | # 10 | 11 | include ::DataMapper::Resource 12 | 13 | # 14 | # Properties 15 | # 16 | 17 | property :id, Serial 18 | property :salesman, String, :auto_validation => false 19 | 20 | # 21 | # Validations 22 | # 23 | 24 | validates_absence_of :salesman, :on => :sale 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /spec/fixtures/lernean_hydra.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | module DataMapper 4 | module Validation 5 | module Fixtures 6 | class LerneanHydra 7 | # 8 | # Behaviors 9 | # 10 | 11 | include DataMapper::Resource 12 | 13 | # 14 | # Properties 15 | # 16 | 17 | property :id, Serial 18 | 19 | without_auto_validations do 20 | property :head_count, Float 21 | end 22 | 23 | # 24 | # Validations 25 | # 26 | 27 | validates_numericality_of :head_count, :eq => 9, :message => "Lernean hydra is said to have exactly 9 heads" 28 | 29 | def self.valid_instance(overrides = {}) 30 | defaults = { 31 | :head_count => 9 32 | } 33 | 34 | new(defaults.merge(overrides)) 35 | end 36 | end 37 | end # Fixtures 38 | end # Validations 39 | end # DataMapper 40 | -------------------------------------------------------------------------------- /spec/fixtures/llama_spaceship.rb: -------------------------------------------------------------------------------- 1 | module DataMapper 2 | module Validations 3 | module Fixtures 4 | class LlamaSpaceship 5 | include DataMapper::Resource 6 | 7 | property :id, Serial 8 | property :type, String 9 | property :color, String 10 | 11 | validates_format_of :color, :with => /^red|black$/, :if => Proc.new { |spaceship| spaceship.type == "standard" } 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/fixtures/mathematical_function.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | module DataMapper 4 | module Validation 5 | module Fixtures 6 | class MathematicalFunction 7 | # 8 | # Behaviors 9 | # 10 | 11 | include ::DataMapper::Resource 12 | 13 | # 14 | # Properties 15 | # 16 | 17 | property :id, Serial 18 | property :input, Float, :auto_validation => false 19 | property :output, Float, :auto_validation => false 20 | 21 | # 22 | # Validations 23 | # 24 | 25 | # function domain 26 | # don't ask me what function that is 27 | validates_within :input, :set => (1..n) 28 | 29 | # function range 30 | validates_within :output, :set => (-n..0), :message => "Negative values or zero only, please" 31 | end # MathematicalFunction 32 | end # Fixtures 33 | end # Validations 34 | end # DataMapper 35 | -------------------------------------------------------------------------------- /spec/fixtures/memory_object.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | require File.join(File.dirname(__FILE__),'integer_dumped_as_string_property') 4 | 5 | module DataMapper 6 | module Validation 7 | module Fixtures 8 | class MemoryObject 9 | # 10 | # Behaviors 11 | # 12 | 13 | include ::DataMapper::Resource 14 | 15 | # 16 | # Properties 17 | # 18 | 19 | property :id, Serial 20 | property :marked, Boolean, :auto_validation => false 21 | property :color, String, :auto_validation => false 22 | 23 | property :stupid_integer, IntegerDumpedAsStringProperty, :auto_validation => false 24 | 25 | # 26 | # Validations 27 | # 28 | 29 | validates_primitive_type_of :marked 30 | validates_primitive_type_of :color 31 | validates_primitive_type_of :stupid_integer 32 | end 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /spec/fixtures/mittelschnauzer.rb: -------------------------------------------------------------------------------- 1 | module DataMapper 2 | module Validation 3 | module Fixtures 4 | # Mittelschauzer is a type of dog. The More You Know. 5 | class Mittelschnauzer 6 | 7 | # 8 | # Behaviors 9 | # 10 | 11 | include DataMapper::Resource 12 | 13 | # 14 | # Properties 15 | # 16 | 17 | without_auto_validations do 18 | property :name, String, :key => true 19 | property :height, Float 20 | end 21 | 22 | attr_accessor :owner 23 | 24 | # 25 | # Validations 26 | # 27 | 28 | validates_length_of :name, :min => 2, :allow_nil => false 29 | validates_length_of :owner, :min => 2 30 | 31 | validates_numericality_of :height, :lt => 55.2 32 | 33 | def self.valid_instance 34 | new(:name => "Roudolf Wilde", :height => 50.4, :owner => 'don') 35 | end 36 | end # Mittelschnauzer 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /spec/fixtures/motor_launch.rb: -------------------------------------------------------------------------------- 1 | module DataMapper 2 | module Validation 3 | module Fixtures 4 | 5 | class MotorLaunch 6 | # 7 | # Behaviors 8 | # 9 | 10 | include DataMapper::Resource 11 | 12 | # 13 | # Properties 14 | # 15 | 16 | property :id, Serial 17 | property :name, String, :auto_validation => false 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /spec/fixtures/multibyte.rb: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | module DataMapper 4 | module Validation 5 | module Fixtures 6 | class Multibyte 7 | include DataMapper::Resource 8 | 9 | property :id, Serial 10 | property :name, String 11 | 12 | validates_length_of :name, :is => 20 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/fixtures/page.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | module DataMapper 4 | module Validation 5 | module Fixtures 6 | 7 | # see http://datamapper.lighthouseapp.com/projects/20609/tickets/671 8 | class Page 9 | # 10 | # Behaviors 11 | # 12 | 13 | include DataMapper::Resource 14 | 15 | # 16 | # Properties 17 | # 18 | 19 | property :id, Serial, :key => true 20 | property :body, Text, :required => true 21 | 22 | # 23 | # Validations 24 | # 25 | 26 | # duplicates inferred validation for body (caused by 27 | # :required => true) 28 | validates_presence_of :body 29 | end 30 | end # Fixtures 31 | end # Validations 32 | end # DataMapper 33 | -------------------------------------------------------------------------------- /spec/fixtures/phone_number.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | module DataMapper 4 | module Validation 5 | module Fixtures 6 | class PhoneNumber 7 | # 8 | # Behaviors 9 | # 10 | 11 | include ::DataMapper::Resource 12 | 13 | # 14 | # Properties 15 | # 16 | 17 | property :id, Serial 18 | property :type_of_number, String, :auto_validation => false 19 | 20 | # 21 | # Validations 22 | # 23 | 24 | validates_within :type_of_number, :set => %w(home work cell), :message => "Should be one of: home, cell or work" 25 | end # PhoneNumber 26 | end # Fixtures 27 | end # Validations 28 | end # DataMapper 29 | -------------------------------------------------------------------------------- /spec/fixtures/pirogue.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | module DataMapper 4 | module Validation 5 | module Fixtures 6 | class Pirogue 7 | # 8 | # Behaviors 9 | # 10 | 11 | include DataMapper::Resource 12 | 13 | # 14 | # Properties 15 | # 16 | 17 | property :id, Serial 18 | property :salesman, String, :default => 'Layfayette' 19 | 20 | # 21 | # Validations 22 | # 23 | 24 | validates_absence_of :salesman, :on => :sale 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /spec/fixtures/programming_language.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | module DataMapper 4 | module Validation 5 | module Fixtures 6 | # If you think that this particular fixture class 7 | # and assumptions made below are full of bullshit 8 | # and author is a moron, you are 100% right. I am, 9 | # but it's me who rewrites poor dm-validations 10 | # spec suite this time, so unless someone smart 11 | # steps up to do it, we have to roll on with 12 | # this crappy example of method validation. — MK 13 | class ProgrammingLanguage 14 | # 15 | # Behaviors 16 | # 17 | 18 | include ::DataMapper::Validations 19 | 20 | # 21 | # Attributes 22 | # 23 | 24 | attr_accessor :name, :allows_system_calls, :allows_manual_memory_management, :allows_optional_parentheses, 25 | :allows_operator_overload, :approved_by_linus, :compiler_excels_at_utilizing_cpu_cache, 26 | :is_very_high_level, :does_not_require_explicit_return_keyword, :standard_library_support_parallel_programming_out_of_the_box 27 | 28 | # 29 | # Validations 30 | # 31 | 32 | validates_with_method :ensure_appropriate_for_system_programming, :when => [:doing_system_programming, :hacking_on_the_kernel, :implementing_a_game_engine] 33 | validates_with_method :ensure_appropriate_for_dsls, :when => [:implementing_a_dsl] 34 | validates_with_method :ensure_appropriate_for_cpu_intensive_tasks, :when => [:implementing_a_game_engine_core] 35 | validates_with_method :ensure_approved_by_linus_himself, :when => [:hacking_on_the_kernel], :violation_type => :unapproved_by_linus 36 | 37 | # 38 | # API 39 | # 40 | 41 | def initialize(args = {}) 42 | args.each do |key, value| 43 | self.send("#{key}=", value) 44 | end 45 | end 46 | 47 | def ensure_appropriate_for_system_programming 48 | if allows_manual_memory_management && allows_system_calls 49 | true 50 | else 51 | [false, "try something that is closer to the metal"] 52 | end 53 | end 54 | 55 | def ensure_appropriate_for_dsls 56 | if allows_optional_parentheses && allows_operator_overload && is_very_high_level && does_not_require_explicit_return_keyword 57 | true 58 | else 59 | [false, "may not be so good for domain specific languages"] 60 | end 61 | end 62 | 63 | def ensure_appropriate_for_cpu_intensive_tasks 64 | if compiler_excels_at_utilizing_cpu_cache && allows_manual_memory_management 65 | true 66 | else 67 | [false, "may not be so good for CPU intensive tasks"] 68 | end 69 | end 70 | 71 | def ensure_approved_by_linus_himself 72 | if name.downcase == "c++" 73 | [false, "Quite frankly, even if the choice of C were to do *nothing* 74 | but keep the C++ programmers out, that in itself would be 75 | a huge reason to use C."] 76 | else 77 | true 78 | end 79 | end 80 | end # ProgrammingLanguage 81 | end # Fixtures 82 | end # Validations 83 | end # DataMapper 84 | -------------------------------------------------------------------------------- /spec/fixtures/reservation.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | module DataMapper 4 | module Validation 5 | module Fixtures 6 | class Reservation 7 | # 8 | # Behaviors 9 | # 10 | 11 | include ::DataMapper::Resource 12 | 13 | # 14 | # Attributes 15 | # 16 | 17 | attr_accessor :person_name_confirmation, :seats_confirmation 18 | 19 | # 20 | # Properties 21 | # 22 | 23 | property :id, Serial 24 | property :person_name, String, :auto_validation => false 25 | property :number_of_seats, Integer, :auto_validation => false 26 | 27 | # 28 | # Validations 29 | # 30 | 31 | validates_confirmation_of :person_name, :allow_nil => false, :allow_blank => false 32 | validates_confirmation_of :number_of_seats, :confirm => :seats_confirmation, :message => Proc.new { |resource, property| 33 | '%s requires confirmation for %s' % [DataMapper::Inflector.demodulize(resource.model.name), property.name] 34 | } 35 | end # Reservation 36 | end # Fixtures 37 | end # Validations 38 | end # DataMapper 39 | -------------------------------------------------------------------------------- /spec/fixtures/scm_operation.rb: -------------------------------------------------------------------------------- 1 | # 2 | # SCMs 3 | # 4 | # This example may look stupid (I am sure it is), 5 | # but it is way better than foobars and easier to read/add cases 6 | # compared to gardening examples because every software engineer has idea 7 | # about SCMs and not every software engineer does gardening often. 8 | # 9 | 10 | class ScmOperation 11 | include DataMapper::Resource 12 | 13 | # 14 | # Property 15 | # 16 | 17 | property :id, Serial 18 | 19 | # operation name 20 | property :name, String, :auto_validation => false 21 | 22 | property :committer_name, String, :auto_validation => false, :default => "Just another Ruby hacker" 23 | property :author_name, String, :auto_validation => false, :default => "Just another Ruby hacker" 24 | property :network_connection, Boolean, :auto_validation => false 25 | property :message, Text, :auto_validation => false 26 | property :clean_working_copy, Boolean, :auto_validation => false 27 | 28 | # 29 | # Validations 30 | # 31 | 32 | validates_presence_of :name 33 | end 34 | 35 | class SubversionOperation < ScmOperation 36 | # 37 | # Validations 38 | # 39 | 40 | validates_presence_of :network_connection, :when => [:committing, :log_viewing] 41 | end 42 | 43 | class GitOperation < ScmOperation 44 | # 45 | # Validations 46 | # 47 | 48 | validates_presence_of :author_name, :committer_name, :when => :committing 49 | 50 | validates_presence_of :message, :when => :committing 51 | validates_presence_of :network_connection, :when => [:pushing, :pulling], :message => { 52 | :pushing => "though git is advanced, it cannot push without network connectivity", 53 | :pulling => "you must have network connectivity to pull from others" 54 | } 55 | validates_presence_of :clean_working_copy, :when => :pulling 56 | end 57 | -------------------------------------------------------------------------------- /spec/fixtures/sms_message.rb: -------------------------------------------------------------------------------- 1 | module DataMapper 2 | module Validation 3 | module Fixtures 4 | 5 | class SmsMessage 6 | # 7 | # Behaviors 8 | # 9 | 10 | include DataMapper::Resource 11 | 12 | # 13 | # Properties 14 | # 15 | 16 | property :id, Serial 17 | property :body, Text, :length => (1..500) 18 | end 19 | 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /spec/fixtures/udp_packet.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | module DataMapper 4 | module Validation 5 | module Fixtures 6 | 7 | class UDPPacket 8 | # 9 | # Behaviors 10 | # 11 | 12 | include DataMapper::Resource 13 | 14 | # 15 | # Properties 16 | # 17 | 18 | property :id, Serial 19 | 20 | property :source_port, Integer, :auto_validation => false 21 | property :destination_port, Integer, :auto_validation => false 22 | 23 | property :length, Integer, :auto_validation => false 24 | property :checksum, String, :auto_validation => false 25 | # consider that there are multiple algorithms 26 | # available to the app, and it is allowed 27 | # to be chosed 28 | # 29 | # yes, to some degree, this is a made up 30 | # property ;) 31 | property :checksum_algorithm, String, :auto_validation => false 32 | property :data, Text, :auto_validation => false 33 | 34 | # 35 | # Volatile attributes 36 | # 37 | 38 | attr_accessor :underlying_ip_version 39 | 40 | # 41 | # Validations 42 | # 43 | 44 | validates_presence_of :checksum_algorithm, :checksum, :if => Proc.new { |packet| packet.underlying_ip_version == 6 }, :message => "Checksum is mandatory when used with IPv6" 45 | end 46 | 47 | end # Fixtures 48 | end # Validations 49 | end # DataMapper 50 | -------------------------------------------------------------------------------- /spec/integration/absent_field_validator/absent_field_validator_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/absent_field_validator/spec_helper' 3 | 4 | describe 'DataMapper::Validations::Fixtures::Kayak' do 5 | before :all do 6 | DataMapper::Validations::Fixtures::Kayak.auto_migrate! 7 | 8 | @kayak = DataMapper::Validations::Fixtures::Kayak.new 9 | @kayak.should be_valid_for_sale 10 | end 11 | 12 | describe "with salesman being non blank" do 13 | before :all do 14 | @kayak.salesman = 'Joe' 15 | end 16 | 17 | it "is invalid" do 18 | @kayak.should_not be_valid_for_sale 19 | end 20 | 21 | it "has meaningful error message" do 22 | @kayak.errors.on(:salesman).should == [ 'Salesman must be absent' ] 23 | end 24 | end 25 | 26 | 27 | describe "with salesman being nil" do 28 | before :all do 29 | @kayak.salesman = nil 30 | end 31 | 32 | it "is valid" do 33 | @kayak.should be_valid_for_sale 34 | end 35 | 36 | it "has no error messages" do 37 | @kayak.errors.on(:salesman).should be_nil 38 | end 39 | end 40 | 41 | 42 | describe "with salesman being an empty string" do 43 | before :all do 44 | @kayak.salesman = '' 45 | end 46 | 47 | it "is valid" do 48 | @kayak.should be_valid_for_sale 49 | end 50 | 51 | it "has no error messages" do 52 | @kayak.errors.on(:salesman).should be_nil 53 | end 54 | end 55 | 56 | 57 | describe "with salesman being a string of white spaces" do 58 | before :all do 59 | @kayak.salesman = ' ' 60 | end 61 | 62 | it "is valid" do 63 | @kayak.should be_valid_for_sale 64 | end 65 | 66 | it "has no error messages" do 67 | @kayak.errors.on(:salesman).should be_nil 68 | end 69 | end 70 | end 71 | 72 | 73 | describe 'DataMapper::Validations::Fixtures::Pirogue' do 74 | before :all do 75 | DataMapper::Validations::Fixtures::Pirogue.auto_migrate! 76 | 77 | @kayak = DataMapper::Validations::Fixtures::Pirogue.new 78 | @kayak.should_not be_valid_for_sale 79 | end 80 | 81 | describe "by default" do 82 | it "is invalid" do 83 | @kayak.should_not be_valid_for_sale 84 | end 85 | 86 | it "has meaningful error message" do 87 | @kayak.errors.on(:salesman).should == [ 'Salesman must be absent' ] 88 | end 89 | end 90 | end 91 | -------------------------------------------------------------------------------- /spec/integration/absent_field_validator/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # put validator specific fixture models and helpers here 2 | # 3 | # make sure you check out spec/fixtures to see fixture models 4 | # already written 5 | # 6 | # DataMapper developers feels strongly against foobars in the spec 7 | # suite 8 | -------------------------------------------------------------------------------- /spec/integration/acceptance_validator/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # put validator specific fixture models and helpers here 2 | # 3 | # make sure you check out spec/fixtures to see fixture models 4 | # already written 5 | # 6 | # DataMapper developers feels strongly against foobars in the spec 7 | # suite 8 | -------------------------------------------------------------------------------- /spec/integration/automatic_validation/custom_messages_for_inferred_validation_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/automatic_validation/spec_helper' 3 | 4 | describe 'Inferred validations' do 5 | it "allow overriding a single error message" do 6 | custom_boat = Class.new do 7 | include DataMapper::Resource 8 | 9 | def self.name 10 | 'Boat' 11 | end 12 | 13 | property :id, DataMapper::Property::Serial 14 | property :name, String, :required => true, :message => "This boat must have name" 15 | end 16 | boat = custom_boat.new 17 | boat.should_not be_valid 18 | boat.errors.on(:name).should == [ 'This boat must have name' ] 19 | end 20 | 21 | it "should have correct error messages" do 22 | custom_boat = Class.new do 23 | include DataMapper::Resource 24 | 25 | def self.name 26 | 'Boat' 27 | end 28 | 29 | property :id, DataMapper::Property::Serial 30 | property :name, String, :required => true, :length => 5..20, :format => /^[a-z]+$/, 31 | :messages => { 32 | :presence => "This boat must have name", 33 | :length => "Name must have at least 4 and at most 20 chars", 34 | :format => "Please use only small letters" 35 | } 36 | end 37 | 38 | boat = custom_boat.new 39 | boat.should_not be_valid 40 | boat.errors.on(:name).should == [ 'This boat must have name' ] 41 | 42 | boat.name = "%%" 43 | boat.should_not be_valid 44 | boat.errors.on(:name).should == [ 45 | 'Name must have at least 4 and at most 20 chars', 46 | 'Please use only small letters', 47 | ] 48 | 49 | boat.name = "%%asd" 50 | boat.should_not be_valid 51 | boat.errors.on(:name).should == [ 'Please use only small letters' ] 52 | 53 | boat.name = "superboat" 54 | boat.should be_valid 55 | boat.errors.on(:name).should be_nil 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /spec/integration/automatic_validation/disabling_inferred_validation_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/automatic_validation/spec_helper' 3 | 4 | describe "A class with inferred validations disabled for all properties with an option" do 5 | before :all do 6 | @klass = Class.new do 7 | include DataMapper::Resource 8 | 9 | def self.name 10 | 'InferredValidation' 11 | end 12 | 13 | property :id, DataMapper::Property::Serial, :auto_validation => false 14 | property :name, String, :required => true, :auto_validation => false 15 | property :bool, DataMapper::Property::Boolean, :required => true, :auto_validation => false 16 | end 17 | 18 | @model = @klass.new 19 | end 20 | 21 | describe "when instantiated w/o any attributes" do 22 | it_should_behave_like "valid model" 23 | end 24 | end 25 | 26 | 27 | describe "A class with inferred validations disabled for all properties with a block" do 28 | before :all do 29 | @klass = Class.new do 30 | include DataMapper::Resource 31 | 32 | def self.name 33 | 'InferredValidation' 34 | end 35 | 36 | without_auto_validations do 37 | property :id, DataMapper::Property::Serial 38 | property :name, String, :required => true 39 | property :bool, DataMapper::Property::Boolean, :required => true 40 | end 41 | end 42 | 43 | @model = @klass.new 44 | end 45 | 46 | describe "when instantiated w/o any attributes" do 47 | it_should_behave_like "valid model" 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /spec/integration/automatic_validation/inferred_boolean_properties_validation_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/automatic_validation/spec_helper' 3 | 4 | describe "A model with a Boolean property" do 5 | before :all do 6 | @model = HasNullableBoolean.new(:id => 1) 7 | end 8 | 9 | describe "assigned a true" do 10 | before :all do 11 | @model.bool = true 12 | end 13 | 14 | it_should_behave_like "valid model" 15 | end 16 | 17 | describe "assigned a false" do 18 | before :all do 19 | @model.bool = false 20 | end 21 | 22 | it_should_behave_like "valid model" 23 | end 24 | 25 | describe "assigned a nil" do 26 | before :all do 27 | @model.bool = nil 28 | end 29 | 30 | it_should_behave_like "valid model" 31 | end 32 | end 33 | 34 | describe "A model with a required Boolean property" do 35 | before :all do 36 | @model = HasRequiredBoolean.new(:id => 1) 37 | end 38 | 39 | describe "assigned a true" do 40 | before :all do 41 | @model.bool = true 42 | end 43 | 44 | it_should_behave_like "valid model" 45 | end 46 | 47 | describe "assigned a false" do 48 | before :all do 49 | @model.bool = false 50 | end 51 | 52 | it_should_behave_like "valid model" 53 | end 54 | 55 | describe "assigned a nil" do 56 | before :all do 57 | @model.bool = nil 58 | end 59 | 60 | it_should_behave_like "invalid model" 61 | 62 | it "has a meaningful error message" do 63 | @model.errors.on(:bool).should == [ 'Bool must not be nil' ] 64 | end 65 | end 66 | end 67 | 68 | describe "A model with a required paranoid Boolean property" do 69 | before :all do 70 | @model = HasRequiredParanoidBoolean.new(:id => 1) 71 | end 72 | 73 | describe "assigned a true" do 74 | before :all do 75 | @model.bool = true 76 | end 77 | 78 | it_should_behave_like "valid model" 79 | end 80 | 81 | describe "assigned a false" do 82 | before :all do 83 | @model.bool = false 84 | end 85 | 86 | it_should_behave_like "valid model" 87 | end 88 | 89 | describe "assigned a nil" do 90 | before :all do 91 | @model.bool = nil 92 | end 93 | 94 | it_should_behave_like "invalid model" 95 | 96 | it "has a meaningful error message" do 97 | @model.errors.on(:bool).should == [ 'Bool must not be nil' ] 98 | end 99 | end 100 | end 101 | -------------------------------------------------------------------------------- /spec/integration/automatic_validation/inferred_float_property_validation_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/automatic_validation/spec_helper' 3 | 4 | 5 | { :float => Float, :big_decimal => BigDecimal }.each do |column, type| 6 | describe "#{type} property" do 7 | before :all do 8 | SailBoat.auto_migrate! 9 | 10 | @model = SailBoat.new(:id => 1) 11 | end 12 | 13 | describe "with an integer value" do 14 | before :all do 15 | @model.attributes = {column => 1} 16 | end 17 | 18 | it_should_behave_like "valid model" 19 | end 20 | 21 | describe "with a float value" do 22 | before :all do 23 | @model.attributes = {column => 1.0} 24 | end 25 | 26 | it_should_behave_like "valid model" 27 | end 28 | 29 | describe "with a BigDecimal value" do 30 | before :all do 31 | @model.attributes = {column => BigDecimal('1')} 32 | end 33 | 34 | it_should_behave_like "valid model" 35 | end 36 | 37 | describe "with an uncoercible value" do 38 | before :all do 39 | @model.attributes = {column => "foo"} 40 | end 41 | 42 | it_should_behave_like "invalid model" 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /spec/integration/automatic_validation/inferred_format_validation_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/automatic_validation/spec_helper' 3 | 4 | describe 'SailBoat', "with a :format option on a property" do 5 | before :all do 6 | SailBoat.auto_migrate! 7 | 8 | @model = SailBoat.new 9 | @model.should be_valid_for_format_test 10 | end 11 | 12 | describe "and value that matches the format" do 13 | before :all do 14 | @model.code = 'A1234' 15 | end 16 | 17 | it "passes inferred format validation" do 18 | @model.should be_valid_for_format_test 19 | end 20 | end 21 | 22 | describe "and value that DOES NOT match the format" do 23 | before :all do 24 | @model.code = 'BAD CODE' 25 | end 26 | 27 | it "does not pass inferred format validation" do 28 | @model.should_not be_valid_for_format_test 29 | end 30 | 31 | it "has a meaningful error message" do 32 | @model.errors.on(:code).should == [ 'Code has an invalid format' ] 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /spec/integration/automatic_validation/inferred_integer_properties_validation_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/automatic_validation/spec_helper' 3 | 4 | describe "A model with an Integer property" do 5 | before :all do 6 | SailBoat.auto_migrate! 7 | 8 | @model = SailBoat.new 9 | end 10 | 11 | # success case 12 | describe "assigned to an integer" do 13 | before :all do 14 | @model.id = 1 15 | end 16 | 17 | it_should_behave_like "valid model" 18 | end 19 | 20 | describe "assigned a value coercible into an integer" do 21 | before :all do 22 | @model.id = 1.0 23 | end 24 | 25 | it_should_behave_like "valid model" 26 | end 27 | 28 | describe "assigned a value not coercible into an integer" do 29 | before :all do 30 | @model.id = "foo" 31 | end 32 | 33 | it "is invalid" do 34 | @model.should_not be_valid 35 | end 36 | 37 | it "has a meaningful default error message" do 38 | @model.errors.on(:id).should == [ 'Id must be an integer' ] 39 | end 40 | end 41 | 42 | describe "assigned to a too-small integer" do 43 | before :all do 44 | @model.id = 0 45 | end 46 | 47 | it "is invalid" do 48 | @model.should_not be_valid 49 | end 50 | 51 | it "has a meaningful default error message" do 52 | @model.errors.on(:id).should == [ 'Id must be greater than or equal to 1' ] 53 | end 54 | end 55 | 56 | describe "assigned to a too-large integer" do 57 | before :all do 58 | @model.id = 11 59 | end 60 | 61 | it "is invalid" do 62 | @model.should_not be_valid 63 | end 64 | 65 | it "has a meaningful default error message" do 66 | @model.errors.on(:id).should == [ 'Id must be less than or equal to 10' ] 67 | end 68 | end 69 | 70 | end 71 | -------------------------------------------------------------------------------- /spec/integration/automatic_validation/inferred_length_validation_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/automatic_validation/spec_helper' 3 | 4 | describe 'SailBoat' do 5 | before :all do 6 | SailBoat.auto_migrate! 7 | 8 | @model = SailBoat.new(:id => 1) 9 | @model.should be_valid_for_length_test_1 10 | end 11 | 12 | 13 | describe "with a nil value on property that allows nil" do 14 | before :all do 15 | @model.allow_nil = nil 16 | end 17 | 18 | it "is valid" do 19 | @model.should be_valid_for_nil_test 20 | end 21 | end 22 | 23 | 24 | describe "with 11 characters long description" do 25 | before :all do 26 | @model.description = 'ABCDEFGHIJK' #11 27 | end 28 | 29 | # validates_length_of is inferred from property's :length option 30 | it "is invalid" do 31 | @model.should_not be_valid_for_length_test_1 32 | @model.errors.on(:description).should == [ 'Description must be at most 10 characters long' ] 33 | end 34 | end 35 | 36 | 37 | describe "with 9 characters long description" do 38 | before :all do 39 | @model.description = 'ABCDEFGHI' # 9 40 | end 41 | 42 | # validates_length_of is inferred from property's :length option 43 | it_should_behave_like "valid model" 44 | end 45 | 46 | describe "with 2 character long note" do 47 | before :all do 48 | @model = SailBoat.new(:notes => "AB") 49 | end 50 | 51 | it "is valid" do 52 | @model.should be_valid_for_length_test_2 53 | end 54 | end 55 | 56 | describe "with 10 character long note" do 57 | before :all do 58 | @model = SailBoat.new(:notes => "ABCDEFGHIJ") 59 | end 60 | 61 | it "is valid" do 62 | @model.should be_valid_for_length_test_2 63 | end 64 | end 65 | 66 | describe "with 11 character long note" do 67 | before :all do 68 | @model = SailBoat.new(:notes => "ABCDEFGHIJK") 69 | end 70 | 71 | it "is invalid" do 72 | @model.should_not be_valid_for_length_test_2 73 | end 74 | 75 | it "has a meaningful error message" do 76 | @model.errors.on(:notes).should == [ 'Notes must be between 2 and 10 characters long' ] 77 | end 78 | end 79 | end 80 | 81 | 82 | 83 | describe 'DataMapper::Validations::Fixtures::SmsMessage' do 84 | before :all do 85 | DataMapper::Validations::Fixtures::SmsMessage.auto_migrate! 86 | 87 | @model = DataMapper::Validations::Fixtures::SmsMessage.new(:id => 10) 88 | end 89 | 90 | describe "with 2 character long note" do 91 | before :all do 92 | @model.body = "ab" 93 | end 94 | 95 | it_should_behave_like "valid model" 96 | end 97 | 98 | describe "with 10 character long note" do 99 | before :all do 100 | @model.body = "ABCDEFGHIJ" 101 | end 102 | 103 | it_should_behave_like "valid model" 104 | end 105 | 106 | describe "with 499 character long note" do 107 | before :all do 108 | @model.body = "a" * 499 109 | end 110 | 111 | it_should_behave_like "valid model" 112 | end 113 | 114 | describe "with 503 character long note" do 115 | before :all do 116 | @model.body = "a" * 503 117 | end 118 | 119 | it_should_behave_like "invalid model" 120 | 121 | it "has a meaningful error message" do 122 | @model.errors.on(:body).should == [ 'Body must be between 1 and 500 characters long' ] 123 | end 124 | end 125 | 126 | describe 'with an infinitely long note' do 127 | before do 128 | @original = @model.class.properties[:body] 129 | end 130 | 131 | after do 132 | @model.class.property(@original.name, @original.class, @original.options) 133 | end 134 | 135 | it "should raise when trying to set the upper bound of a property length range to Infinity" do 136 | expected_msg = 'Infinity is not a valid upper bound for a length range' 137 | lambda { 138 | @model.class.property :body, String, :length => (1..1.0/0) 139 | }.should raise_error(ArgumentError, expected_msg) 140 | end 141 | end 142 | end 143 | -------------------------------------------------------------------------------- /spec/integration/automatic_validation/inferred_presence_validation_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/automatic_validation/spec_helper' 3 | 4 | describe 'SailBoat' do 5 | before :all do 6 | SailBoat.auto_migrate! 7 | 8 | @model = SailBoat.new(:id => 1) 9 | @model.name = 'Float' 10 | @model.should be_valid_for_presence_test 11 | end 12 | 13 | describe "without name" do 14 | before :all do 15 | @model.name = nil 16 | end 17 | 18 | # has validates_is_present for name thanks to :required => true 19 | it "is invalid" do 20 | @model.should_not be_valid_for_presence_test 21 | @model.errors.on(:name).should == [ 'Name must not be blank' ] 22 | end 23 | end 24 | end 25 | 26 | 27 | 28 | describe 'SailBoat' do 29 | before :all do 30 | SailBoat.auto_migrate! 31 | 32 | @model = SailBoat.new(:id => 1) 33 | @model.name = 'Float' 34 | @model.should be_valid_for_presence_test 35 | end 36 | 37 | describe "with a name" do 38 | before :all do 39 | # no op 40 | end 41 | 42 | # has validates_is_present for name thanks to :required => true 43 | it_should_behave_like "valid model" 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /spec/integration/automatic_validation/inferred_primitive_validation_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/automatic_validation/spec_helper' 3 | 4 | describe 'SailBoat' do 5 | before :all do 6 | SailBoat.auto_migrate! 7 | 8 | @model = SailBoat.new(:id => 1) 9 | @model.should be_valid_for_primitive_test 10 | end 11 | 12 | describe "with invlid value assigned to primitive column" do 13 | before :all do 14 | @model.build_date = 'ABC' 15 | end 16 | 17 | it "is invalid" do 18 | @model.should_not be_valid_for_primitive_test 19 | @model.errors.on(:build_date).should == [ 'Build date must be of type Date' ] 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /spec/integration/automatic_validation/inferred_uniqueness_validation_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/automatic_validation/spec_helper' 3 | 4 | describe 'uniqueness' do 5 | describe 'single attribute' do 6 | before :all do 7 | class UniqueEventsSingle 8 | include DataMapper::Resource 9 | 10 | # storage_names[:default] = 'unique_events_single' 11 | 12 | property :id, Integer, :key => true 13 | property :start_year, Integer, :unique => true 14 | end 15 | UniqueEventsSingle.auto_migrate! 16 | 17 | @existing = UniqueEventsSingle.create(:id => 1, :start_year => 2008) 18 | @new = UniqueEventsSingle.new(:id => 2, :start_year => 2008) 19 | end 20 | 21 | it 'validates' do 22 | @new.should_not be_valid 23 | end 24 | end 25 | 26 | describe 'multiple attributes' do 27 | before :all do 28 | class UniqueEventsMultiple 29 | include DataMapper::Resource 30 | 31 | # storage_names[:default] = 'unique_events_multiple' 32 | 33 | property :id, Integer, :key => true 34 | property :start_year, Integer, :unique => :years 35 | property :stop_year, Integer, :unique => :years 36 | end 37 | UniqueEventsMultiple.auto_migrate! 38 | 39 | @new = UniqueEventsMultiple.new(:id => 1, :start_year => 2008, :stop_year => 2009) 40 | end 41 | 42 | it 'validates uniquness' do 43 | lambda { 44 | @new.should_not be_valid 45 | }.should raise_error(ArgumentError) 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /spec/integration/automatic_validation/inferred_within_validation_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/automatic_validation/spec_helper' 3 | 4 | describe 'A model with a :set & :default options on a property' do 5 | before :all do 6 | class ::LimitedBoat 7 | include DataMapper::Resource 8 | property :id, DataMapper::Property::Serial 9 | property :limited, String, :set => %w[ foo bar bang ], :default => 'foo' 10 | end 11 | 12 | LimitedBoat.finalize 13 | end 14 | 15 | describe "without value on that property" do 16 | before :all do 17 | @model = LimitedBoat.new 18 | end 19 | 20 | # default value is respected 21 | it_should_behave_like "valid model" 22 | end 23 | 24 | describe "without value on that property that is not in allowed range/set" do 25 | before :all do 26 | @model = LimitedBoat.new(:limited => "blah") 27 | end 28 | 29 | it_should_behave_like "invalid model" 30 | 31 | it "has a meaningful error message" do 32 | @model.errors.on(:limited).should == [ 'Limited must be one of foo, bar, bang' ] 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /spec/integration/automatic_validation/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # put validator specific fixture models and helpers here 2 | # 3 | # make sure you check out spec/fixtures to see fixture models 4 | # already written 5 | # 6 | # DataMapper developers feels strongly against foobars in the spec 7 | # suite 8 | 9 | # TODO: one day we need to get rid of this remaining foobarness 10 | # and use a few more realistic models with ParanoidBoolean and all 11 | # that 12 | 13 | class SailBoat 14 | include DataMapper::Resource 15 | 16 | # this one is not Serial intentionally 17 | # use Serial in real world apps 18 | property :id, Integer, :key => true, :min => 1, :max => 10 19 | 20 | property :name, String, :required => true, :validates => :presence_test 21 | property :description, String, :length => 10, :validates => :length_test_1 22 | property :notes, String, :length => 2..10, :validates => :length_test_2 23 | property :no_validation, String, :auto_validation => false 24 | property :salesman, String, :required => true, :validates => [:multi_context_1, :multi_context_2] 25 | property :code, String, :format => Proc.new { |code| code =~ /A\d{4}\z/ }, :validates => :format_test 26 | property :allow_nil, String, :length => 5..10, :required => false, :validates => :nil_test 27 | property :build_date, Date, :validates => :primitive_test 28 | property :float, Float, :precision => 2, :scale => 1 29 | property :big_decimal, Decimal, :precision => 2, :scale => 1 30 | end 31 | 32 | class HasNullableBoolean 33 | include DataMapper::Resource 34 | 35 | # this one is not Serial intentionally 36 | # use Serial in real world apps 37 | property :id, Integer, :key => true 38 | property :bool, Boolean # :required => false by default 39 | end 40 | 41 | class HasRequiredBoolean 42 | include DataMapper::Resource 43 | 44 | # this one is not Serial intentionally 45 | # use Serial in real world apps 46 | property :id, Integer, :key => true 47 | property :bool, Boolean, :required => true 48 | end 49 | 50 | class HasRequiredParanoidBoolean 51 | include DataMapper::Resource 52 | 53 | # this one is not Serial intentionally 54 | # use Serial in real world apps 55 | property :id, Integer, :key => true 56 | property :bool, ParanoidBoolean, :required => true 57 | end 58 | -------------------------------------------------------------------------------- /spec/integration/block_validator/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # make sure you check out spec/fixtures to see fixture models 2 | # already written 3 | # 4 | # DataMapper developers feels strongly against foobars in the spec 5 | # suite 6 | -------------------------------------------------------------------------------- /spec/integration/conditional_validation/if_condition_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/conditional_validation/spec_helper' 3 | 4 | describe 'DataMapper::Validations::Fixtures::UDPPacket' do 5 | before :all do 6 | DataMapper::Validations::Fixtures::UDPPacket.auto_migrate! 7 | 8 | @model = DataMapper::Validations::Fixtures::UDPPacket.new 9 | end 10 | 11 | describe "that is transported encapsulated into IPv4 packet" do 12 | before :all do 13 | @model.underlying_ip_version = 4 14 | end 15 | 16 | describe "and has no checksum" do 17 | before :all do 18 | @model.checksum = nil 19 | end 20 | 21 | it_should_behave_like "valid model" 22 | end 23 | 24 | describe "and has no checksum algorithm" do 25 | before :all do 26 | @model.checksum_algorithm = nil 27 | end 28 | 29 | it_should_behave_like "valid model" 30 | end 31 | end 32 | 33 | 34 | describe "that is transported encapsulated into IPv6 packet" do 35 | before :all do 36 | @model.underlying_ip_version = 6 37 | end 38 | 39 | describe "and has no checksum" do 40 | before :all do 41 | @model.checksum = nil 42 | end 43 | 44 | it_should_behave_like "invalid model" 45 | 46 | it "has a meaningful error message" do 47 | @model.errors.on(:checksum).should == [ 'Checksum is mandatory when used with IPv6' ] 48 | end 49 | end 50 | 51 | describe "and has no checksum algorithm" do 52 | before :all do 53 | @model.checksum_algorithm = nil 54 | end 55 | 56 | it_should_behave_like "invalid model" 57 | 58 | it "has a meaningful error message" do 59 | @model.errors.on(:checksum_algorithm).should == [ 'Checksum is mandatory when used with IPv6' ] 60 | end 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /spec/integration/conditional_validation/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # make sure you check out spec/fixtures to see fixture models 2 | # already written 3 | # 4 | # DataMapper developers feels strongly against foobars in the spec 5 | # suite 6 | -------------------------------------------------------------------------------- /spec/integration/confirmation_validator/confirmation_validator_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/confirmation_validator/spec_helper' 3 | 4 | describe "reservation with mismatched person name", :shared => true do 5 | it "has meaningful error message" do 6 | @model.errors.on(:person_name).should == [ 'Person name does not match the confirmation' ] 7 | end 8 | end 9 | 10 | describe "reservation with mismatched seats number", :shared => true do 11 | it "has meaningful error message" do 12 | # Proc gets expanded here 13 | @model.errors.on(:number_of_seats).should == [ 'Reservation requires confirmation for number_of_seats' ] 14 | end 15 | end 16 | 17 | 18 | describe 'DataMapper::Validations::Fixtures::Reservation' do 19 | before :all do 20 | DataMapper::Validations::Fixtures::Reservation.auto_migrate! 21 | 22 | @model = DataMapper::Validations::Fixtures::Reservation.new(:person_name => "Tyler Durden", 23 | :person_name_confirmation => "Tyler Durden", 24 | :number_of_seats => 2, 25 | :seats_confirmation => 2) 26 | @model.should be_valid 27 | end 28 | 29 | describe "with matching person name and confirmation" do 30 | before :all do 31 | @model.person_name = "mismatch" 32 | end 33 | 34 | it_should_behave_like "invalid model" 35 | it_should_behave_like "reservation with mismatched person name" 36 | end 37 | 38 | 39 | describe "with a blank person name and confirmation" do 40 | before :all do 41 | @model.person_name = "" 42 | end 43 | 44 | it_should_behave_like "invalid model" 45 | it_should_behave_like "reservation with mismatched person name" 46 | end 47 | 48 | 49 | describe "with a missing person name and confirmation" do 50 | before :all do 51 | @model.person_name = nil 52 | end 53 | 54 | it_should_behave_like "invalid model" 55 | it_should_behave_like "reservation with mismatched person name" 56 | end 57 | 58 | 59 | describe "with mismatching number of seats and confirmation" do 60 | before :all do 61 | @model.number_of_seats = -1 62 | end 63 | 64 | it_should_behave_like "invalid model" 65 | it_should_behave_like "reservation with mismatched seats number" 66 | end 67 | 68 | 69 | describe "with a blank number of seats and confirmation" do 70 | before :all do 71 | @model.number_of_seats = nil 72 | end 73 | 74 | it_should_behave_like "valid model" 75 | end 76 | end 77 | -------------------------------------------------------------------------------- /spec/integration/confirmation_validator/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # make sure you check out spec/fixtures to see fixture models 2 | # already written 3 | # 4 | # DataMapper developers feels strongly against foobars in the spec 5 | # suite 6 | -------------------------------------------------------------------------------- /spec/integration/datamapper_models/association_validation_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'DataMapper::Validations::Fixtures::Product' do 4 | before :all do 5 | DataMapper::Validations::Fixtures::ProductCompany.auto_migrate! 6 | DataMapper::Validations::Fixtures::Product.auto_migrate! 7 | 8 | parent_model = DataMapper::Validations::Fixtures::ProductCompany 9 | @parent = parent_model.new(:title => "Apple", :flagship_product => "Macintosh") 10 | @parent.should be_valid 11 | @parent.save.should be_true 12 | 13 | model_model = DataMapper::Validations::Fixtures::Product 14 | @model = model_model.new(:name => "MacBook Pro", :company => @parent) 15 | @model.should be_valid 16 | end 17 | 18 | describe "without company" do 19 | before :all do 20 | @model.company = nil 21 | end 22 | 23 | it_should_behave_like "invalid model" 24 | 25 | it "has a meaningful error message" do 26 | @model.errors.on(:company).should == [ 'Company must not be blank' ] 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /spec/integration/datamapper_models/inheritance_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'DataMapper::Validations::Fixtures::ServiceCompany' do 4 | before :all do 5 | DataMapper::Validations::Fixtures::ServiceCompany.auto_migrate! 6 | 7 | @model = DataMapper::Validations::Fixtures::ServiceCompany.new(:title => "Monsters, Inc.", :area_of_expertise => "Little children's nightmares") 8 | @model.valid? 9 | end 10 | 11 | describe "without title" do 12 | before :all do 13 | @model.title = nil 14 | end 15 | 16 | it_should_behave_like "invalid model" 17 | 18 | it "has a meaningful error message for inherited property" do 19 | @model.errors.on(:title).should == [ 'Company name is a required field' ] 20 | end 21 | end 22 | 23 | describe "without area of expertise" do 24 | before :all do 25 | @model.area_of_expertise = nil 26 | end 27 | 28 | it_should_behave_like "invalid model" 29 | 30 | it "has a meaningful error message for own property" do 31 | @model.errors.on(:area_of_expertise).should == [ 'Area of expertise must not be blank' ] 32 | end 33 | end 34 | end 35 | 36 | 37 | 38 | describe 'DataMapper::Validations::Fixtures::ProductCompany' do 39 | before :all do 40 | DataMapper::Validations::Fixtures::ProductCompany.auto_migrate! 41 | 42 | @model = DataMapper::Validations::Fixtures::ProductCompany.new(:title => "Apple", :flagship_product => "Macintosh") 43 | @model.valid? 44 | end 45 | 46 | it_should_behave_like "valid model" 47 | 48 | describe "without title" do 49 | before :all do 50 | @model.title = nil 51 | end 52 | 53 | it_should_behave_like "invalid model" 54 | 55 | it "has error message from the subclass itself" do 56 | @model.errors.on(:title).should include('Product company must have a name') 57 | end 58 | 59 | # this may or may not be a desired behavior, 60 | # but append vs. replace is a matter of opinion 61 | # anyway 62 | # 63 | # TODO: there should be a way to clear validations for a field 64 | # that subclasses can use 65 | it "has error message from superclass" do 66 | @model.errors.on(:title).should include('Company name is a required field') 67 | end 68 | end 69 | 70 | 71 | describe "without flagship product" do 72 | before :all do 73 | @model.flagship_product = nil 74 | end 75 | 76 | it_should_behave_like "invalid model" 77 | 78 | it "has a meaningful error message for own property" do 79 | @model.errors.on(:flagship_product).should == [ 'Flagship product must not be blank' ] 80 | end 81 | end 82 | end 83 | -------------------------------------------------------------------------------- /spec/integration/dirty_attributes/dirty_attributes_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'DataMapper::Validations::Fixtures::LlamaSpaceship' do 4 | before :all do 5 | DataMapper::Validations::Fixtures::LlamaSpaceship.auto_migrate! 6 | end 7 | 8 | it "validates even non dirty attributes" do 9 | spaceship = DataMapper::Validations::Fixtures::LlamaSpaceship.create(:type => "custom", :color => "pink") 10 | spaceship.type = "standard" 11 | spaceship.should_not be_valid 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/integration/duplicated_validations/duplicated_validations_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | require 'spec_helper' 4 | require 'integration/duplicated_validations/spec_helper' 5 | 6 | describe 'DataMapper::Validations::Fixtures::Page' do 7 | before :all do 8 | DataMapper::Validations::Fixtures::Page.auto_migrate! 9 | 10 | @model = DataMapper::Validations::Fixtures::Page.new(:id => 1024) 11 | end 12 | 13 | describe "without body" do 14 | before :all do 15 | @model.body = nil 16 | end 17 | 18 | it_should_behave_like "invalid model" 19 | 20 | it "does not have duplicated error messages" do 21 | @model.errors.on(:body).should == ["Body must not be blank"] 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /spec/integration/duplicated_validations/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # make sure you check out spec/fixtures to see fixture models 2 | # already written 3 | # 4 | # DataMapper developers feels strongly against foobars in the spec 5 | # suite 6 | -------------------------------------------------------------------------------- /spec/integration/format_validator/format_validator_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/format_validator/spec_helper' 3 | 4 | describe 'DataMapper::Validations::Fixtures::BillOfLading' do 5 | before :all do 6 | DataMapper::Validations::Fixtures::BillOfLading.auto_migrate! 7 | end 8 | 9 | def valid_attributes 10 | { :id => 1, :doc_no => 'A1234', :email => 'user@example.com', :url => 'http://example.com' } 11 | end 12 | 13 | describe "with doc no with value of 'BAD CODE :)'" do 14 | before :all do 15 | @model = DataMapper::Validations::Fixtures::BillOfLading.new(valid_attributes.merge(:doc_no => 'BAD CODE :)')) 16 | end 17 | 18 | it_should_behave_like 'invalid model' 19 | 20 | it "has meaningful error message on invalid field" do 21 | @model.errors.on(:doc_no).should == [ 'Doc no has an invalid format' ] 22 | end 23 | end 24 | 25 | describe "with doc no with value of 'A1234'" do 26 | before :all do 27 | @model = DataMapper::Validations::Fixtures::BillOfLading.new(valid_attributes.merge(:doc_no => 'A1234')) 28 | end 29 | 30 | it_should_behave_like 'valid model' 31 | end 32 | 33 | describe "with doc no with value of 'B123456X12'" do 34 | before :all do 35 | @model = DataMapper::Validations::Fixtures::BillOfLading.new(valid_attributes.merge(:doc_no => 'B123456X12')) 36 | end 37 | 38 | it_should_behave_like 'valid model' 39 | end 40 | 41 | describe "with missing url" do 42 | before :all do 43 | @model = DataMapper::Validations::Fixtures::BillOfLading.new(valid_attributes.except(:url)) 44 | end 45 | 46 | it_should_behave_like 'invalid model' 47 | end 48 | 49 | describe "with blank name" do 50 | before :all do 51 | @model = DataMapper::Validations::Fixtures::BillOfLading.new(valid_attributes.merge(:username => '')) 52 | end 53 | 54 | it_should_behave_like 'valid model' 55 | end 56 | 57 | describe "with blank email" do 58 | before :all do 59 | @model = DataMapper::Validations::Fixtures::BillOfLading.new(valid_attributes.merge(:email => '')) 60 | end 61 | 62 | it_should_behave_like 'valid model' 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /spec/integration/format_validator/regexp_validator_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/format_validator/spec_helper' 3 | 4 | describe 'DataMapper::Validations::Fixtures::BillOfLading' do 5 | before :all do 6 | DataMapper::Validations::Fixtures::BillOfLading.auto_migrate! 7 | end 8 | 9 | def valid_attributes 10 | { :id => 1, :doc_no => 'A1234', :email => 'user@example.com', :url => 'http://example.com' } 11 | end 12 | 13 | describe "with code of 123456" do 14 | before :all do 15 | @model = DataMapper::Validations::Fixtures::BillOfLading.new(valid_attributes.merge(:code => '123456')) 16 | end 17 | 18 | it_should_behave_like 'valid model' 19 | end 20 | 21 | 22 | describe "with code of 12" do 23 | before :all do 24 | @model = DataMapper::Validations::Fixtures::BillOfLading.new(valid_attributes.merge(:code => '12')) 25 | end 26 | 27 | it_should_behave_like 'invalid model' 28 | 29 | it "has a meaningful error message" do 30 | @model.errors.on(:code).should == [ 'Code format is invalid' ] 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /spec/integration/format_validator/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # make sure you check out spec/fixtures to see fixture models 2 | # already written 3 | # 4 | # DataMapper developers feels strongly against foobars in the spec 5 | # suite 6 | -------------------------------------------------------------------------------- /spec/integration/format_validator/url_format_validator_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/format_validator/spec_helper' 3 | 4 | describe 'DataMapper::Validations::Fixtures::BillOfLading' do 5 | before :all do 6 | DataMapper::Validations::Fixtures::BillOfLading.auto_migrate! 7 | end 8 | 9 | def valid_attributes 10 | { :id => 1, :doc_no => 'A1234', :email => 'user@example.com', :url => 'http://example.com' } 11 | end 12 | 13 | invalid_uris = [ 'http:// example.com', 'ftp://example.com', 'http://.com', 'http://', 'test', '...', 14 | # these are valid URIs from RFC perspective, 15 | # but too often not the case for web apps 16 | # 17 | # TODO: add another format that is strictly 18 | # RFC compliant so it can be used, for instance, 19 | # for internal apps that may refer to local domains 20 | # like http://backend:8080 21 | "http://localhost:4000", "http://localhost" ] 22 | 23 | invalid_uris.each do |uri| 24 | describe "with URL of #{uri.inspect}" do 25 | before :all do 26 | @model = DataMapper::Validations::Fixtures::BillOfLading.new(valid_attributes.merge(:url => uri)) 27 | end 28 | 29 | it_should_behave_like "invalid model" 30 | 31 | it "has a meaningful error message" do 32 | @model.errors.on(:url).should == [ 'Url has an invalid format' ] 33 | end 34 | end 35 | end 36 | 37 | # http:// throws an exception in Addressable::URI, so it wouldn't make it to the validation part anyway :) 38 | (invalid_uris - ['http:// example.com', 'http://']).each do |uri| 39 | describe "with dm-type URI of #{uri.inspect}" do 40 | before(:all) do 41 | @model = DataMapper::Validations::Fixtures::SurrenderBillOfLading.new(valid_attributes.merge(:bank_url => uri)) 42 | end 43 | 44 | it_should_behave_like "invalid model" 45 | 46 | it "has a meaningful error message" do 47 | @model.errors.on(:bank_url).should == [ 'Bank url has an invalid format' ] 48 | end 49 | end 50 | end 51 | 52 | [ 'http://apple.com', 53 | 'http://www.apple.com', 54 | "http://apple.com/", 55 | "http://apple.com/iphone", 56 | "http://www.google.com/search?client=safari&rls=en-us&q=LED&ie=UTF-8&oe=UTF-8", 57 | "http://books.google.com", 58 | "http://books.google.com/", 59 | "http://db2.clouds.megacorp.net:8080", 60 | "https://github.com", 61 | "https://github.com/", 62 | "http://www.example.com:8088/never/ending/path/segments/", 63 | "http://db2.clouds.megacorp.net:8080/resources/10", 64 | "http://www.example.com:8088/never/ending/path/segments", 65 | "http://books.google.com/books?id=uSUJ3VhH4BsC&printsec=frontcover&dq=subject:%22+Linguistics+%22&as_brr=3&ei=DAHPSbGQE5rEzATk1sShAQ&rview=1", 66 | "http://books.google.com:80/books?uid=14472359158468915761&rview=1", 67 | "http://books.google.com/books?id=Ar3-TXCYXUkC&printsec=frontcover&rview=1", 68 | "http://books.google.com/books/vp6ae081e454d30f89b6bca94e0f96fc14.js", 69 | "http://www.google.com/images/cleardot.gif", 70 | "http://books.google.com:80/books?id=Ar3-TXCYXUkC&printsec=frontcover&rview=1#PPA5,M1", 71 | "http://www.hulu.com/watch/64923/terminator-the-sarah-connor-chronicles-to-the-lighthouse", 72 | "http://hulu.com:80/browse/popular/tv", 73 | "http://www.hulu.com/watch/62475/the-simpsons-gone-maggie-gone#s-p1-so-i0" 74 | ].each do |uri| 75 | describe "with URL of #{uri.inspect}" do 76 | before :all do 77 | @model = DataMapper::Validations::Fixtures::BillOfLading.new(valid_attributes.merge(:url => uri)) 78 | end 79 | 80 | it_should_behave_like "valid model" 81 | end 82 | 83 | describe "with dm-type URI of #{uri.inspect}" do 84 | before(:all) do 85 | @model = DataMapper::Validations::Fixtures::SurrenderBillOfLading.new(valid_attributes.merge(:bank_url => uri)) 86 | end 87 | 88 | it_should_behave_like "valid model" 89 | end 90 | end 91 | end 92 | -------------------------------------------------------------------------------- /spec/integration/length_validator/default_value_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/length_validator/spec_helper' 3 | 4 | describe 'DataMapper::Validations::Fixtures::BoatDock' do 5 | before :all do 6 | DataMapper::Validations::Fixtures::BoatDock.auto_migrate! 7 | 8 | @model = DataMapper::Validations::Fixtures::BoatDock.new 9 | end 10 | 11 | describe "with default values that are valid" do 12 | it_should_behave_like "valid model" 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/integration/length_validator/equality_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'spec_helper' 4 | require 'integration/length_validator/spec_helper' 5 | 6 | describe "entity with wrong destination MAC address length", :shared => true do 7 | it "has error message with range bounds" do 8 | @model.errors.on(:destination_mac).should == [ 'Destination mac must be 6 characters long' ] 9 | end 10 | end 11 | 12 | 13 | describe 'DataMapper::Validations::Fixtures::EthernetFrame' do 14 | before :all do 15 | DataMapper::Validations::Fixtures::EthernetFrame.auto_migrate! 16 | 17 | @model = DataMapper::Validations::Fixtures::EthernetFrame.valid_instance 18 | @model.link_support_fragmentation = false 19 | end 20 | 21 | it_should_behave_like "valid model" 22 | 23 | describe "with destination MAC 3 'bits' long" do 24 | before :all do 25 | @model.destination_mac = "123" 26 | @model.valid? 27 | end 28 | 29 | it_should_behave_like "invalid model" 30 | 31 | it_should_behave_like "entity with wrong destination MAC address length" 32 | end 33 | 34 | describe "with destination MAC 8 'bits' long" do 35 | before :all do 36 | @model.destination_mac = "123abce8" 37 | @model.valid? 38 | end 39 | 40 | it_should_behave_like "invalid model" 41 | 42 | it_should_behave_like "entity with wrong destination MAC address length" 43 | end 44 | 45 | # arguable but reasonable for 80% of cases 46 | # to treat nil as a 0 lengh value 47 | # reported in 48 | # http://datamapper.lighthouseapp.com/projects/20609/tickets/646 49 | describe "that has no destination MAC address" do 50 | before :all do 51 | @model.destination_mac = nil 52 | @model.valid? 53 | end 54 | 55 | it_should_behave_like "invalid model" 56 | 57 | it_should_behave_like "entity with wrong destination MAC address length" 58 | end 59 | 60 | describe "with a 6 'bits' destination MAC address" do 61 | before :all do 62 | @model.destination_mac = "a1b2c3" 63 | @model.valid? 64 | end 65 | 66 | it_should_behave_like "valid model" 67 | end 68 | 69 | describe "with multibyte characters" do 70 | before :all do 71 | begin 72 | # force normal encoding in this block 73 | original, $KCODE = $KCODE, 'N' if RUBY_VERSION <= '1.8.6' 74 | 75 | # example from: http://intertwingly.net/stories/2004/04/14/i18n.html 76 | @model = DataMapper::Validations::Fixtures::Multibyte.new( 77 | :name => 'Iñtërnâtiônàlizætiøn' 78 | ) 79 | @model.should be_valid 80 | ensure 81 | $KCODE = original if RUBY_VERSION <= '1.8.6' 82 | end 83 | end 84 | 85 | it_should_behave_like "valid model" 86 | end 87 | end 88 | -------------------------------------------------------------------------------- /spec/integration/length_validator/error_message_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/length_validator/spec_helper' 3 | 4 | describe 'DataMapper::Validations::Fixtures::Jabberwock' do 5 | before :all do 6 | DataMapper::Validations::Fixtures::Jabberwock.auto_migrate! 7 | 8 | @model = DataMapper::Validations::Fixtures::Jabberwock.new 9 | end 10 | 11 | describe "without snickersnack" do 12 | before :all do 13 | @model.snickersnack = nil 14 | end 15 | 16 | it_should_behave_like "invalid model" 17 | 18 | it "has custom error message" do 19 | @model.errors.on(:snickersnack).should == [ 'worble warble' ] 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /spec/integration/length_validator/maximum_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/length_validator/spec_helper' 3 | 4 | describe "barcode with invalid code length", :shared => true do 5 | it "has a meaninful error message with length restrictions mentioned" do 6 | @model.errors.on(:code).should == [ 'Code must be at most 10 characters long' ] 7 | end 8 | end 9 | 10 | describe 'DataMapper::Validations::Fixtures::Barcode' do 11 | before :all do 12 | DataMapper::Validations::Fixtures::Barcode.auto_migrate! 13 | 14 | @model = DataMapper::Validations::Fixtures::Barcode.valid_instance 15 | end 16 | 17 | it_should_behave_like "valid model" 18 | 19 | describe "with a 17 characters long code" do 20 | before :all do 21 | @model.code = "18283849284728124" 22 | @model.valid? 23 | end 24 | 25 | it_should_behave_like "invalid model" 26 | 27 | it_should_behave_like "barcode with invalid code length" 28 | end 29 | 30 | describe "with a 7 characters long code" do 31 | before :all do 32 | @model.code = "8372786" 33 | @model.valid? 34 | end 35 | 36 | it_should_behave_like "valid model" 37 | end 38 | 39 | describe "with an 11 characters long code" do 40 | before :all do 41 | @model.code = "83727868754" 42 | @model.valid? 43 | end 44 | 45 | it_should_behave_like "invalid model" 46 | 47 | it_should_behave_like "barcode with invalid code length" 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /spec/integration/length_validator/minimum_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/length_validator/spec_helper' 3 | 4 | describe "entity with a name shorter than 2 characters", :shared => true do 5 | it "has a meaninful error message with length restrictions mentioned" do 6 | @model.errors.on(:name).should == [ 'Name must be at least 2 characters long' ] 7 | end 8 | end 9 | 10 | describe 'DataMapper::Validations::Fixtures::Mittelschnauzer' do 11 | before :all do 12 | DataMapper::Validations::Fixtures::Mittelschnauzer.auto_migrate! 13 | 14 | @model = DataMapper::Validations::Fixtures::Mittelschnauzer.valid_instance 15 | end 16 | 17 | it_should_behave_like "valid model" 18 | 19 | describe "with a 13 characters long name" do 20 | it_should_behave_like "valid model" 21 | end 22 | 23 | describe "with a single character name" do 24 | before :all do 25 | @model.name = "R" 26 | @model.valid? 27 | end 28 | 29 | it_should_behave_like "invalid model" 30 | 31 | it_should_behave_like "entity with a name shorter than 2 characters" 32 | end 33 | 34 | describe "with blank name" do 35 | before :all do 36 | @model.name = "" 37 | @model.valid? 38 | end 39 | 40 | it_should_behave_like "invalid model" 41 | 42 | it_should_behave_like "entity with a name shorter than 2 characters" 43 | end 44 | 45 | describe "persisted, with a single character owner" do 46 | before :all do 47 | @model.save 48 | @model.owner = 'a' 49 | @model.valid? 50 | end 51 | 52 | it_should_behave_like "invalid model" 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /spec/integration/length_validator/range_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/length_validator/spec_helper' 3 | 4 | describe 'DataMapper::Validations::Fixtures::EthernetFrame' do 5 | before :all do 6 | DataMapper::Validations::Fixtures::EthernetFrame.auto_migrate! 7 | 8 | @model = DataMapper::Validations::Fixtures::EthernetFrame.valid_instance 9 | @model.link_support_fragmentation = false 10 | end 11 | 12 | it_should_behave_like "valid model" 13 | 14 | describe "with payload that is 7 'bits' long (too short)" do 15 | before :all do 16 | @model.payload = "1234567" 17 | @model.valid? 18 | end 19 | 20 | it_should_behave_like "invalid model" 21 | 22 | it "has error message with range bounds" do 23 | @model.errors.on(:payload).should == [ 'Payload must be between 46 and 1500 characters long' ] 24 | end 25 | end 26 | 27 | 28 | describe "with a one character long payload (too short)" do 29 | before :all do 30 | @model.payload = 'a' 31 | @model.valid? 32 | end 33 | 34 | it_should_behave_like "invalid model" 35 | 36 | it "has error message with range bounds" do 37 | @model.errors.on(:payload).should == [ 'Payload must be between 46 and 1500 characters long' ] 38 | end 39 | end 40 | 41 | 42 | describe "with a 1600 'bits' long payload (needs fragmentation)" do 43 | before :all do 44 | @model.payload = 'a' 45 | @model.valid? 46 | end 47 | 48 | it_should_behave_like "invalid model" 49 | 50 | it "has error message with range bounds" do 51 | @model.errors.on(:payload).should == [ 'Payload must be between 46 and 1500 characters long' ] 52 | end 53 | end 54 | 55 | 56 | # arguable but reasonable for 80% of cases 57 | # to treat nil as a 0 lengh value 58 | # reported in 59 | # http://datamapper.lighthouseapp.com/projects/20609/tickets/646 60 | describe "that has no payload" do 61 | before :all do 62 | @model.payload = nil 63 | @model.valid? 64 | end 65 | 66 | it_should_behave_like "invalid model" 67 | 68 | it "has error message with range bounds" do 69 | @model.errors.on(:payload).should == [ 'Payload must be between 46 and 1500 characters long' ] 70 | end 71 | end 72 | 73 | 74 | 75 | describe "with a 50 characters long payload" do 76 | before :all do 77 | @model.payload = 'Imagine yourself a beautiful bag full of bits here' 78 | @model.valid? 79 | end 80 | 81 | it_should_behave_like "valid model" 82 | 83 | it "has blank error message" do 84 | @model.errors.on(:payload).should be_nil 85 | end 86 | end 87 | end 88 | -------------------------------------------------------------------------------- /spec/integration/length_validator/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # put validator specific fixture models and helpers here 2 | # 3 | # make sure you check out spec/fixtures to see fixture models 4 | # already written 5 | # 6 | # DataMapper developers feels strongly against foobars in the spec 7 | # suite 8 | -------------------------------------------------------------------------------- /spec/integration/method_validator/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # make sure you check out spec/fixtures to see fixture models 2 | # already written 3 | # 4 | # DataMapper developers feels strongly against foobars in the spec 5 | # suite 6 | -------------------------------------------------------------------------------- /spec/integration/numeric_validator/equality_with_float_type_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/numeric_validator/spec_helper' 3 | 4 | describe 'DataMapper::Validations::Fixtures::BasketballCourt' do 5 | before :all do 6 | DataMapper::Validations::Fixtures::BasketballCourt.auto_migrate! 7 | end 8 | 9 | describe "with valid set of attributes" do 10 | before :all do 11 | @model = DataMapper::Validations::Fixtures::BasketballCourt.valid_instance 12 | @model.valid? 13 | end 14 | 15 | it_should_behave_like "valid model" 16 | end 17 | 18 | 19 | describe "with rim height of 3.05" do 20 | before :all do 21 | @model = DataMapper::Validations::Fixtures::BasketballCourt.valid_instance(:rim_height => 3.05) 22 | @model.valid? 23 | end 24 | 25 | it_should_behave_like "valid model" 26 | end 27 | 28 | 29 | describe "with rim height of 3.30" do 30 | before :all do 31 | @model = DataMapper::Validations::Fixtures::BasketballCourt.valid_instance(:rim_height => 3.30) 32 | @model.valid? 33 | end 34 | 35 | it_should_behave_like "invalid model" 36 | 37 | it "has a meaningful error message" do 38 | @model.errors.on(:rim_height).should == [ 'Rim height must be equal to 3.05' ] 39 | end 40 | end 41 | 42 | 43 | describe "with free throw line distance of 4.57" do 44 | before :all do 45 | @model = DataMapper::Validations::Fixtures::BasketballCourt.valid_instance(:free_throw_line_distance => 4.57) 46 | @model.valid? 47 | end 48 | 49 | it_should_behave_like "valid model" 50 | end 51 | 52 | 53 | describe "with free throw line distance of 3.10" do 54 | before :all do 55 | @model = DataMapper::Validations::Fixtures::BasketballCourt.valid_instance(:free_throw_line_distance => 3.10) 56 | @model.valid? 57 | end 58 | 59 | it_should_behave_like "invalid model" 60 | 61 | it "has a meaningful error message" do 62 | @model.errors.on(:free_throw_line_distance).should == [ 'Free throw line distance must be equal to 4.57' ] 63 | end 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /spec/integration/numeric_validator/equality_with_integer_type_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/numeric_validator/spec_helper' 3 | 4 | describe 'DataMapper::Validations::Fixtures::LerneanHydra' do 5 | before :all do 6 | DataMapper::Validations::Fixtures::LerneanHydra.auto_migrate! 7 | end 8 | 9 | describe "with valid set of attributes" do 10 | before :all do 11 | @model = DataMapper::Validations::Fixtures::LerneanHydra.valid_instance 12 | @model.valid? 13 | end 14 | 15 | it_should_behave_like "valid model" 16 | end 17 | 18 | 19 | describe "with 9 heads" do 20 | before :all do 21 | @model = DataMapper::Validations::Fixtures::LerneanHydra.valid_instance(:head_count => 9) 22 | @model.valid? 23 | end 24 | 25 | it_should_behave_like "valid model" 26 | end 27 | 28 | 29 | describe "with only 3 heads" do 30 | before :all do 31 | @model = DataMapper::Validations::Fixtures::LerneanHydra.valid_instance(:head_count => 3) 32 | @model.valid? 33 | end 34 | 35 | it_should_behave_like "invalid model" 36 | 37 | it "has a meaningful error message" do 38 | @model.errors.on(:head_count).should == [ 'Lernean hydra is said to have exactly 9 heads' ] 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /spec/integration/numeric_validator/float_type_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/numeric_validator/spec_helper' 3 | 4 | describe 'DataMapper::Validations::Fixtures::BasketballPlayer' do 5 | before :all do 6 | DataMapper::Validations::Fixtures::BasketballPlayer.auto_migrate! 7 | 8 | @model = DataMapper::Validations::Fixtures::BasketballPlayer.new(:name => "Michael Jordan", :height => 198.1, :weight => 97.2) 9 | end 10 | 11 | describe "with height as float" do 12 | before :all do 13 | # no op in this case 14 | end 15 | 16 | it_should_behave_like "valid model" 17 | end 18 | 19 | describe "with height as integer" do 20 | before :all do 21 | @model.height = 198 22 | end 23 | 24 | it_should_behave_like "valid model" 25 | end 26 | 27 | describe "with height as string containing only integers" do 28 | before :all do 29 | @model.height = "198" 30 | end 31 | 32 | it_should_behave_like "valid model" 33 | end 34 | 35 | describe "with height as string containing a float" do 36 | before :all do 37 | @model.height = "198.1" 38 | end 39 | 40 | it_should_behave_like "valid model" 41 | end 42 | 43 | describe "with height as string containing a float that will be represented in scientific notation" do 44 | before :all do 45 | @model.height = '0.00004' 46 | end 47 | 48 | it_should_behave_like "valid model" 49 | end 50 | 51 | describe "with height as string containing random alphanumeric characters" do 52 | before :all do 53 | @height = 'height=198.1' 54 | @model.height = "height=198.1" 55 | end 56 | 57 | it "is should not change the value" do 58 | @model.height.should == @height 59 | end 60 | 61 | it_should_behave_like "invalid model" 62 | end 63 | 64 | describe "with height as string containing random punctuation characters" do 65 | before :all do 66 | @height = '$$ * $?' 67 | @model.height = @height 68 | end 69 | 70 | it "is should not change the value" do 71 | @model.height.should == @height 72 | end 73 | 74 | it_should_behave_like "invalid model" 75 | end 76 | 77 | describe "with nil height" do 78 | before :all do 79 | @model.height = nil 80 | @model.valid? 81 | end 82 | 83 | # typecasting kicks in 84 | it_should_behave_like "invalid model" 85 | 86 | it "has a meaningful error message" do 87 | @model.errors.on(:height).should == [ 'Height must be a number' ] 88 | end 89 | end 90 | end 91 | -------------------------------------------------------------------------------- /spec/integration/numeric_validator/gt_with_float_type_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/numeric_validator/spec_helper' 3 | 4 | describe 'DataMapper::Validations::Fixtures::BasketballCourt' do 5 | before :all do 6 | DataMapper::Validations::Fixtures::BasketballCourt.auto_migrate! 7 | 8 | @model = DataMapper::Validations::Fixtures::BasketballCourt.valid_instance 9 | @model.valid? 10 | end 11 | 12 | it_should_behave_like "valid model" 13 | 14 | 15 | describe "with three point line distance of 7.2" do 16 | before :all do 17 | @model.three_point_line_distance = 7.2 18 | @model.valid? 19 | end 20 | 21 | it_should_behave_like "valid model" 22 | end 23 | 24 | 25 | describe "with three point line distance of 3.5" do 26 | before :all do 27 | @model.three_point_line_distance = 3.5 28 | @model.valid? 29 | end 30 | 31 | it_should_behave_like "invalid model" 32 | 33 | it "has a meaningful error message" do 34 | @model.errors.on(:three_point_line_distance).should == [ 'Three point line distance must be greater than 6.7' ] 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /spec/integration/numeric_validator/gte_with_float_type_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/numeric_validator/spec_helper' 3 | 4 | describe 'DataMapper::Validations::Fixtures::BasketballCourt' do 5 | before :all do 6 | DataMapper::Validations::Fixtures::BasketballCourt.auto_migrate! 7 | 8 | @model = DataMapper::Validations::Fixtures::BasketballCourt.valid_instance 9 | @model.valid? 10 | end 11 | 12 | it_should_behave_like "valid model" 13 | 14 | 15 | describe "with length of 15.0" do 16 | before :all do 17 | @model.length = 15.0 18 | @model.valid? 19 | end 20 | 21 | it_should_behave_like "valid model" 22 | end 23 | 24 | 25 | describe "with length of 14.0" do 26 | before :all do 27 | @model.length = 14.0 28 | @model.valid? 29 | end 30 | 31 | it_should_behave_like "invalid model" 32 | 33 | it "has a meaningful error message" do 34 | @model.errors.on(:length).should == [ 'Length must be greater than or equal to 15.0' ] 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /spec/integration/numeric_validator/integer_only_true_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/numeric_validator/spec_helper' 3 | 4 | describe 'Country' do 5 | before do 6 | Country.auto_migrate! 7 | 8 | @country = Country.new(:name => "Italy", :area => "301318") 9 | end 10 | 11 | describe "with area as integer" do 12 | before do 13 | # no op in this case 14 | end 15 | 16 | it "is valid" do 17 | @country.should be_valid 18 | end 19 | end 20 | 21 | 22 | describe "with area as integer" do 23 | before do 24 | @country.area = 1603 25 | end 26 | 27 | it "is valid" do 28 | @country.should be_valid 29 | end 30 | end 31 | 32 | 33 | describe "with area as string containing only integers" do 34 | before do 35 | @country.area = "301318" 36 | end 37 | 38 | it "is valid" do 39 | @country.should be_valid 40 | end 41 | end 42 | 43 | 44 | describe "with area as string containing a float" do 45 | before do 46 | @country.area = "301318.6" 47 | end 48 | 49 | it "IS valid" do 50 | @country.should be_valid 51 | end 52 | end 53 | 54 | 55 | describe "with area as string containing random alphanumeric characters" do 56 | before do 57 | @country.area = "area=51" 58 | end 59 | 60 | it "IS NOT valid" do 61 | @country.should_not be_valid 62 | end 63 | end 64 | 65 | 66 | describe "with area as string containing random punctuation characters" do 67 | before do 68 | @country.area = "$$ * $?" 69 | end 70 | 71 | it "IS NOT valid" do 72 | @country.should_not be_valid 73 | end 74 | end 75 | 76 | 77 | describe "with unknown area" do 78 | before do 79 | @country.area = nil 80 | end 81 | 82 | it "is NOT valid" do 83 | @country.should_not be_valid 84 | end 85 | 86 | it "has a meaningful error message on for the property" do 87 | @country.valid? 88 | @country.errors.on(:area).should == [ 'Please use integers to specify area' ] 89 | end 90 | end 91 | end 92 | -------------------------------------------------------------------------------- /spec/integration/numeric_validator/integer_type_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/numeric_validator/spec_helper' 3 | 4 | describe 'City' do 5 | before do 6 | City.auto_migrate! 7 | 8 | @city = City.new(:name => "Tokyo", :founded_in => 1603) 9 | end 10 | 11 | describe "with foundation year as integer" do 12 | before do 13 | # no op in this case 14 | end 15 | 16 | it "is valid" do 17 | @city.should be_valid 18 | end 19 | end 20 | 21 | 22 | describe "with foundation year as integer" do 23 | before do 24 | @city.founded_in = 1603 25 | end 26 | 27 | it "is valid" do 28 | @city.should be_valid 29 | end 30 | end 31 | 32 | 33 | describe "with foundation year as string containing only integers" do 34 | before do 35 | @city.founded_in = "1603" 36 | end 37 | 38 | it "is valid" do 39 | @city.should be_valid 40 | end 41 | end 42 | 43 | 44 | describe "with foundation year as string containing a float" do 45 | before do 46 | @city.founded_in = "1603.6" 47 | end 48 | 49 | it "is valid" do 50 | @city.should be_valid 51 | end 52 | end 53 | 54 | 55 | describe "with foundation year as string that is not an integer or float" do 56 | before do 57 | @string = "founded-in=1603" 58 | 59 | @city.founded_in = @string 60 | end 61 | 62 | it "is not altered" do 63 | @city.founded_in.should be(@string) 64 | end 65 | 66 | it "IS NOT valid" do 67 | @city.should_not be_valid 68 | end 69 | end 70 | 71 | 72 | describe "with unknown foundation date" do 73 | before do 74 | @city.founded_in = nil 75 | end 76 | 77 | it "is NOT valid" do 78 | @city.should_not be_valid 79 | end 80 | 81 | it "has a meaningful error message on for the property" do 82 | @city.valid? 83 | @city.errors.on(:founded_in).should == [ 'Foundation year must be an integer' ] 84 | end 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /spec/integration/numeric_validator/lt_with_float_type_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/numeric_validator/spec_helper' 3 | 4 | describe 'DataMapper::Validations::Fixtures::BasketballCourt' do 5 | before :all do 6 | DataMapper::Validations::Fixtures::BasketballCourt.auto_migrate! 7 | 8 | @model = DataMapper::Validations::Fixtures::BasketballCourt.valid_instance 9 | @model.valid? 10 | end 11 | 12 | it_should_behave_like "valid model" 13 | 14 | 15 | describe "with three point line distance of 6.8" do 16 | before :all do 17 | @model.three_point_line_distance = 6.8 18 | @model.valid? 19 | end 20 | 21 | it_should_behave_like "valid model" 22 | end 23 | 24 | 25 | describe "with three point line distance of 10.0" do 26 | before :all do 27 | @model.three_point_line_distance = 10.0 28 | @model.valid? 29 | end 30 | 31 | it_should_behave_like "invalid model" 32 | 33 | it "has a meaningful error message" do 34 | @model.errors.on(:three_point_line_distance).should == [ 'Three point line distance must be less than 7.24' ] 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /spec/integration/numeric_validator/lte_with_float_type_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/numeric_validator/spec_helper' 3 | 4 | describe 'DataMapper::Validations::Fixtures::BasketballCourt' do 5 | before :all do 6 | DataMapper::Validations::Fixtures::BasketballCourt.auto_migrate! 7 | 8 | @model = DataMapper::Validations::Fixtures::BasketballCourt.valid_instance 9 | @model.valid? 10 | end 11 | 12 | it_should_behave_like "valid model" 13 | 14 | 15 | describe "with length of 15.24" do 16 | before :all do 17 | @model.length = 15.24 18 | @model.valid? 19 | end 20 | 21 | it_should_behave_like "valid model" 22 | end 23 | 24 | 25 | describe "with length of 20.0" do 26 | before :all do 27 | @model.length = 20.0 28 | @model.valid? 29 | end 30 | 31 | it_should_behave_like "invalid model" 32 | 33 | it "has a meaningful error message" do 34 | @model.errors.on(:length).should == [ 'Length must be less than or equal to 15.24' ] 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /spec/integration/numeric_validator/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # make sure you check out spec/fixtures to see fixture models 2 | # already written 3 | # 4 | # DataMapper developers feels strongly against foobars in the spec 5 | # suite 6 | -------------------------------------------------------------------------------- /spec/integration/primitive_validator/primitive_validator_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/primitive_validator/spec_helper' 3 | 4 | describe 'DataMapper::Validations::Fixtures::MemoryObject' do 5 | include DataMapper::Validations::Fixtures 6 | 7 | before :all do 8 | DataMapper::Validations::Fixtures::MemoryObject.auto_migrate! 9 | 10 | @model = DataMapper::Validations::Fixtures::MemoryObject.new 11 | end 12 | 13 | describe "with color given as a string" do 14 | before :all do 15 | @model.color = "grey" 16 | end 17 | 18 | it "is valid" do 19 | @model.should be_valid 20 | end 21 | end 22 | 23 | 24 | describe "with color given as an object" do 25 | before :all do 26 | # we have to go through the back door 27 | # since writer= method does typecasting 28 | # and Object is casted to String 29 | @model.instance_variable_set(:@color, Object.new) 30 | end 31 | 32 | it "is NOT valid" do 33 | @model.should_not be_valid 34 | end 35 | end 36 | 37 | describe "with stupid integer given as Integer" do 38 | before :all do 39 | @model.stupid_integer = 100 40 | end 41 | 42 | it "is valid" do 43 | @model.should be_valid 44 | end 45 | end 46 | 47 | describe "with stupid integer given as Object" do 48 | before :all do 49 | @model.stupid_integer = Object.new 50 | end 51 | 52 | it "is NOT valid" do 53 | @model.should_not be_valid 54 | end 55 | end 56 | 57 | 58 | describe "with mark flag set to true" do 59 | before :all do 60 | @model.marked = true 61 | end 62 | 63 | it "is valid" do 64 | @model.should be_valid 65 | end 66 | end 67 | 68 | 69 | describe "with mark flag set to false" do 70 | before :all do 71 | @model.marked = false 72 | end 73 | 74 | it "is valid" do 75 | @model.should be_valid 76 | end 77 | end 78 | 79 | describe "with mark flag set to an object" do 80 | before :all do 81 | # go through the back door to avoid typecasting 82 | @model.instance_variable_set(:@marked, Object.new) 83 | end 84 | 85 | it "is NOT valid" do 86 | @model.should_not be_valid 87 | end 88 | end 89 | 90 | 91 | describe "with color set to nil" do 92 | before :all do 93 | # go through the back door to avoid typecasting 94 | @model.color = nil 95 | end 96 | 97 | it "is valid" do 98 | @model.should be_valid 99 | end 100 | end 101 | 102 | 103 | describe "with mark flag set to nil" do 104 | before :all do 105 | @model.marked = nil 106 | end 107 | 108 | it "is valid" do 109 | @model.should be_valid 110 | end 111 | end 112 | end 113 | -------------------------------------------------------------------------------- /spec/integration/primitive_validator/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # make sure you check out spec/fixtures to see fixture models 2 | # already written 3 | # 4 | # DataMapper developers feels strongly against foobars in the spec 5 | # suite 6 | -------------------------------------------------------------------------------- /spec/integration/pure_ruby_objects/plain_old_ruby_object_validation_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | module PureRubyObjects 4 | # notice that it is a pure Ruby class, not a DataMapper resource 5 | class Country 6 | # 7 | # Behaviors 8 | # 9 | 10 | include DataMapper::Validations 11 | 12 | # 13 | # Validations 14 | # 15 | 16 | validates_presence_of :name, :when => [:default, :adding_to_encyclopedia] 17 | validates_presence_of :population, :when => :adding_to_encyclopedia, :message => Proc.new { |record| 18 | "population really needs to be specified when adding %s to encyclopedia" % [record.class.name] 19 | } 20 | 21 | validates_length_of :name, :in => (4..50) 22 | 23 | # 24 | # API 25 | # 26 | 27 | attr_accessor :name, :population 28 | 29 | def initialize(name, population = nil) 30 | @name = name 31 | @population = population 32 | end 33 | end 34 | end 35 | 36 | describe 'PureRubyObjects::Country' do 37 | before do 38 | # Powerset says so 39 | @model = PureRubyObjects::Country.new("Italy", 58_147_733) 40 | end 41 | 42 | describe "without name" do 43 | before do 44 | @model.name = nil 45 | end 46 | 47 | it_should_behave_like "object invalid in default context" 48 | 49 | it "is not valid in encyclopedia context" do 50 | @model.should_not be_valid(:adding_to_encyclopedia) 51 | @model.should_not be_valid_for_adding_to_encyclopedia 52 | end 53 | end 54 | 55 | 56 | describe "without name and without population information" do 57 | before do 58 | @model.name = nil 59 | @model.population = nil 60 | end 61 | 62 | it_should_behave_like "object invalid in default context" 63 | 64 | it "is not valid in encyclopedia context" do 65 | @model.should_not be_valid(:adding_to_encyclopedia) 66 | @model.should_not be_valid_for_adding_to_encyclopedia 67 | end 68 | 69 | it "has a meaningful error message" do 70 | # trigger validation => have errors on the object 71 | @model.valid_for_adding_to_encyclopedia? 72 | @model.errors.on(:population).should == ["population really needs to be specified when adding PureRubyObjects::Country to encyclopedia"] 73 | end 74 | end 75 | 76 | 77 | describe "with name and without population information" do 78 | before do 79 | @model.population = nil 80 | end 81 | 82 | it_should_behave_like "object valid in default context" 83 | 84 | it "is not valid in encyclopedia context" do 85 | @model.should_not be_valid(:adding_to_encyclopedia) 86 | @model.should_not be_valid_for_adding_to_encyclopedia 87 | end 88 | end 89 | 90 | 91 | describe "with name and population information" do 92 | it_should_behave_like "object valid in default context" 93 | 94 | it "is valid in encyclopedia context" do 95 | @model.should be_valid(:adding_to_encyclopedia) 96 | @model.should be_valid_for_adding_to_encyclopedia 97 | end 98 | end 99 | 100 | 101 | describe "with a 2 characters long name" do 102 | before do 103 | @model.name = "It" 104 | @model.valid? 105 | end 106 | 107 | it_should_behave_like "object invalid in default context" 108 | 109 | it "has errors on name" do 110 | @model.errors.on(:name).should_not be_empty 111 | end 112 | 113 | it "is valid in encyclopedia context" do 114 | @model.should be_valid(:adding_to_encyclopedia) 115 | @model.should be_valid_for_adding_to_encyclopedia 116 | end 117 | end 118 | end 119 | -------------------------------------------------------------------------------- /spec/integration/required_field_validator/association_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/required_field_validator/spec_helper' 3 | 4 | describe 'required_field_validator/association_spec' do 5 | 6 | before :all do 7 | 8 | class ::Artist 9 | 10 | include DataMapper::Resource 11 | 12 | property :id, Serial 13 | property :name, String, :auto_validation => false 14 | 15 | has n, :albums 16 | 17 | validates_presence_of :name 18 | 19 | end 20 | 21 | class ::Album 22 | 23 | include DataMapper::Resource 24 | 25 | property :id, Serial 26 | property :name, String, :auto_validation => false 27 | property :artist_id, Integer, :index => :artist 28 | 29 | belongs_to :artist 30 | 31 | validates_presence_of :name, :artist 32 | 33 | end 34 | 35 | Artist.auto_migrate! 36 | Album.auto_migrate! 37 | end 38 | 39 | 40 | describe 'Album' do 41 | 42 | before do 43 | @artist = Artist.create(:name => "Oceanlab") 44 | @album = @artist.albums.new(:name => "Sirens of the sea") 45 | end 46 | 47 | describe 'with a missing artist' do 48 | before do 49 | @album.artist = nil 50 | end 51 | 52 | it 'is not valid' do 53 | @album.should_not be_valid 54 | end 55 | 56 | it 'has a meaninful error messages on association key property' do 57 | @album.valid? 58 | @album.errors.on(:artist).should == [ 'Artist must not be blank' ] 59 | end 60 | end 61 | 62 | describe 'with specified artist and name' do 63 | it 'is valid' do 64 | @album.should be_valid 65 | end 66 | end 67 | end 68 | 69 | end 70 | -------------------------------------------------------------------------------- /spec/integration/required_field_validator/date_type_value_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/required_field_validator/spec_helper' 3 | 4 | describe 'required_field_validator/date_type_value_spec' do 5 | 6 | class Holiday 7 | # 8 | # Behaviors 9 | # 10 | 11 | include DataMapper::Resource 12 | 13 | # 14 | # Properties 15 | # 16 | 17 | property :id, Serial 18 | property :on, Date, :auto_validation => false 19 | 20 | # 21 | # Validations 22 | # 23 | 24 | validates_presence_of :on 25 | end 26 | 27 | describe 'Holiday' do 28 | before :all do 29 | Holiday.auto_migrate! 30 | end 31 | 32 | before do 33 | @ny09 = Holiday.new(:on => Date.new(2008, 12, 31)) 34 | @ny09.should be_valid 35 | end 36 | 37 | 38 | describe "with on = nil" do 39 | before do 40 | @ny09.on = nil 41 | end 42 | 43 | it "is NOT valid" do 44 | # nil = missing for Date value 45 | # and Holiday only has default validation context 46 | @ny09.should_not be_valid 47 | 48 | # sanity check 49 | @ny09.on = Date.new(2008, 12, 31) 50 | @ny09.should be_valid 51 | end 52 | end 53 | 54 | 55 | describe "with on = valid date" do 56 | before do 57 | @ny09.on = 0.0 58 | end 59 | 60 | it "IS valid" do 61 | # yes, presence validator does not care 62 | @ny09.should be_valid 63 | end 64 | end 65 | 66 | 67 | 68 | describe "with on = 0" do 69 | before do 70 | @ny09.on = 0 71 | end 72 | 73 | it "IS valid" do 74 | # yes, presence validator does not care 75 | @ny09.should be_valid 76 | end 77 | end 78 | 79 | 80 | 81 | describe "with on = 100" do 82 | before do 83 | @ny09.on = 100 84 | end 85 | 86 | it "IS valid" do 87 | @ny09.should be_valid 88 | end 89 | end 90 | 91 | 92 | describe "with on = 100.0" do 93 | before do 94 | @ny09.on = 100.0 95 | end 96 | 97 | it "IS valid" do 98 | @ny09.should be_valid 99 | end 100 | end 101 | 102 | 103 | describe "with on = -1100" do 104 | before do 105 | # presence validator does not care 106 | @ny09.on = -1100 107 | end 108 | 109 | it "IS valid" do 110 | @ny09.should be_valid 111 | end 112 | end 113 | 114 | 115 | describe "with on = -1100.5" do 116 | before do 117 | # presence validator does not care 118 | @ny09.on = -1100.5 119 | end 120 | 121 | it "IS valid" do 122 | @ny09.should be_valid 123 | end 124 | end 125 | end 126 | 127 | end 128 | -------------------------------------------------------------------------------- /spec/integration/required_field_validator/datetime_type_value_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/required_field_validator/spec_helper' 3 | 4 | describe 'required_field_validator/datetime_type_value_spec' do 5 | 6 | class ScheduledOperation 7 | # 8 | # Behaviors 9 | # 10 | 11 | include DataMapper::Resource 12 | 13 | # 14 | # Properties 15 | # 16 | 17 | property :id, Serial 18 | property :at, DateTime, :auto_validation => false 19 | 20 | # 21 | # Validations 22 | # 23 | 24 | validates_presence_of :at 25 | end 26 | 27 | describe 'ScheduledOperation' do 28 | before :all do 29 | ScheduledOperation.auto_migrate! 30 | end 31 | 32 | before do 33 | @operation = ScheduledOperation.new(:at => DateTime.civil(2008, 06, 07, 15, 00, 00)) 34 | @operation.should be_valid 35 | end 36 | 37 | 38 | describe "with on = nil" do 39 | before do 40 | @operation.at = nil 41 | end 42 | 43 | it "is NOT valid" do 44 | # nil = missing for Date value 45 | # and ScheduledOperation only has default validation context 46 | @operation.should_not be_valid 47 | 48 | # sanity check 49 | @operation.at = Date.new(2008, 12, 31) 50 | @operation.should be_valid 51 | end 52 | end 53 | 54 | 55 | describe "with on = valid date" do 56 | before do 57 | @operation.at = 0.0 58 | end 59 | 60 | it "IS valid" do 61 | # yes, presence validator does not care 62 | @operation.should be_valid 63 | end 64 | end 65 | 66 | 67 | 68 | describe "with on = 0" do 69 | before do 70 | @operation.at = 0 71 | end 72 | 73 | it "IS valid" do 74 | # yes, presence validator does not care 75 | @operation.should be_valid 76 | end 77 | end 78 | 79 | 80 | 81 | describe "with on = 100" do 82 | before do 83 | @operation.at = 100 84 | end 85 | 86 | it "IS valid" do 87 | @operation.should be_valid 88 | end 89 | end 90 | 91 | 92 | describe "with on = 100.0" do 93 | before do 94 | @operation.at = 100.0 95 | end 96 | 97 | it "IS valid" do 98 | @operation.should be_valid 99 | end 100 | end 101 | 102 | 103 | describe "with on = -1100" do 104 | before do 105 | # presence validator does not care 106 | @operation.at = -1100 107 | end 108 | 109 | it "IS valid" do 110 | @operation.should be_valid 111 | end 112 | end 113 | 114 | 115 | describe "with on = -1100.5" do 116 | before do 117 | # presence validator does not care 118 | @operation.at = -1100.5 119 | end 120 | 121 | it "IS valid" do 122 | @operation.should be_valid 123 | end 124 | end 125 | end 126 | 127 | end 128 | -------------------------------------------------------------------------------- /spec/integration/required_field_validator/float_type_value_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/required_field_validator/spec_helper' 3 | 4 | describe 'required_field_validator/float_type_value_spec' do 5 | 6 | # 7 | # Especially stupid example since Hg adds local repository revision 8 | # to each new commit, but lets roll on with this SCM-ish classes and 9 | # still show how Integer type values are validated for presence 10 | # 11 | class CpuConsumption 12 | # 13 | # Behaviors 14 | # 15 | 16 | include DataMapper::Resource 17 | 18 | # 19 | # Properties 20 | # 21 | 22 | property :id, Serial 23 | property :percent, Float, :auto_validation => false 24 | 25 | # 26 | # Validations 27 | # 28 | 29 | validates_presence_of :percent 30 | end 31 | 32 | describe 'CpuConsumption' do 33 | before :all do 34 | CpuConsumption.auto_migrate! 35 | end 36 | 37 | before do 38 | @metric = CpuConsumption.new(:percent => 20.0) 39 | @metric.should be_valid 40 | end 41 | 42 | describe "with percentage = 0.0" do 43 | before do 44 | @metric.percent = 0.0 45 | end 46 | 47 | it "IS valid" do 48 | # yes, presence validator does not care 49 | @metric.should be_valid 50 | end 51 | end 52 | 53 | 54 | 55 | describe "with percentage = 0" do 56 | before do 57 | @metric.percent = 0 58 | end 59 | 60 | it "IS valid" do 61 | # yes, presence validator does not care 62 | @metric.should be_valid 63 | end 64 | end 65 | 66 | 67 | 68 | describe "with percentage = 100" do 69 | before do 70 | @metric.percent = 100 71 | end 72 | 73 | it "IS valid" do 74 | @metric.should be_valid 75 | end 76 | end 77 | 78 | 79 | describe "with percentage = 100.0" do 80 | before do 81 | @metric.percent = 100.0 82 | end 83 | 84 | it "IS valid" do 85 | @metric.should be_valid 86 | end 87 | end 88 | 89 | 90 | describe "with percentage = -1100" do 91 | before do 92 | # presence validator does not care 93 | @metric.percent = -1100 94 | end 95 | 96 | it "IS valid" do 97 | @metric.should be_valid 98 | end 99 | end 100 | 101 | 102 | describe "with percentage = -1100.5" do 103 | before do 104 | # presence validator does not care 105 | @metric.percent = -1100.5 106 | end 107 | 108 | it "IS valid" do 109 | @metric.should be_valid 110 | end 111 | end 112 | 113 | 114 | describe "with percentage = nil" do 115 | before do 116 | @metric.percent = nil 117 | end 118 | 119 | it "is NOT valid" do 120 | # nil = missing for float value 121 | # and CpuConsumption only has default validation context 122 | @metric.should_not be_valid 123 | 124 | # sanity check 125 | @metric.percent = 100 126 | @metric.should be_valid 127 | end 128 | end 129 | end 130 | 131 | end 132 | -------------------------------------------------------------------------------- /spec/integration/required_field_validator/integer_type_value_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/required_field_validator/spec_helper' 3 | 4 | describe 'required_field_validator/integer_type_value_spec' do 5 | 6 | # 7 | # Especially stupid example since Hg adds local repository revision 8 | # to each new commit, but lets roll on with this SCM-ish classes and 9 | # still show how Integer type values are validated for presence 10 | # 11 | class HgCommit < ScmOperation 12 | # 13 | # Properties 14 | # 15 | 16 | property :local_repo_revision_num, Integer, :auto_validation => false 17 | 18 | # 19 | # Validations 20 | # 21 | 22 | validates_presence_of :local_repo_revision_num 23 | end 24 | 25 | describe 'HgCommit' do 26 | before :all do 27 | HgCommit.auto_migrate! 28 | end 29 | 30 | before do 31 | @operation = HgCommit.new(:local_repo_revision_num => 90, :name => "ci") 32 | @operation.should be_valid 33 | end 34 | 35 | describe "with local revision number = 0" do 36 | before do 37 | @operation.local_repo_revision_num = 0 38 | end 39 | 40 | it "IS valid" do 41 | # yes, presence validator does not care 42 | @operation.should be_valid 43 | end 44 | end 45 | 46 | 47 | 48 | describe "with local revision number = 100" do 49 | before do 50 | @operation.local_repo_revision_num = 100 51 | end 52 | 53 | it "IS valid" do 54 | @operation.should be_valid 55 | end 56 | end 57 | 58 | 59 | describe "with local revision number = 100.0 (float!)" do 60 | before do 61 | @operation.local_repo_revision_num = 100.0 62 | end 63 | 64 | it "IS valid" do 65 | @operation.should be_valid 66 | end 67 | end 68 | 69 | 70 | describe "with local revision number = -1100" do 71 | before do 72 | # presence validator does not care 73 | @operation.local_repo_revision_num = -1100 74 | end 75 | 76 | it "IS valid" do 77 | @operation.should be_valid 78 | end 79 | end 80 | 81 | 82 | describe "with local revision number = nil" do 83 | before do 84 | @operation.local_repo_revision_num = nil 85 | end 86 | 87 | it "is NOT valid" do 88 | # nil = missing for integer value 89 | # and HgCommit only has default validation context 90 | @operation.should_not be_valid 91 | 92 | # sanity check 93 | @operation.local_repo_revision_num = 100 94 | @operation.should be_valid 95 | end 96 | end 97 | end 98 | 99 | end 100 | -------------------------------------------------------------------------------- /spec/integration/required_field_validator/plain_old_ruby_object_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/required_field_validator/spec_helper' 3 | 4 | describe 'required_field_validator/plain_old_ruby_object_spec' do 5 | 6 | describe "A plain old Ruby object (not a DM resource)" do 7 | before do 8 | class PlainClass 9 | extend DataMapper::Validations::ClassMethods 10 | include DataMapper::Validations 11 | attr_accessor :accessor 12 | validates_presence_of :here, :empty, :nil, :accessor 13 | def here; "here" end 14 | def empty; "" end 15 | def nil; nil end 16 | end 17 | 18 | @pc = PlainClass.new 19 | end 20 | 21 | it "should fail validation with empty, nil, or blank fields" do 22 | @pc.should_not be_valid 23 | @pc.errors.on(:empty).should == [ 'Empty must not be blank' ] 24 | @pc.errors.on(:nil).should == [ 'Nil must not be blank' ] 25 | @pc.errors.on(:accessor).should == [ 'Accessor must not be blank' ] 26 | end 27 | 28 | it "giving accessor a value should remove validation error" do 29 | @pc.accessor = "full" 30 | @pc.valid? 31 | @pc.errors.on(:accessor).should be_nil 32 | end 33 | end 34 | 35 | end 36 | -------------------------------------------------------------------------------- /spec/integration/required_field_validator/shared_examples.rb: -------------------------------------------------------------------------------- 1 | describe 'GitOperation' do 2 | before do 3 | GitOperation.auto_migrate! 4 | 5 | @operation = GitOperation.new 6 | end 7 | 8 | describe "unnamed SCM operation", :shared => true do 9 | before do 10 | @operation.name = nil 11 | @operation.valid? 12 | end 13 | 14 | it "is not valid" do 15 | @operation.should_not be_valid 16 | end 17 | 18 | it "is not valid in default validation context" do 19 | @operation.should_not be_valid(:default) 20 | end 21 | 22 | it "points to blank name in the error message" do 23 | @operation.errors.on(:name).should == [ 'Name must not be blank' ] 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /spec/integration/required_field_validator/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # make sure you check out spec/fixtures to see fixture models 2 | # already written 3 | # 4 | # DataMapper developers feels strongly against foobars in the spec 5 | # suite 6 | 7 | require 'integration/required_field_validator/shared_examples' 8 | -------------------------------------------------------------------------------- /spec/integration/required_field_validator/text_type_value_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'integration/required_field_validator/spec_helper' 3 | 4 | describe 'required_field_validator/text_type_value_spec' do 5 | 6 | # keep in mind any ScmOperation has a default value for brand property 7 | # so it is used 8 | describe 'GitOperation' do 9 | before :all do 10 | GitOperation.auto_migrate! 11 | end 12 | 13 | before do 14 | @operation = GitOperation.new(:network_connection => true, 15 | :clean_working_copy => true, 16 | :message => "I did it! I did it!! Hell yeah!!!") 17 | end 18 | 19 | describe "with empty message" do 20 | before do 21 | @operation.message = "" 22 | end 23 | 24 | it "is NOT valid for committing" do 25 | # empty string is not considered present for 26 | # a text value 27 | @operation.should_not be_valid_for_committing 28 | 29 | # sanity check since this empty vs blank vs nil 30 | # thing is a shaky ground 31 | @operation.message = "RUBY ON RAILS CAN SCALE NOW!!! w00t!!!" 32 | @operation.should be_valid_for_committing 33 | end 34 | 35 | it "IS valid for pushing" do 36 | @operation.should be_valid_for_pushing 37 | end 38 | 39 | it "IS valid for pulling" do 40 | @operation.should be_valid_for_pulling 41 | end 42 | 43 | it "is not valid in default context" do 44 | @operation.should_not be_valid 45 | end 46 | end 47 | end 48 | 49 | end 50 | -------------------------------------------------------------------------------- /spec/integration/shared/default_validation_context.rb: -------------------------------------------------------------------------------- 1 | describe "object invalid in default context", :shared => true do 2 | it "is not valid in default context" do 3 | @model.should_not be_valid 4 | @model.should_not be_valid(:default) 5 | end 6 | end 7 | 8 | describe "object valid in default context", :shared => true do 9 | it "is valid in default context" do 10 | @model.should be_valid 11 | @model.should be_valid(:default) 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/integration/shared/valid_and_invalid_model.rb: -------------------------------------------------------------------------------- 1 | describe "valid model", :shared => true do 2 | before do 3 | @model.valid? 4 | end 5 | 6 | it "is valid" do 7 | @model.should be_valid 8 | end 9 | 10 | it "has no error messages" do 11 | @model.errors.should be_empty 12 | end 13 | 14 | it "has empty list of full error messages" do 15 | @model.errors.full_messages.should be_empty 16 | end 17 | end 18 | 19 | describe "invalid model", :shared => true do 20 | before do 21 | @model.valid? 22 | end 23 | 24 | it "is NOT valid" do 25 | @model.should_not be_valid 26 | end 27 | 28 | it "has error messages" do 29 | @model.errors.should_not be_empty 30 | end 31 | 32 | it "has list of full error messages" do 33 | @model.errors.full_messages.should_not be_empty 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /spec/integration/uniqueness_validator/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # make sure you check out spec/fixtures to see fixture models 2 | # already written 3 | # 4 | # DataMapper developers feels strongly against foobars in the spec 5 | # suite 6 | -------------------------------------------------------------------------------- /spec/integration/within_validator/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # make sure you check out spec/fixtures to see fixture models 2 | # already written 3 | # 4 | # DataMapper developers feels strongly against foobars in the spec 5 | # suite 6 | -------------------------------------------------------------------------------- /spec/public/resource_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'DataMapper::Resource' do 4 | before :all do 5 | DataMapper::Validations::Fixtures::Barcode.destroy! 6 | 7 | @resource = DataMapper::Validations::Fixtures::Barcode.new 8 | end 9 | 10 | describe '#update' do 11 | describe 'when provided valid attributes' do 12 | before :all do 13 | @response = @resource.update(:code => 'a' * 10) 14 | end 15 | 16 | it 'should return true' do 17 | @response.should be(true) 18 | end 19 | end 20 | 21 | describe 'when provided invalid attributes' do 22 | before :all do 23 | @response = @resource.update(:code => 'a' * 11) 24 | end 25 | 26 | it 'should return false' do 27 | @response.should be(false) 28 | end 29 | 30 | it 'should set errors' do 31 | @resource.errors.to_a.should == [ [ 'Code must be at most 10 characters long' ] ] 32 | end 33 | end 34 | 35 | describe 'when provided invalid attributes and a context' do 36 | before :all do 37 | DataMapper::Validations::Fixtures::Organisation.destroy! 38 | DataMapper::Validations::Fixtures::Department.destroy! 39 | DataMapper::Validations::Fixtures::User.destroy! 40 | 41 | organization = DataMapper::Validations::Fixtures::Organisation.create(:name => 'Org 101', :domain => '101') 42 | dept = DataMapper::Validations::Fixtures::Department.create(:name => 'accounting') 43 | 44 | attributes = { 45 | :organisation => organization, 46 | :user_name => 'guy', 47 | :department => dept, 48 | } 49 | 50 | # create a record that will be a dupe when User#update is executed below 51 | DataMapper::Validations::Fixtures::User.create(attributes).should be_saved 52 | 53 | @resource = DataMapper::Validations::Fixtures::User.create(attributes.merge(:user_name => 'other')) 54 | 55 | @response = @resource.update(attributes, :signing_up_for_department_account) 56 | end 57 | 58 | it 'should return false' do 59 | @response.should be(false) 60 | end 61 | 62 | it 'should set errors' do 63 | @resource.errors.to_a.should == [ [ 'User name is already taken' ] ] 64 | end 65 | end 66 | end 67 | 68 | describe '#save' do 69 | before :all do 70 | @resource.code = 'a' * 10 71 | @resource.save 72 | end 73 | 74 | describe 'on a new, non-dirty resource' do 75 | it 'should call valid? once' do 76 | blank = DataMapper::Validations::Fixtures::Barcode.new 77 | blank.save 78 | blank.valid_hook_call_count.should == 1 79 | end 80 | end 81 | 82 | describe 'on a new, dirty resource' do 83 | it 'should call valid? once' do 84 | @resource.valid_hook_call_count.should == 1 85 | end 86 | end 87 | 88 | describe 'on a saved, non-dirty resource' do 89 | before :all do 90 | # reload the resource 91 | @resource = @resource.model.get(*@resource.key) 92 | @resource.save 93 | end 94 | 95 | it 'should not call valid?' do 96 | @resource.valid_hook_call_count.to_i.should == 0 97 | end 98 | end 99 | 100 | describe 'on a saved, dirty resource' do 101 | before :all do 102 | # reload the resource 103 | @resource = @resource.model.get(*@resource.key) 104 | @resource.code = 'b' * 10 105 | @resource.save 106 | end 107 | 108 | it 'should call valid? once' do 109 | @resource.valid_hook_call_count.should == 1 110 | end 111 | end 112 | end 113 | end 114 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'dm-core/spec/setup' 2 | require 'dm-core/spec/lib/adapter_helpers' 3 | 4 | require 'dm-validations' 5 | require 'dm-types' 6 | require 'dm-migrations' 7 | 8 | class Hash 9 | def except(*keys) 10 | hash = dup 11 | keys.each { |key| hash.delete(key) } 12 | hash 13 | end 14 | end 15 | 16 | SPEC_ROOT = Pathname(__FILE__).dirname 17 | Pathname.glob((SPEC_ROOT + 'fixtures/**/*.rb').to_s).each { |file| require file } 18 | Pathname.glob((SPEC_ROOT + 'integration/shared/**/*.rb').to_s).each { |file| require file } 19 | 20 | DataMapper::Spec.setup 21 | DataMapper.finalize 22 | 23 | Spec::Runner.configure do |config| 24 | config.extend(DataMapper::Spec::Adapters::Helpers) 25 | 26 | config.before :suite do 27 | DataMapper.finalize.auto_migrate! 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /spec/unit/contextual_validators/emptiness_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'spec_helper' 3 | require 'unit/contextual_validators/spec_helper' 4 | 5 | describe 'DataMapper::Validations::ContextualRuleSet' do 6 | before :all do 7 | @validators = DataMapper::Validations::ContextualRuleSet.new 8 | end 9 | 10 | describe "initially" do 11 | it "is empty" do 12 | @validators.should be_empty 13 | end 14 | end 15 | 16 | 17 | describe "after first reference to context" do 18 | before :all do 19 | @validators.context(:create) 20 | end 21 | 22 | it "initializes list of validators for referred context" do 23 | @validators.context(:create).should be_empty 24 | end 25 | end 26 | 27 | 28 | describe "after a context being added" do 29 | before :all do 30 | @validators.context(:default) << DataMapper::Validations::Rule::Presence.new(:toc, :when => [:publishing]) 31 | end 32 | 33 | it "is no longer empty" do 34 | @validators.should_not be_empty 35 | end 36 | end 37 | 38 | 39 | describe "when cleared" do 40 | before :all do 41 | @validators.context(:default) << DataMapper::Validations::Rule::Presence.new(:toc, :when => [:publishing]) 42 | @validators.should_not be_empty 43 | @validators.clear 44 | end 45 | 46 | it "becomes empty again" do 47 | @validators.should be_empty 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /spec/unit/contextual_validators/execution_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'spec_helper' 3 | require 'unit/contextual_validators/spec_helper' 4 | 5 | describe 'DataMapper::Validations::ContextualRuleSet' do 6 | before :all do 7 | @validators = DataMapper::Validations::ContextualRuleSet.new 8 | end 9 | 10 | describe "#execute(name, target)" do 11 | before do 12 | @validator_one = DataMapper::Validations::Rule::Presence.new(:name) 13 | @validator_two = DataMapper::Validations::Rule::Within.new(:operating_system, :set => ["Mac OS X", "Linux", "FreeBSD", "Solaris"]) 14 | 15 | @validators.context(:default) << @validator_one << @validator_two 16 | end 17 | 18 | 19 | describe "when target satisfies all validators" do 20 | before do 21 | @target = DataMapper::Validations::Fixtures::PieceOfSoftware.new(:name => 'gcc', :operating_system => "Mac OS X") 22 | @validator_one.call(@target).should be(true) 23 | @validator_two.call(@target).should be(true) 24 | 25 | @result = @validators.execute(:default, @target) 26 | end 27 | 28 | it "returns true" do 29 | @result.should be(true) 30 | end 31 | end 32 | 33 | 34 | describe "when target does not satisfy all validators" do 35 | before do 36 | @target = DataMapper::Validations::Fixtures::PieceOfSoftware.new(:name => 'Skitch', :operating_system => "Haiku") 37 | @validator_one.call(@target).should be(true) 38 | @validator_two.call(@target).should be(false) 39 | 40 | @result = @validators.execute(:default, @target) 41 | end 42 | 43 | it "returns false" do 44 | @result.should be(false) 45 | end 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /spec/unit/contextual_validators/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | module DataMapper 4 | module Validation 5 | module Fixtures 6 | 7 | class PieceOfSoftware 8 | # 9 | # Behaviors 10 | # 11 | 12 | include DataMapper::Validations 13 | 14 | # 15 | # Attributes 16 | # 17 | 18 | attr_accessor :name, :operating_system 19 | 20 | # 21 | # Validations 22 | # 23 | 24 | # 25 | # API 26 | # 27 | 28 | def initialize(attributes = {}) 29 | attributes.each do |key, value| 30 | self.send("#{key}=", value) 31 | end 32 | end 33 | end 34 | 35 | end # Fixtures 36 | end # Validations 37 | end # DataMapper 38 | -------------------------------------------------------------------------------- /spec/unit/generic_validator/equality_operator_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'DataMapper::Validations::Rule' do 4 | describe "when types and fields are equal" do 5 | it "returns true" do 6 | DataMapper::Validations::Rule::Presence.new(:name). 7 | should == DataMapper::Validations::Rule::Presence.new(:name) 8 | end 9 | end 10 | 11 | 12 | describe "when types differ" do 13 | it "returns false" do 14 | DataMapper::Validations::Rule::Presence.new(:name). 15 | should_not == DataMapper::Validations::Rule::Uniqueness.new(:name) 16 | end 17 | end 18 | 19 | 20 | describe "when property names differ" do 21 | it "returns false" do 22 | DataMapper::Validations::Rule::Presence.new(:first_name). 23 | should_not == DataMapper::Validations::Rule::Presence.new(:last_name) 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /spec/unit/generic_validator/optional_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'DataMapper::Validations::Rule::Generic', '#optional?' do 4 | def validator(opts = {}) 5 | DataMapper::Validations::Rule::Length.new(:name, opts) 6 | end 7 | 8 | describe 'allowing blank' do 9 | subject do 10 | validator( 11 | :allow_blank => true 12 | ) 13 | end 14 | 15 | it { subject.optional?("" ).should be } 16 | it { subject.optional?(nil).should be } 17 | end 18 | 19 | describe 'allowing nil' do 20 | subject do 21 | validator( 22 | :allow_nil => true 23 | ) 24 | end 25 | 26 | it { subject.optional?("" ).should_not be } 27 | it { subject.optional?(nil).should be } 28 | end 29 | 30 | describe 'allowing blank, but now allowing nil' do 31 | subject do 32 | validator( 33 | :allow_blank => true, 34 | :allow_nil => false 35 | ) 36 | end 37 | 38 | it { subject.optional?("" ).should be } 39 | it { subject.optional?(nil).should_not be } 40 | end 41 | 42 | describe 'allowing nil, but now allowing blank' do 43 | subject do 44 | validator( 45 | :allow_blank => false, 46 | :allow_nil => true 47 | ) 48 | end 49 | 50 | it { subject.optional?("" ).should_not be } 51 | it { subject.optional?(nil).should be } 52 | end 53 | 54 | end 55 | -------------------------------------------------------------------------------- /spec/unit/validators/within_validator_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'DataMapper::Validations::Rule::Within' do 4 | it 'should allow Sets to be passed to the :set option' do 5 | types = Set.new(%w(home mobile business)) 6 | 7 | @model = Class.new do 8 | include DataMapper::Resource 9 | 10 | def self.name 11 | 'WithinValidatorClass' 12 | end 13 | 14 | property :id, DataMapper::Property::Serial 15 | property :name, String, :auto_validation => false 16 | end.new 17 | 18 | validator = DataMapper::Validations::Rule::Within.new(:name, :set => types) 19 | validator.call(@model) 20 | 21 | @model.errors.should_not be_empty 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/unit/violation_set/adding_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'spec_helper' 3 | 4 | describe 'DataMapper::Validations::ViolationSet' do 5 | before :all do 6 | @model = DataMapper::Validations::ViolationSet.new(Object.new) 7 | end 8 | 9 | describe "after first error being added" do 10 | before :all do 11 | @model.add(:property, "can't be valid, no way") 12 | end 13 | 14 | it "is no longer empty" do 15 | @model.should_not be_empty 16 | end 17 | 18 | it "adds error message to list of errors for given property name" do 19 | @model.on(:property).should == ["can't be valid, no way"] 20 | end 21 | end 22 | 23 | 24 | describe "after second error being added" do 25 | before :all do 26 | @model.add(:property, "can't be valid, no way") 27 | @model.add(:property, "something else is wrong") 28 | end 29 | 30 | it "is no longer empty" do 31 | @model.should_not be_empty 32 | end 33 | 34 | it "appends error message to list of errors for given property name" do 35 | @model.on(:property).should == ["can't be valid, no way", "something else is wrong"] 36 | end 37 | end 38 | 39 | 40 | describe "when duplicate error being added" do 41 | before :all do 42 | @model.add(:property, "can't be valid, no way") 43 | @model.add(:property, "can't be valid, no way") 44 | end 45 | 46 | it "is no longer empty" do 47 | @model.should_not be_empty 48 | end 49 | 50 | it "DOES NOT allow duplication" do 51 | @model.on(:property).should == ["can't be valid, no way"] 52 | end 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /spec/unit/violation_set/emptiness_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'spec_helper' 3 | 4 | describe 'DataMapper::Validations::ViolationSet' do 5 | before :all do 6 | @model = DataMapper::Validations::ViolationSet.new(Object.new) 7 | end 8 | 9 | describe "initially" do 10 | it "is empty" do 11 | @model.should be_empty 12 | end 13 | end 14 | 15 | # Not sure if this is worth having at all, 16 | # just keeping old spec suite bits in place 17 | # if they make no harm — MK 18 | describe "after enquiry" do 19 | before :all do 20 | @model.on(:property) 21 | end 22 | 23 | it "is still empty" do 24 | @model.should be_empty 25 | end 26 | end 27 | 28 | 29 | describe "after errors being added" do 30 | before :all do 31 | @model.add(:property, "can't be valid, no way") 32 | end 33 | 34 | it "is no longer empty" do 35 | @model.should_not be_empty 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /spec/unit/violation_set/enumerable_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'spec_helper' 3 | 4 | describe 'DataMapper::Validations::ViolationSet' do 5 | before :all do 6 | @model = DataMapper::Validations::ViolationSet.new(Object.new) 7 | @model.add(:ip_address, "must have valid format") 8 | @model.add(:full_name, "can't be blank") 9 | end 10 | 11 | describe "#each" do 12 | it "iterates over properties and yields error message arrays" do 13 | params = [] 14 | @model.each do |param| 15 | params << param 16 | end 17 | 18 | params.should == [ [ 'must have valid format' ], [ "can't be blank" ] ] 19 | end 20 | end 21 | 22 | 23 | describe "#map" do 24 | before :all do 25 | @model.add(:ip_address, "must belong to a local subnet") 26 | end 27 | it "maps error message arrays using provided block" do 28 | projection = @model.map { |ary| ary } 29 | projection.should == [ [ 'must have valid format', 'must belong to a local subnet' ], [ "can't be blank" ] ] 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /spec/unit/violation_set/reading_spec.rb: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | require 'spec_helper' 3 | 4 | shared_examples_for 'a validation error reader' do 5 | context 'and that property has no associated errors' do 6 | it 'should return an empty array' do 7 | @errors[@property].should == [] 8 | end 9 | end 10 | context 'and that property has associated error(s)' do 11 | it 'should return a non empty array' do 12 | @errors.add(@property.to_sym, 'invalid') 13 | @errors[@property].should_not be_empty 14 | end 15 | end 16 | end 17 | 18 | describe 'DataMapper::Validations::ViolationSet' do 19 | describe '[]' do 20 | describe 'when passing the argument as a String' do 21 | before(:each) do 22 | @errors = DataMapper::Validations::ViolationSet.new(Object.new) 23 | @property = 'name' 24 | end 25 | it_should_behave_like 'a validation error reader' 26 | end 27 | describe 'when passing the argument as a Symbol' do 28 | before(:each) do 29 | @errors = DataMapper::Validations::ViolationSet.new(Object.new) 30 | @property = :name 31 | end 32 | it_should_behave_like 'a validation error reader' 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /spec/unit/violation_set/respond_to_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'DataMapper::Validations::ViolationSet#respond_to?' do 4 | 5 | subject { DataMapper::Validations::ViolationSet.new(Object.new) } 6 | 7 | it 'should look for the method in self' do 8 | subject.should respond_to(:full_messages) 9 | end 10 | 11 | it 'should delegate lookup to the underlying errors hash' do 12 | subject.should respond_to(:size) 13 | end 14 | 15 | end 16 | -------------------------------------------------------------------------------- /tasks/spec.rake: -------------------------------------------------------------------------------- 1 | spec_defaults = lambda do |spec| 2 | spec.pattern = 'spec/**/*_spec.rb' 3 | spec.libs << 'lib' << 'spec' 4 | spec.spec_opts << '--loadby random' 5 | spec.spec_opts << '-c' if RUBY_VERSION < '2.2' 6 | end 7 | 8 | begin 9 | require 'spec/rake/spectask' 10 | 11 | Spec::Rake::SpecTask.new(:spec, &spec_defaults) 12 | rescue LoadError 13 | task :spec do 14 | abort 'rspec is not available. In order to run spec, you must: gem install rspec' 15 | end 16 | end 17 | 18 | begin 19 | require 'rcov' 20 | require 'spec/rake/verify_rcov' 21 | 22 | Spec::Rake::SpecTask.new(:rcov) do |rcov| 23 | spec_defaults.call(rcov) 24 | rcov.rcov = true 25 | rcov.rcov_opts = File.read('spec/rcov.opts').split(/\s+/) 26 | end 27 | 28 | RCov::VerifyTask.new(:verify_rcov => :rcov) do |rcov| 29 | rcov.threshold = 100 30 | end 31 | rescue LoadError 32 | %w[ rcov verify_rcov ].each do |name| 33 | task name do 34 | abort "rcov is not available. In order to run #{name}, you must: gem install rcov" 35 | end 36 | end 37 | end 38 | 39 | task :default => :spec 40 | -------------------------------------------------------------------------------- /tasks/yard.rake: -------------------------------------------------------------------------------- 1 | begin 2 | require 'yard' 3 | 4 | YARD::Rake::YardocTask.new 5 | rescue LoadError 6 | task :yard do 7 | abort 'YARD is not available. In order to run yard, you must: gem install yard' 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /tasks/yardstick.rake: -------------------------------------------------------------------------------- 1 | begin 2 | require 'pathname' 3 | require 'yardstick/rake/measurement' 4 | require 'yardstick/rake/verify' 5 | 6 | # yardstick_measure task 7 | Yardstick::Rake::Measurement.new 8 | 9 | # verify_measurements task 10 | Yardstick::Rake::Verify.new do |verify| 11 | verify.threshold = 100 12 | end 13 | rescue LoadError 14 | %w[ yardstick_measure verify_measurements ].each do |name| 15 | task name.to_s do 16 | abort "Yardstick is not available. In order to run #{name}, you must: gem install yardstick" 17 | end 18 | end 19 | end 20 | --------------------------------------------------------------------------------