semantic_attributes 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. data/.gitignore +2 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +99 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README +54 -0
  6. data/Rakefile +37 -0
  7. data/gist.rdoc +208 -0
  8. data/lib/active_record/validation_recursion_control.rb +33 -0
  9. data/lib/core_ext/class.rb +14 -0
  10. data/lib/predicates/aliased.rb +22 -0
  11. data/lib/predicates/association.rb +43 -0
  12. data/lib/predicates/base.rb +93 -0
  13. data/lib/predicates/blacklisted.rb +23 -0
  14. data/lib/predicates/domain.rb +31 -0
  15. data/lib/predicates/email.rb +42 -0
  16. data/lib/predicates/enumerated.rb +23 -0
  17. data/lib/predicates/hex_color.rb +24 -0
  18. data/lib/predicates/length.rb +71 -0
  19. data/lib/predicates/number.rb +104 -0
  20. data/lib/predicates/pattern.rb +22 -0
  21. data/lib/predicates/phone_number.rb +62 -0
  22. data/lib/predicates/required.rb +22 -0
  23. data/lib/predicates/same_as.rb +17 -0
  24. data/lib/predicates/size.rb +2 -0
  25. data/lib/predicates/time.rb +43 -0
  26. data/lib/predicates/unique.rb +71 -0
  27. data/lib/predicates/url.rb +62 -0
  28. data/lib/predicates/usa_state.rb +87 -0
  29. data/lib/predicates/usa_zip_code.rb +25 -0
  30. data/lib/predicates/whitelisted.rb +2 -0
  31. data/lib/predicates.rb +3 -0
  32. data/lib/semantic_attributes/attribute.rb +46 -0
  33. data/lib/semantic_attributes/attribute_formats.rb +67 -0
  34. data/lib/semantic_attributes/locale/en.yml +31 -0
  35. data/lib/semantic_attributes/predicates.rb +170 -0
  36. data/lib/semantic_attributes/set.rb +40 -0
  37. data/lib/semantic_attributes/version.rb +3 -0
  38. data/lib/semantic_attributes.rb +37 -0
  39. data/semantic_attributes.gemspec +29 -0
  40. data/test/db/database.yml +3 -0
  41. data/test/db/models.rb +38 -0
  42. data/test/db/schema.rb +33 -0
  43. data/test/fixtures/addresses.yml +15 -0
  44. data/test/fixtures/roles.yml +4 -0
  45. data/test/fixtures/roles_users.yml +6 -0
  46. data/test/fixtures/services.yml +6 -0
  47. data/test/fixtures/subscriptions.yml +16 -0
  48. data/test/fixtures/users.yml +20 -0
  49. data/test/test_helper.rb +67 -0
  50. data/test/unit/active_record_predicates_test.rb +88 -0
  51. data/test/unit/attribute_formats_test.rb +40 -0
  52. data/test/unit/inheritance_test.rb +23 -0
  53. data/test/unit/predicates/aliased_test.rb +17 -0
  54. data/test/unit/predicates/association_predicate_test.rb +51 -0
  55. data/test/unit/predicates/base_test.rb +53 -0
  56. data/test/unit/predicates/blacklisted_predicate_test.rb +28 -0
  57. data/test/unit/predicates/domain_predicate_test.rb +27 -0
  58. data/test/unit/predicates/email_test.rb +82 -0
  59. data/test/unit/predicates/enumerated_predicate_test.rb +22 -0
  60. data/test/unit/predicates/hex_color_predicate_test.rb +29 -0
  61. data/test/unit/predicates/length_predicate_test.rb +85 -0
  62. data/test/unit/predicates/number_test.rb +109 -0
  63. data/test/unit/predicates/pattern_predicate_test.rb +29 -0
  64. data/test/unit/predicates/phone_number_predicate_test.rb +41 -0
  65. data/test/unit/predicates/required_predicate_test.rb +13 -0
  66. data/test/unit/predicates/same_as_predicate_test.rb +19 -0
  67. data/test/unit/predicates/time_test.rb +49 -0
  68. data/test/unit/predicates/unique_test.rb +58 -0
  69. data/test/unit/predicates/url_test.rb +86 -0
  70. data/test/unit/predicates/usa_state_test.rb +31 -0
  71. data/test/unit/predicates/usa_zip_code_test.rb +42 -0
  72. data/test/unit/semantic_attribute_test.rb +18 -0
  73. data/test/unit/semantic_attributes_test.rb +29 -0
  74. data/test/unit/validations_test.rb +121 -0
  75. metadata +235 -0
@@ -0,0 +1,88 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class ActiveRecordExtensionsTest < SemanticAttributes::TestCase
4
+ class FooUser < User
5
+ attr_accessor :foo
6
+ end
7
+
8
+ def setup
9
+ FooUser.semantic_attributes = nil
10
+ end
11
+
12
+ def test_module
13
+ assert ActiveRecord::Base.included_modules.include?(SemanticAttributes::Predicates)
14
+ assert ActiveRecord::Base.semantic_attributes.is_a?(SemanticAttributes::Set)
15
+ end
16
+
17
+ def test_declarative_sugar
18
+ @klass = FooUser
19
+
20
+ assert_nothing_raised 'creating predicates via method_missing sugar' do
21
+ @klass.foo_is_required
22
+ @klass.foo_has_a_length
23
+ @klass.foo_is_a_phone_number
24
+ end
25
+
26
+ assert @klass.semantic_attributes[:foo].has?(:required)
27
+ assert @klass.foo_is_required?
28
+
29
+ assert @klass.semantic_attributes[:foo].has?(:length)
30
+ assert @klass.foo_has_length?
31
+
32
+ assert @klass.semantic_attributes[:foo].has?(:phone_number)
33
+ assert @klass.foo_is_a_phone_number?
34
+ end
35
+
36
+ def test_declarative_sugar_allows_inline_required
37
+ @klass = FooUser
38
+
39
+ @klass.foo_is_a_required_phone_number
40
+ assert !@klass.semantic_attributes[:foo].get(:phone_number).allow_empty?
41
+ assert @klass.foo_is_a_phone_number?
42
+ end
43
+
44
+ def test_declarative_sugar_catches_unknown_attributes
45
+ @klass = FooUser
46
+ assert_raises SemanticAttributes::MissingAttribute do
47
+ @klass.unknown_is_required
48
+ end
49
+ end
50
+
51
+ def test_declarative_sugar_for_mass_assignment
52
+ @klass = FooUser
53
+ assert_nothing_raised do
54
+ @klass.fields_are_required :foo
55
+ end
56
+ assert @klass.foo_is_required?
57
+ end
58
+
59
+ def test_method_missing_still_works
60
+ assert_raise NoMethodError do User.i_do_not_exist end
61
+ end
62
+
63
+ ##
64
+ ## Want to test :expected_error_for with some common predicates.
65
+ ##
66
+
67
+ class PasswordUser < PluginTestModels::User
68
+ attr_accessor :password, :password_confirmation
69
+ end
70
+
71
+ def test_expected_error_for_with_unique_predicate
72
+ PasswordUser.stub_semantics_with(:login => :unique)
73
+ assert_not_nil PasswordUser.expected_error_for(:login, users(:bob).login)
74
+ assert_nil PasswordUser.expected_error_for(:login, "veryuniquelogin!")
75
+ end
76
+
77
+ def test_expected_error_for_with_length_predicate
78
+ PasswordUser.stub_semantics_with(:login => {:length => {:above => 5}})
79
+ assert_not_nil PasswordUser.expected_error_for(:login, "a" * 4)
80
+ assert_nil PasswordUser.expected_error_for(:login, "a" * 6)
81
+ end
82
+
83
+ def test_expected_error_for_with_same_as_predicate
84
+ PasswordUser.stub_semantics_with(:password_confirmation => {:same_as => {:method => :password}})
85
+ assert_not_nil PasswordUser.expected_error_for(:password_confirmation, "one thing", :password => "another thing")
86
+ assert_nil PasswordUser.expected_error_for(:password_confirmation, "thing", :password => "thing")
87
+ end
88
+ end
@@ -0,0 +1,40 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class AttributeFormatsTest < SemanticAttributes::TestCase
4
+ class User < User
5
+ cell_is_a_phone_number
6
+ cell_is_required
7
+ end
8
+
9
+ def setup
10
+ @record = User.new
11
+ end
12
+
13
+ def test_semantic_attribute_read_and_write
14
+ assert_nothing_raised do
15
+ @record.cell = '(222) 333.4444'
16
+ end
17
+ assert_equal '+12223334444', @record.attributes['cell'], 'value is stored in normalized format'
18
+
19
+ assert_equal '+12223334444', @record.cell, 'read defaults to machine format'
20
+ assert @record.respond_to?(:cell_for_human)
21
+ assert_equal '(222) 333-4444', @record.cell_for_human, 'reading in human format'
22
+ end
23
+
24
+ def test_regular_attribute_read_and_write
25
+ assert_nothing_raised do
26
+ @record.login = 'hugo'
27
+ end
28
+ assert_equal 'hugo', @record.attributes['login']
29
+ assert !@record.respond_to?(:login_for_human)
30
+ assert_raise NoMethodError do @record.login_for_human end
31
+ end
32
+
33
+ def test_normalize
34
+ assert_equal '+12223334444', User.normalize(:cell, '(222) 333.4444')
35
+ end
36
+
37
+ def test_humanize
38
+ assert_equal '(222) 333-4444', User.humanize(:cell, '+12223334444')
39
+ end
40
+ end
@@ -0,0 +1,23 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class InheritanceTest < SemanticAttributes::TestCase
4
+ class Worker < User
5
+ attr_accessor :name_tag
6
+ name_tag_is_required
7
+ end
8
+
9
+ class Clerk < Worker
10
+ attr_accessor :pen
11
+ pen_is_required
12
+ end
13
+
14
+ def test_parent_semantics
15
+ assert Worker.semantic_attributes[:name_tag].has?(:required)
16
+ assert !Worker.semantic_attributes[:pen].has?(:required)
17
+ end
18
+
19
+ def test_child_semantics
20
+ assert Clerk.semantic_attributes[:name_tag].has?(:required)
21
+ assert Clerk.semantic_attributes[:pen].has?(:required)
22
+ end
23
+ end
@@ -0,0 +1,17 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
2
+
3
+ class AliasedPredicateTest < SemanticAttributes::TestCase
4
+ def setup
5
+ @predicate = Predicates::Aliased.new(:foo, :options => {'10111001' => '185'})
6
+ end
7
+
8
+ def test_formats
9
+ assert_equal '185', @predicate.to_human('10111001')
10
+ assert_equal '10111001', @predicate.normalize('185')
11
+ end
12
+
13
+ def test_validation
14
+ assert @predicate.validate('185', nil)
15
+ assert !@predicate.validate('10111001', nil)
16
+ end
17
+ end
@@ -0,0 +1,51 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
2
+
3
+ class AssociationPredicateTest < SemanticAttributes::TestCase
4
+ def test_singular_associations
5
+ predicate = Predicates::Association.new(:subscription)
6
+ assert predicate.validate(users(:bob).subscription, users(:bob))
7
+ end
8
+
9
+ def test_plural_associations
10
+ predicate = Predicates::Association.new(:subscriptions)
11
+ assert predicate.validate(services(:free).subscriptions, services(:free))
12
+ end
13
+
14
+ def test_association_min
15
+ predicate = Predicates::Association.new(:subscriptions)
16
+ assert_equal 3, services(:free).subscriptions.size, "assuming three free subscriptions"
17
+
18
+ predicate.min = 4
19
+ predicate.max = nil
20
+ assert !predicate.validate(services(:free).subscriptions, services(:free)), "min works"
21
+
22
+ predicate.min = 3
23
+ predicate.max = nil
24
+ assert predicate.validate(services(:free).subscriptions, services(:free)), "min doesn't not work"
25
+ end
26
+
27
+ def test_association_max
28
+ predicate = Predicates::Association.new(:subscriptions)
29
+ assert_equal 3, services(:free).subscriptions.size, "assuming three free subscriptions"
30
+
31
+ predicate.min = nil
32
+ predicate.max = 2
33
+ assert !predicate.validate(services(:free).subscriptions, services(:free)), "max works"
34
+
35
+ predicate.min = nil
36
+ predicate.max = 3
37
+ assert predicate.validate(services(:free).subscriptions, services(:free)), "max doesn't not work"
38
+ end
39
+
40
+ # def test_recursion_for_new_records
41
+ # # service has_many subscriptions
42
+ # Service.stub_semantics_with(:subscriptions => :association)
43
+ # # subscription belongs_to service
44
+ # Subscription.stub_semantics_with(:service => :association)
45
+ #
46
+ # unleaded = Service.new(:name => 'unleaded')
47
+ # unleaded.subscriptions = [Subscription.new(:service => unleaded, :user => users(:bob))]
48
+ #
49
+ # assert_nothing_raised {unleaded.valid?}
50
+ # end
51
+ end
@@ -0,0 +1,53 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
2
+
3
+ class BasePredicateTest < SemanticAttributes::TestCase
4
+ def setup
5
+ @predicate = Predicates::Base.new(:foo)
6
+ end
7
+
8
+ def test_unimplemented_methods
9
+ assert_equal 2, @predicate.method(:validate).arity
10
+ assert_raise NotImplementedError do @predicate.validate(nil, nil) end
11
+ assert_equal 'foo', @predicate.to_human('foo')
12
+ assert_equal 'foo', @predicate.normalize('foo')
13
+ end
14
+
15
+ def test_initializer_assignment
16
+ predicate = Predicates::Base.new(:foo, :error_message => 'hello world')
17
+ assert_equal 'hello world', predicate.error_message
18
+ end
19
+
20
+ def test_initializer_assignment_with_typos
21
+ assert_raises NoMethodError do
22
+ Predicates::Base.new(:foo, :unknown_option => "something")
23
+ end
24
+ end
25
+
26
+ def test_default_values
27
+ assert @predicate.allow_empty?, "allow empty/nil values by default"
28
+ assert_equal :both, @predicate.validate_on, "validate on create and update by default"
29
+ assert_equal :invalid, @predicate.error_message, "error message is a bland :invalid by default"
30
+ assert_equal Hash.new, @predicate.error_binds, "there are no binds by default"
31
+ end
32
+
33
+ def test_or_empty
34
+ predicate = Predicates::Base.new(:foo, :or_empty => true)
35
+ assert predicate.allow_empty?
36
+ predicate = Predicates::Base.new(:foo, :or_empty => false)
37
+ assert !predicate.allow_empty?
38
+ end
39
+
40
+ def test_message_aliasing
41
+ predicate = Predicates::Base.new(:foo)
42
+ predicate.error_message = "something"
43
+ assert_equal "something", predicate.message
44
+ predicate.message = "another thing"
45
+ assert_equal "another thing", predicate.error_message
46
+ end
47
+
48
+ def test_string_errors_are_preserved
49
+ predicate = Predicates::Base.new(:foo)
50
+ predicate.error_message = "something"
51
+ assert_equal "something", predicate.error
52
+ end
53
+ end
@@ -0,0 +1,28 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
2
+
3
+ class BlacklistedPredicateTest < SemanticAttributes::TestCase
4
+ def setup
5
+ @predicate = Predicates::Blacklisted.new(:foo)
6
+ end
7
+
8
+ def test_case_insensitive_validation
9
+ @predicate.case_sensitive = false
10
+ @predicate.restricted = [1, "foo"]
11
+ assert !@predicate.validate(1, nil)
12
+ assert !@predicate.validate("1", nil)
13
+ assert !@predicate.validate("foo", nil)
14
+ assert !@predicate.validate("foO", nil)
15
+ end
16
+
17
+ def test_case_sensitive_validation
18
+ @predicate.case_sensitive = true
19
+
20
+ @predicate.restricted = [1, 2, '3']
21
+
22
+ assert !@predicate.validate(1, nil)
23
+ assert !@predicate.validate(2, nil)
24
+ assert @predicate.validate(3, nil), 'type is important'
25
+ assert !@predicate.validate('3', nil)
26
+ assert @predicate.validate(6, nil)
27
+ end
28
+ end
@@ -0,0 +1,27 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
2
+
3
+ class DomainPredicateTest < SemanticAttributes::TestCase
4
+ def setup
5
+ @predicate = Predicates::Domain.new(:foo)
6
+ end
7
+
8
+ def test_valid_domains
9
+ %w(example.com www.example.com).each do |domain|
10
+ assert @predicate.validate(domain, nil), "#{domain} is a valid domain"
11
+ end
12
+ end
13
+
14
+ def test_invalid_domains
15
+ %w(example example.com/foo http://example.com 123.45.6.78).each do |domain|
16
+ assert !@predicate.validate(domain, nil), "#{domain} is not a valid domain"
17
+ end
18
+ end
19
+
20
+ def test_normalize
21
+ assert_equal "example.com", @predicate.normalize("http://example.com:8080/foo")
22
+ assert_equal "example.com", @predicate.normalize("example.com/foo")
23
+ assert_equal nil, @predicate.normalize(nil)
24
+ assert_equal "", @predicate.normalize("")
25
+ assert_equal "example.com", @predicate.normalize("example.com")
26
+ end
27
+ end
@@ -0,0 +1,82 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
2
+
3
+ class EmailPredicateTest < SemanticAttributes::TestCase
4
+ def setup
5
+ @predicate = Predicates::Email.new(:foo)
6
+ end
7
+
8
+ ##
9
+ ## Test cases from Alex Dunae's validates_email_format_of
10
+ ## see http://code.dunae.ca/validates_email_format_of/trunk/test/validates_email_format_of_test.rb
11
+ ##
12
+
13
+ def test_should_allow_valid_email_addresses
14
+ ['valid@example.com',
15
+ 'Valid@test.example.com',
16
+ 'valid+valid123@test.example.com',
17
+ 'valid_valid123@test.example.com',
18
+ 'valid-valid+123@test.example.co.uk',
19
+ 'valid-valid+1.23@test.example.com.au',
20
+ 'valid@example.co.uk',
21
+ 'v@example.com',
22
+ 'valid@example.ca',
23
+ 'valid_@example.com',
24
+ 'valid123.456@example.org',
25
+ 'valid123.456@example.travel',
26
+ 'valid123.456@example.museum',
27
+ 'valid@example.mobi',
28
+ 'valid@example.info',
29
+ 'valid-@example.com',
30
+ # from RFC 3696, page 6
31
+ 'customer/department=shipping@example.com',
32
+ '$A12345@example.com',
33
+ '!def!xyz%abc@example.com',
34
+ '_somename@example.com',
35
+ # apostrophes
36
+ "test'test@example.com",
37
+ # from http://www.rfc-editor.org/errata_search.php?rfc=3696
38
+ '"Abc\@def"@example.com',
39
+ '"Fred\ Bloggs"@example.com',
40
+ '"Joe.\\Blow"@example.com',
41
+ ].each do |email|
42
+ assert @predicate.validate(email, nil), "#{email} should be valid"
43
+ end
44
+ end
45
+
46
+ def test_should_not_allow_invalid_email_addresses
47
+ ['invalid@example-com',
48
+ # period can not start local part
49
+ '.invalid@example.com',
50
+ # period can not end local part
51
+ 'invalid.@example.com',
52
+ # period can not appear twice consecutively in local part
53
+ 'invali..d@example.com',
54
+ 'invalid@example.com.',
55
+ 'invalid@example.com_',
56
+ 'invalid@example.com-',
57
+ 'invalid-example.com',
58
+ 'invalid@example.b#r.com',
59
+ 'invalid@example.c',
60
+ 'invali d@example.com',
61
+ 'invalidexample.com',
62
+ 'invalid@example.',
63
+ # from http://tools.ietf.org/html/rfc3696, page 5
64
+ # corrected in http://www.rfc-editor.org/errata_search.php?rfc=3696
65
+ 'Fred\ Bloggs_@example.com',
66
+ 'Abc\@def+@example.com',
67
+ 'Joe.\\Blow@example.com',
68
+ # too lengthy
69
+ "#{"a".rjust(65, 'a')}@example.com",
70
+ "test@#{"a.com".rjust(256, 'a')}"
71
+ ].each do |email|
72
+ assert !@predicate.validate(email, nil), "#{email} should not be valid"
73
+ end
74
+ end
75
+
76
+ def test_with_mx_record
77
+ assert @predicate.validate('test@example.com', nil), 'syntax check only'
78
+ @predicate.with_mx_record = true
79
+ assert !@predicate.validate('test@example.com', nil), 'syntax and mx check'
80
+ assert @predicate.validate('test@gmail.com', nil)
81
+ end
82
+ end
@@ -0,0 +1,22 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
2
+
3
+ class EnumeratedPredicateTest < SemanticAttributes::TestCase
4
+ def setup
5
+ @predicate = Predicates::Enumerated.new(:foo)
6
+ end
7
+
8
+ def test_validation
9
+ @predicate.options = [1, 2, '3']
10
+
11
+ assert @predicate.validate(1, nil)
12
+ assert @predicate.validate(2, nil)
13
+ assert !@predicate.validate(3, nil), 'type is important'
14
+ assert @predicate.validate('3', nil)
15
+ assert !@predicate.validate(6, nil)
16
+ end
17
+
18
+ def test_or_empty
19
+ assert !Predicates::Enumerated.new(:foo).allow_empty?
20
+ assert Predicates::Enumerated.new(:foo, :or_empty => true).allow_empty?
21
+ end
22
+ end
@@ -0,0 +1,29 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
2
+
3
+ class HexColorPredicateTest < SemanticAttributes::TestCase
4
+ def setup
5
+ @predicate = Predicates::HexColor.new(:foo)
6
+ end
7
+
8
+ def test_normalize_conversions
9
+ assert_equal "", @predicate.normalize("")
10
+ assert_equal nil, @predicate.normalize(nil)
11
+ assert_equal "#123456", @predicate.normalize("123456"), "adds a pound sign"
12
+ assert_equal "#123456", @predicate.normalize("#123456"), "does not duplicate the pound sign"
13
+ assert_equal "#112233", @predicate.normalize("123"), "expand three-character syntax"
14
+ assert_equal "#112233", @predicate.normalize("#123"), "handles existing pound sign when expanding to six characters"
15
+ end
16
+
17
+ def test_valid_colors
18
+ %w(#123456 #fff000).each do |color|
19
+ assert @predicate.validate(color, nil), "#{color} should be a valid hex color"
20
+ end
21
+ end
22
+
23
+ def test_invalid_colors
24
+ %w(1 12 123 1234 12345 abc zzz kf0f00).each do |color|
25
+ assert !@predicate.validate(color, nil), "#{color} should be a invalid hex color"
26
+ end
27
+ end
28
+
29
+ end
@@ -0,0 +1,85 @@
1
+ # encoding: UTF-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
3
+
4
+ class LengthPredicateTest < SemanticAttributes::TestCase
5
+ def setup
6
+ @predicate = Predicates::Length.new(:foo)
7
+ end
8
+
9
+ def test_range
10
+ @predicate.range = 1..5
11
+ assert_equal :wrong_length, @predicate.error_message
12
+
13
+ assert !@predicate.validate('', nil)
14
+ assert @predicate.validate('1', nil)
15
+ assert @predicate.validate('12345', nil)
16
+ assert !@predicate.validate('123456', nil)
17
+
18
+ @predicate.range = 1...5
19
+ assert_equal :wrong_length, @predicate.error_message, 'same message for inclusive range'
20
+ assert !@predicate.validate('12345', nil)
21
+ end
22
+
23
+ def test_min
24
+ @predicate.above = 5
25
+ assert_equal :too_short, @predicate.error_message
26
+
27
+ assert !@predicate.validate('', nil)
28
+ assert !@predicate.validate('12345', nil)
29
+ assert @predicate.validate('123456', nil)
30
+ end
31
+
32
+ def test_max
33
+ @predicate.below = 5
34
+ assert_equal :too_long, @predicate.error_message
35
+
36
+ assert @predicate.validate('', nil)
37
+ assert @predicate.validate('1234', nil)
38
+ assert !@predicate.validate('12345', nil)
39
+ end
40
+
41
+ def test_exact
42
+ @predicate.exactly = 5
43
+ assert_equal :inexact_length, @predicate.error_message
44
+
45
+ assert !@predicate.validate('', nil)
46
+ assert !@predicate.validate('1234', nil)
47
+ assert @predicate.validate('12345', nil)
48
+ assert !@predicate.validate('123456', nil)
49
+ end
50
+
51
+ def test_symbols
52
+ @predicate.range = 2..3
53
+ assert @predicate.validate(:abc, nil)
54
+ assert !@predicate.validate(:abcdef, nil)
55
+ end
56
+
57
+ def test_numbers
58
+ @predicate.range = 2..3
59
+ assert !@predicate.validate(3, nil)
60
+ assert @predicate.validate(123, nil)
61
+ end
62
+
63
+ def test_arrays
64
+ @predicate.range = 2..3
65
+ assert !@predicate.validate(['abc'], nil)
66
+ assert @predicate.validate(['abc', 'def', 'ghi'], nil)
67
+ end
68
+
69
+ def test_multibyte_characters
70
+ $KCODE = "UTF8" if RUBY_VERSION < "1.9" # so ActiveSupport uses the UTF8Handler for Chars
71
+ @predicate.exactly = 4
72
+ assert @predicate.validate('ægis', nil)
73
+ assert !@predicate.validate('aegis', nil)
74
+ end
75
+
76
+ def test_normalization
77
+ assert_equal "hello\nworld", @predicate.normalize("hello\r\nworld")
78
+ assert_equal ['a', 'b'], @predicate.normalize(['a', 'b'])
79
+ end
80
+
81
+ def test_no_options
82
+ assert_raise RuntimeError do @predicate.error_message end
83
+ assert @predicate.validate(nil, nil)
84
+ end
85
+ end
@@ -0,0 +1,109 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
2
+
3
+ class NumberPredicateTest < SemanticAttributes::TestCase
4
+ def setup
5
+ @predicate = Predicates::Number.new(:foo)
6
+ end
7
+
8
+ def test_basic_error_message
9
+ assert_equal :not_a_number, @predicate.error_message
10
+ end
11
+
12
+ def test_integers
13
+ @predicate.integer = true
14
+
15
+ assert @predicate.validate(0, nil)
16
+ assert @predicate.validate(-15, nil)
17
+ assert @predicate.validate(15, nil)
18
+ assert @predicate.validate('0', nil)
19
+ assert @predicate.validate('-15', nil)
20
+ assert @predicate.validate('+15', nil)
21
+
22
+ assert !@predicate.validate('1.0', nil)
23
+ assert !@predicate.validate(1.0, nil)
24
+ end
25
+
26
+ def test_floats
27
+ assert !@predicate.integer
28
+ assert @predicate.validate(5, nil), 'still allows integers'
29
+ assert @predicate.validate(-5, nil)
30
+ assert @predicate.validate(5.2, nil)
31
+ assert @predicate.validate(-5.2, nil)
32
+ assert @predicate.validate(0.0, nil)
33
+ assert @predicate.validate(5.2e5, nil)
34
+ assert @predicate.validate(5.2e-5, nil)
35
+ end
36
+
37
+ def test_min
38
+ @predicate.above = 5
39
+ assert_equal :greater_than, @predicate.error_message
40
+
41
+ assert !@predicate.validate(-10, nil)
42
+ assert !@predicate.validate(-5, nil)
43
+ assert !@predicate.validate(0, nil)
44
+ assert !@predicate.validate(5, nil)
45
+ assert @predicate.validate(10, nil)
46
+
47
+ assert @predicate.validate(5.0001, nil)
48
+ @predicate.integer = true
49
+ assert !@predicate.validate(5.0001, nil)
50
+ end
51
+
52
+ def test_min_inclusive
53
+ @predicate.at_least = 5
54
+ assert_equal 5, @predicate.above
55
+ assert @predicate.inclusive
56
+ assert_equal :greater_than_or_equal_to, @predicate.error_message
57
+
58
+ assert !@predicate.validate(4, nil)
59
+ assert @predicate.validate(5, nil)
60
+ end
61
+
62
+ def test_max
63
+ @predicate.below = 5
64
+ assert_equal :less_than, @predicate.error_message
65
+
66
+ assert @predicate.validate(-10, nil)
67
+ assert @predicate.validate(-5, nil)
68
+ assert @predicate.validate(0, nil)
69
+ assert !@predicate.validate(5, nil)
70
+ assert !@predicate.validate(10, nil)
71
+
72
+ assert @predicate.validate(4.9999, nil)
73
+ @predicate.integer = true
74
+ assert !@predicate.validate(4.9999, nil)
75
+ end
76
+
77
+ def test_max_inclusive
78
+ @predicate.no_more_than = 5
79
+ assert_equal 5, @predicate.below
80
+ assert @predicate.inclusive
81
+ assert_equal :less_than_or_equal_to, @predicate.error_message
82
+
83
+ assert @predicate.validate(5, nil)
84
+ assert !@predicate.validate(6, nil)
85
+ end
86
+
87
+ def test_range
88
+ @predicate.range = -5...5
89
+ assert_equal :between, @predicate.error_message
90
+
91
+ assert !@predicate.validate(-10, nil)
92
+ assert @predicate.validate(-5, nil)
93
+ assert @predicate.validate(0, nil)
94
+ assert !@predicate.validate(5, nil)
95
+ assert !@predicate.validate(10, nil)
96
+
97
+ assert @predicate.validate(4.9999, nil)
98
+ @predicate.integer = true
99
+ assert !@predicate.validate(4.9999, nil)
100
+ end
101
+
102
+ def test_range_inclusive
103
+ @predicate.range = -5..5
104
+ assert_equal :between, @predicate.error_message
105
+
106
+ assert @predicate.validate(5, nil)
107
+ assert !@predicate.validate(6, nil)
108
+ end
109
+ end