openhood-rspec_sequel_matchers 0.1.1
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.
- data/LICENSE +20 -0
- data/README.rdoc +47 -0
- data/Rakefile +48 -0
- data/VERSION.yml +4 -0
- data/lib/rspec_sequel/association.rb +30 -0
- data/lib/rspec_sequel/base.rb +33 -0
- data/lib/rspec_sequel/matchers/have_column.rb +35 -0
- data/lib/rspec_sequel/matchers/have_many_to_many.rb +22 -0
- data/lib/rspec_sequel/matchers/have_many_to_one.rb +22 -0
- data/lib/rspec_sequel/matchers/have_one_to_many.rb +22 -0
- data/lib/rspec_sequel/matchers/validate_exact_length.rb +25 -0
- data/lib/rspec_sequel/matchers/validate_format.rb +25 -0
- data/lib/rspec_sequel/matchers/validate_includes.rb +25 -0
- data/lib/rspec_sequel/matchers/validate_integer.rb +21 -0
- data/lib/rspec_sequel/matchers/validate_length_range.rb +25 -0
- data/lib/rspec_sequel/matchers/validate_max_length.rb +25 -0
- data/lib/rspec_sequel/matchers/validate_min_length.rb +25 -0
- data/lib/rspec_sequel/matchers/validate_not_string.rb +21 -0
- data/lib/rspec_sequel/matchers/validate_numeric.rb +21 -0
- data/lib/rspec_sequel/matchers/validate_presence.rb +21 -0
- data/lib/rspec_sequel/matchers/validate_unique.rb +33 -0
- data/lib/rspec_sequel/validation.rb +77 -0
- data/lib/rspec_sequel_matchers.rb +9 -0
- data/spec/have_column_matcher_spec.rb +89 -0
- data/spec/have_many_to_many_matcher_spec.rb +56 -0
- data/spec/have_many_to_one_matcher_spec.rb +55 -0
- data/spec/have_one_to_many_matcher_spec.rb +55 -0
- data/spec/migrations/001_create_items.rb +15 -0
- data/spec/migrations/002_create_comments.rb +17 -0
- data/spec/migrations/003_create_comments_items.rb +15 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/validate_exact_length_matcher_spec.rb +88 -0
- data/spec/validate_format_matcher_spec.rb +88 -0
- data/spec/validate_includes_matcher_spec.rb +88 -0
- data/spec/validate_integer_matcher_spec.rb +77 -0
- data/spec/validate_length_range_matcher_spec.rb +88 -0
- data/spec/validate_max_length_matcher_spec.rb +88 -0
- data/spec/validate_min_length_matcher_spec.rb +88 -0
- data/spec/validate_not_string_matcher_spec.rb +77 -0
- data/spec/validate_numeric_matcher_spec.rb +77 -0
- data/spec/validate_presence_matcher_spec.rb +77 -0
- data/spec/validate_unique_matcher_spec.rb +79 -0
- metadata +134 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
module RspecSequel
|
2
|
+
module Matchers
|
3
|
+
|
4
|
+
class ValidateMinLengthMatcher < RspecSequel::Validation
|
5
|
+
def description
|
6
|
+
desc = "validate length of #{@attribute.inspect} is greater than or equal to #{@additionnal.inspect}"
|
7
|
+
desc << " with option(s) #{hash_to_nice_string @options}" unless @options.empty?
|
8
|
+
desc
|
9
|
+
end
|
10
|
+
|
11
|
+
def additionnal_param_type
|
12
|
+
Fixnum
|
13
|
+
end
|
14
|
+
|
15
|
+
def validation_type
|
16
|
+
:validates_min_length
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def validate_min_length(*args)
|
21
|
+
ValidateMinLengthMatcher.new(*args)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module RspecSequel
|
2
|
+
module Matchers
|
3
|
+
|
4
|
+
class ValidateNotStringMatcher < RspecSequel::Validation
|
5
|
+
def description
|
6
|
+
desc = "validate that #{@attribute.inspect} is not a string"
|
7
|
+
desc << " with option(s) #{hash_to_nice_string @options}" unless @options.empty?
|
8
|
+
desc
|
9
|
+
end
|
10
|
+
|
11
|
+
def validation_type
|
12
|
+
:validates_not_string
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def validate_not_string(*args)
|
17
|
+
ValidateNotStringMatcher.new(*args)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module RspecSequel
|
2
|
+
module Matchers
|
3
|
+
|
4
|
+
class ValidateNumericMatcher < RspecSequel::Validation
|
5
|
+
def description
|
6
|
+
desc = "validate that #{@attribute.inspect} is a valid float"
|
7
|
+
desc << " with option(s) #{hash_to_nice_string @options}" unless @options.empty?
|
8
|
+
desc
|
9
|
+
end
|
10
|
+
|
11
|
+
def validation_type
|
12
|
+
:validates_numeric
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def validate_numeric(*args)
|
17
|
+
ValidateNumericMatcher.new(*args)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module RspecSequel
|
2
|
+
module Matchers
|
3
|
+
|
4
|
+
class ValidatePresenceMatcher < RspecSequel::Validation
|
5
|
+
def description
|
6
|
+
desc = "validate presence of #{@attribute.inspect}"
|
7
|
+
desc << " with option(s) #{hash_to_nice_string @options}" unless @options.empty?
|
8
|
+
desc
|
9
|
+
end
|
10
|
+
|
11
|
+
def validation_type
|
12
|
+
:validates_presence
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def validate_presence(*args)
|
17
|
+
ValidatePresenceMatcher.new(*args)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module RspecSequel
|
2
|
+
module Matchers
|
3
|
+
|
4
|
+
class ValidateUniqueMatcher < RspecSequel::Validation
|
5
|
+
def description
|
6
|
+
desc = "validate uniqueness of #{@attribute.inspect}"
|
7
|
+
desc << " with option(s) #{hash_to_nice_string @options}" unless @options.empty?
|
8
|
+
desc
|
9
|
+
end
|
10
|
+
|
11
|
+
def validation_type
|
12
|
+
:validates_unique
|
13
|
+
end
|
14
|
+
|
15
|
+
def valid_options
|
16
|
+
[:message]
|
17
|
+
end
|
18
|
+
|
19
|
+
def args_to_called_attributes(args)
|
20
|
+
called_attributes = []
|
21
|
+
until args.empty?
|
22
|
+
called_attributes << args.shift
|
23
|
+
end
|
24
|
+
called_attributes
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def validate_unique(*args)
|
29
|
+
ValidateUniqueMatcher.new(*args)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module RspecSequel
|
2
|
+
|
3
|
+
class Validation < Base
|
4
|
+
|
5
|
+
def initialize(*args)
|
6
|
+
# initialize Base
|
7
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
8
|
+
super(args.pop, options)
|
9
|
+
|
10
|
+
# check additionnal param
|
11
|
+
if additionnal_param_required?
|
12
|
+
if args.size>1
|
13
|
+
raise ArgumentError, "too many params for matcher"
|
14
|
+
else
|
15
|
+
@additionnal = args.pop
|
16
|
+
raise ArgumentError, "expected matcher first parameter to be #{additionnal_param_type.inspect} but received #{@additionnal.class.inspect} instead" unless @additionnal.kind_of?(additionnal_param_type)
|
17
|
+
end
|
18
|
+
else
|
19
|
+
raise ArgumentError, "too many params for matcher" unless args.empty?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def additionnal_param_type
|
24
|
+
NilClass
|
25
|
+
end
|
26
|
+
|
27
|
+
def additionnal_param_required?
|
28
|
+
additionnal_param_type!=NilClass
|
29
|
+
end
|
30
|
+
|
31
|
+
def valid_options
|
32
|
+
[:allow_blank, :allow_missing, :allow_nil, :message]
|
33
|
+
end
|
34
|
+
|
35
|
+
def valid?(db, i, c, attribute, options)
|
36
|
+
# check options
|
37
|
+
invalid_options = options.keys.reject{|o| valid_options.include?(o)}
|
38
|
+
invalid_options.each{|o|
|
39
|
+
@suffix << "but option #{o.inspect} is not valid"
|
40
|
+
}
|
41
|
+
return false unless invalid_options.empty?
|
42
|
+
|
43
|
+
# check validation itself
|
44
|
+
called_count = 0
|
45
|
+
i = i.dup
|
46
|
+
i.class.columns # ensure colums are read again after .dup
|
47
|
+
i.stub!(validation_type).and_return{|*args|
|
48
|
+
called_options = args.last.is_a?(Hash) ? args.pop : {}
|
49
|
+
called_attributes = args_to_called_attributes(args)
|
50
|
+
called_additionnal = args.shift if additionnal_param_required?
|
51
|
+
if !args.empty?
|
52
|
+
@suffix << "but called with too many params"
|
53
|
+
elsif called_attributes.include?(attribute)
|
54
|
+
if additionnal_param_required? && @additionnal!=called_additionnal
|
55
|
+
@suffix << "but called with #{called_additionnal} instead"
|
56
|
+
elsif !options.empty? && called_options!=options
|
57
|
+
@suffix << "but called with option(s) #{hash_to_nice_string called_options} instead"
|
58
|
+
else
|
59
|
+
called_count += 1
|
60
|
+
end
|
61
|
+
end
|
62
|
+
}
|
63
|
+
i.valid?
|
64
|
+
if called_count>1
|
65
|
+
@suffix << "but validation is called too many times"
|
66
|
+
return false
|
67
|
+
end
|
68
|
+
called_count==1
|
69
|
+
end
|
70
|
+
|
71
|
+
def args_to_called_attributes(args)
|
72
|
+
[args.pop].flatten
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# Load base
|
2
|
+
["base", "association", "validation"].each do |file|
|
3
|
+
require File.join(File.dirname(__FILE__), "rspec_sequel", file)
|
4
|
+
end
|
5
|
+
|
6
|
+
# Add matchers
|
7
|
+
Dir[File.join(File.dirname(__FILE__), "rspec_sequel", "matchers", "*.rb")].each do |file|
|
8
|
+
require file
|
9
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/spec_helper"
|
2
|
+
|
3
|
+
describe "have_column_matcher" do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
define_model :item
|
7
|
+
end
|
8
|
+
|
9
|
+
subject{ Item }
|
10
|
+
|
11
|
+
describe "messages" do
|
12
|
+
describe "without type" do
|
13
|
+
it "should contain a description" do
|
14
|
+
@matcher = have_column :name
|
15
|
+
@matcher.description.should == "have a column :name"
|
16
|
+
end
|
17
|
+
it "should set failure messages" do
|
18
|
+
@matcher = have_column :name
|
19
|
+
@matcher.matches? subject
|
20
|
+
@matcher.failure_message.should == "expected Item to " + @matcher.description
|
21
|
+
@matcher.negative_failure_message.should == "expected Item to not " + @matcher.description
|
22
|
+
end
|
23
|
+
end
|
24
|
+
describe "with type as symbol" do
|
25
|
+
it "should contain a description" do
|
26
|
+
@matcher = have_column :name, :type => :string
|
27
|
+
@matcher.description.should == "have a column :name with type string"
|
28
|
+
end
|
29
|
+
it "should set failure messages" do
|
30
|
+
@matcher = have_column :password, :type => :string
|
31
|
+
@matcher.matches? subject
|
32
|
+
@matcher.failure_message.should == "expected Item to " + @matcher.description
|
33
|
+
@matcher.negative_failure_message.should == "expected Item to not " + @matcher.description
|
34
|
+
end
|
35
|
+
end
|
36
|
+
describe "with type as object" do
|
37
|
+
it "should contain a description" do
|
38
|
+
@matcher = have_column :name, :type => String
|
39
|
+
@matcher.description.should == "have a column :name with type String"
|
40
|
+
end
|
41
|
+
it "should set failure messages" do
|
42
|
+
@matcher = have_column :password, :type => String
|
43
|
+
@matcher.matches? subject
|
44
|
+
@matcher.failure_message.should == "expected Item to " + @matcher.description
|
45
|
+
@matcher.negative_failure_message.should == "expected Item to not " + @matcher.description
|
46
|
+
end
|
47
|
+
it "should explicit found type if different than expected" do
|
48
|
+
@matcher = have_column :name, :type => Integer
|
49
|
+
@matcher.matches? subject
|
50
|
+
explanation = " (type found: string, varchar(255))"
|
51
|
+
@matcher.failure_message.should == "expected Item to " + @matcher.description + explanation
|
52
|
+
@matcher.negative_failure_message.should == "expected Item to not " + @matcher.description + explanation
|
53
|
+
end
|
54
|
+
end
|
55
|
+
describe "on anonymous Sequel::Model class" do
|
56
|
+
it "should set failure messages" do
|
57
|
+
@matcher = have_column :password
|
58
|
+
@matcher.matches? Sequel::Model(:comments)
|
59
|
+
@matcher.failure_message.should == "expected Comment to " + @matcher.description
|
60
|
+
@matcher.negative_failure_message.should == "expected Comment to not " + @matcher.description
|
61
|
+
end
|
62
|
+
end
|
63
|
+
describe "on Sequel::Model class" do
|
64
|
+
it "should set failure messages" do
|
65
|
+
@matcher = have_column :password
|
66
|
+
@matcher.matches? Item
|
67
|
+
@matcher.failure_message.should == "expected Item to " + @matcher.description
|
68
|
+
@matcher.negative_failure_message.should == "expected Item to not " + @matcher.description
|
69
|
+
end
|
70
|
+
end
|
71
|
+
describe "on Sequel::Model instance" do
|
72
|
+
it "should set failure messages" do
|
73
|
+
@matcher = have_column :password
|
74
|
+
@matcher.matches? Item.new
|
75
|
+
@matcher.failure_message.should == "expected #<Item @values={}> to " + @matcher.description
|
76
|
+
@matcher.negative_failure_message.should == "expected #<Item @values={}> to not " + @matcher.description
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "matchers" do
|
82
|
+
it{ should have_column(:name) }
|
83
|
+
it{ should have_column(:name, :type => :string) }
|
84
|
+
it{ should have_column(:name, :type => String) }
|
85
|
+
it{ should_not have_column(:password) }
|
86
|
+
it{ should_not have_column(:name, :type => :integer) }
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/spec_helper"
|
2
|
+
|
3
|
+
describe "have_many_to_many_matcher" do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
define_model :item
|
7
|
+
define_model :comment do
|
8
|
+
many_to_many :items
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
subject{ Comment }
|
13
|
+
|
14
|
+
describe "messages" do
|
15
|
+
describe "without option" do
|
16
|
+
it "should contain a description" do
|
17
|
+
@matcher = have_many_to_many :items
|
18
|
+
@matcher.description.should == "have a many_to_many association :items"
|
19
|
+
end
|
20
|
+
it "should set failure messages" do
|
21
|
+
@matcher = have_many_to_many :items
|
22
|
+
@matcher.matches? subject
|
23
|
+
@matcher.failure_message.should == "expected Comment to " + @matcher.description
|
24
|
+
@matcher.negative_failure_message.should == "expected Comment to not " + @matcher.description
|
25
|
+
end
|
26
|
+
end
|
27
|
+
describe "with options" do
|
28
|
+
it "should contain a description" do
|
29
|
+
@matcher = have_many_to_many :items, :class_name => "Item"
|
30
|
+
@matcher.description.should == 'have a many_to_many association :items with option(s) :class_name => "Item"'
|
31
|
+
end
|
32
|
+
it "should set failure messages" do
|
33
|
+
@matcher = have_many_to_many :items, :class_name => "Item"
|
34
|
+
@matcher.matches? subject
|
35
|
+
@matcher.failure_message.should == "expected Comment to " + @matcher.description
|
36
|
+
@matcher.negative_failure_message.should == "expected Comment to not " + @matcher.description
|
37
|
+
end
|
38
|
+
it "should explicit used options if different than expected" do
|
39
|
+
@matcher = have_many_to_many :items, :class_name => "Price"
|
40
|
+
@matcher.matches? subject
|
41
|
+
explanation = ' expected :class_name == "Price" but found "Item" instead'
|
42
|
+
@matcher.failure_message.should == "expected Comment to " + @matcher.description + explanation
|
43
|
+
@matcher.negative_failure_message.should == "expected Comment to not " + @matcher.description + explanation
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "matchers" do
|
49
|
+
it{ should have_many_to_many(:items) }
|
50
|
+
it{ should have_many_to_many(:items, :class_name => "Item", :join_table => :comments_items) }
|
51
|
+
it{ should_not have_many_to_many(:prices) }
|
52
|
+
it{ should_not have_many_to_many(:items, :class_name => "Price") }
|
53
|
+
it{ should_not have_many_to_many(:items, :join_table => :items_comments) }
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/spec_helper"
|
2
|
+
|
3
|
+
describe "have_many_to_one_matcher" do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
define_model :item
|
7
|
+
define_model :comment do
|
8
|
+
many_to_one :item
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
subject{ Comment }
|
13
|
+
|
14
|
+
describe "messages" do
|
15
|
+
describe "without option" do
|
16
|
+
it "should contain a description" do
|
17
|
+
@matcher = have_many_to_one :item
|
18
|
+
@matcher.description.should == "have a many_to_one association :item"
|
19
|
+
end
|
20
|
+
it "should set failure messages" do
|
21
|
+
@matcher = have_many_to_one :item
|
22
|
+
@matcher.matches? subject
|
23
|
+
@matcher.failure_message.should == "expected Comment to " + @matcher.description
|
24
|
+
@matcher.negative_failure_message.should == "expected Comment to not " + @matcher.description
|
25
|
+
end
|
26
|
+
end
|
27
|
+
describe "with options" do
|
28
|
+
it "should contain a description" do
|
29
|
+
@matcher = have_many_to_one :item, :class_name => "Item"
|
30
|
+
@matcher.description.should == 'have a many_to_one association :item with option(s) :class_name => "Item"'
|
31
|
+
end
|
32
|
+
it "should set failure messages" do
|
33
|
+
@matcher = have_many_to_one :item, :class_name => "Item"
|
34
|
+
@matcher.matches? subject
|
35
|
+
@matcher.failure_message.should == "expected Comment to " + @matcher.description
|
36
|
+
@matcher.negative_failure_message.should == "expected Comment to not " + @matcher.description
|
37
|
+
end
|
38
|
+
it "should explicit used options if different than expected" do
|
39
|
+
@matcher = have_many_to_one :item, :class_name => "Price"
|
40
|
+
@matcher.matches? subject
|
41
|
+
explanation = ' expected :class_name == "Price" but found "Item" instead'
|
42
|
+
@matcher.failure_message.should == "expected Comment to " + @matcher.description + explanation
|
43
|
+
@matcher.negative_failure_message.should == "expected Comment to not " + @matcher.description + explanation
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "matchers" do
|
49
|
+
it{ should have_many_to_one(:item) }
|
50
|
+
it{ should have_many_to_one(:item, :class_name => "Item") }
|
51
|
+
it{ should_not have_many_to_one(:price) }
|
52
|
+
it{ should_not have_many_to_one(:item, :class_name => "Price") }
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/spec_helper"
|
2
|
+
|
3
|
+
describe "have_one_to_many_matcher" do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
define_model :item do
|
7
|
+
one_to_many :comments
|
8
|
+
end
|
9
|
+
define_model :comment
|
10
|
+
end
|
11
|
+
|
12
|
+
subject{ Item }
|
13
|
+
|
14
|
+
describe "messages" do
|
15
|
+
describe "without option" do
|
16
|
+
it "should contain a description" do
|
17
|
+
@matcher = have_one_to_many :comments
|
18
|
+
@matcher.description.should == "have a one_to_many association :comments"
|
19
|
+
end
|
20
|
+
it "should set failure messages" do
|
21
|
+
@matcher = have_one_to_many :comments
|
22
|
+
@matcher.matches? subject
|
23
|
+
@matcher.failure_message.should == "expected Item to " + @matcher.description
|
24
|
+
@matcher.negative_failure_message.should == "expected Item to not " + @matcher.description
|
25
|
+
end
|
26
|
+
end
|
27
|
+
describe "with options" do
|
28
|
+
it "should contain a description" do
|
29
|
+
@matcher = have_one_to_many :comments, :class_name => "Comment"
|
30
|
+
@matcher.description.should == 'have a one_to_many association :comments with option(s) :class_name => "Comment"'
|
31
|
+
end
|
32
|
+
it "should set failure messages" do
|
33
|
+
@matcher = have_one_to_many :comments, :class_name => "Comment"
|
34
|
+
@matcher.matches? subject
|
35
|
+
@matcher.failure_message.should == "expected Item to " + @matcher.description
|
36
|
+
@matcher.negative_failure_message.should == "expected Item to not " + @matcher.description
|
37
|
+
end
|
38
|
+
it "should explicit used options if different than expected" do
|
39
|
+
@matcher = have_one_to_many :comments, :class_name => "Price"
|
40
|
+
@matcher.matches? subject
|
41
|
+
explanation = ' expected :class_name == "Price" but found "Comment" instead'
|
42
|
+
@matcher.failure_message.should == "expected Item to " + @matcher.description + explanation
|
43
|
+
@matcher.negative_failure_message.should == "expected Item to not " + @matcher.description + explanation
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "matchers" do
|
49
|
+
it{ should have_one_to_many(:comments) }
|
50
|
+
it{ should have_one_to_many(:comments, :class_name => "Comment") }
|
51
|
+
it{ should_not have_one_to_many(:prices) }
|
52
|
+
it{ should_not have_one_to_many(:comments, :class_name => "Price") }
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|