semantic_attributes 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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