sequel_spec 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +91 -0
- data/Rakefile +1 -0
- data/lib/sequel_spec.rb +8 -0
- data/lib/sequel_spec/association.rb +13 -0
- data/lib/sequel_spec/association/association_matcher.rb +32 -0
- data/lib/sequel_spec/association/have_many_to_many_matcher.rb +15 -0
- data/lib/sequel_spec/association/have_many_to_one_matcher.rb +15 -0
- data/lib/sequel_spec/association/have_one_through_one_matcher.rb +15 -0
- data/lib/sequel_spec/association/have_one_to_many_matcher.rb +15 -0
- data/lib/sequel_spec/association/have_one_to_one_matcher.rb +15 -0
- data/lib/sequel_spec/base.rb +45 -0
- data/lib/sequel_spec/integration/rspec.rb +6 -0
- data/lib/sequel_spec/validation.rb +18 -0
- data/lib/sequel_spec/validation/validate_format_matcher.rb +42 -0
- data/lib/sequel_spec/validation/validate_includes_matcher.rb +43 -0
- data/lib/sequel_spec/validation/validate_integer_matcher.rb +23 -0
- data/lib/sequel_spec/validation/validate_length_matcher.rb +81 -0
- data/lib/sequel_spec/validation/validate_matcher.rb +67 -0
- data/lib/sequel_spec/validation/validate_not_null_matcher.rb +21 -0
- data/lib/sequel_spec/validation/validate_numeric_matcher.rb +23 -0
- data/lib/sequel_spec/validation/validate_presence_matcher.rb +23 -0
- data/lib/sequel_spec/validation/validate_schema_types_matcher.rb +23 -0
- data/lib/sequel_spec/validation/validate_type_matcher.rb +42 -0
- data/lib/sequel_spec/validation/validate_unique_matcher.rb +31 -0
- data/lib/sequel_spec/version.rb +3 -0
- data/sequel_spec.gemspec +25 -0
- data/spec/migrations/001_create_tables.rb +26 -0
- data/spec/sequel_spec/association/have_many_to_many_matcher_spec.rb +57 -0
- data/spec/sequel_spec/association/have_many_to_one_matcher_spec.rb +57 -0
- data/spec/sequel_spec/association/have_one_through_one_matcher_spec.rb +57 -0
- data/spec/sequel_spec/association/have_one_to_many_matcher_spec.rb +57 -0
- data/spec/sequel_spec/association/have_one_to_one_matcher_spec.rb +57 -0
- data/spec/sequel_spec/validation/validate_format_matcher_spec.rb +88 -0
- data/spec/sequel_spec/validation/validate_includes_matcher_spec.rb +88 -0
- data/spec/sequel_spec/validation/validate_integer_matcher_spec.rb +76 -0
- data/spec/sequel_spec/validation/validate_length_matcher_spec.rb +252 -0
- data/spec/sequel_spec/validation/validate_not_null_matcher_spec.rb +83 -0
- data/spec/sequel_spec/validation/validate_numeric_matcher_spec.rb +76 -0
- data/spec/sequel_spec/validation/validate_presence_matcher_spec.rb +77 -0
- data/spec/sequel_spec/validation/validate_schema_types_matcher_spec.rb +83 -0
- data/spec/sequel_spec/validation/validate_type_matcher_spec.rb +88 -0
- data/spec/sequel_spec/validation/validate_unique_matcher_spec.rb +83 -0
- data/spec/spec_helper.rb +33 -0
- data/spec/support/test_helpers.rb +19 -0
- metadata +164 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
module SequelSpec
|
2
|
+
module Matchers
|
3
|
+
module Validation
|
4
|
+
class ValidateIntegerMatcher < ValidateMatcher
|
5
|
+
def description
|
6
|
+
desc = "validate that #{@attribute.inspect} is a valid integer"
|
7
|
+
desc << " with option(s) #{hash_to_nice_string @options}" unless @options.empty?
|
8
|
+
desc
|
9
|
+
end
|
10
|
+
|
11
|
+
def validation_type
|
12
|
+
:validates_integer
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def validate_integer(attribute)
|
17
|
+
ValidateIntegerMatcher.new(attribute)
|
18
|
+
end
|
19
|
+
|
20
|
+
alias :validate_integrity_of :validate_integer
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module SequelSpec
|
2
|
+
module Matchers
|
3
|
+
module Validation
|
4
|
+
class ValidateLengthMatcher < ValidateMatcher
|
5
|
+
attr_reader :validation_type
|
6
|
+
|
7
|
+
def description
|
8
|
+
desc = "validate that length of #{@attribute.inspect} "
|
9
|
+
desc << case validation_type
|
10
|
+
when :validates_exact_length then "is exactly"
|
11
|
+
when :validates_min_length then "is greater than or equal to"
|
12
|
+
when :validates_max_length then "is less than or equal to"
|
13
|
+
when :validates_length_range then "is included in"
|
14
|
+
end << " #{@additionnal.inspect}"
|
15
|
+
|
16
|
+
desc << " with option(s) #{hash_to_nice_string @options}" unless @options.empty?
|
17
|
+
desc
|
18
|
+
end
|
19
|
+
|
20
|
+
def additionnal_param_required?
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
def additionnal_param_check
|
25
|
+
unless validation_type && @additionnal
|
26
|
+
raise ArgumentError, "You should specify the type of validation using #is, #is_at_least, #is_at_most or #is_between"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def is(value)
|
31
|
+
unless value.is_a?(Fixnum)
|
32
|
+
raise ArgumentError, "#is expects a Fixnum, #{value.class} given"
|
33
|
+
end
|
34
|
+
|
35
|
+
@additionnal = value
|
36
|
+
@validation_type = :validates_exact_length
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
alias :is_equal_to :is
|
41
|
+
|
42
|
+
def is_at_least(value)
|
43
|
+
unless value.is_a?(Fixnum)
|
44
|
+
raise ArgumentError, "#is_at_least expects a Fixnum, #{value.class} given"
|
45
|
+
end
|
46
|
+
|
47
|
+
@additionnal = value
|
48
|
+
@validation_type = :validates_min_length
|
49
|
+
self
|
50
|
+
end
|
51
|
+
|
52
|
+
def is_at_most(value)
|
53
|
+
unless value.is_a?(Fixnum)
|
54
|
+
raise ArgumentError, "#is_at_most expects a Fixnum, #{value.class} given"
|
55
|
+
end
|
56
|
+
|
57
|
+
@additionnal = value
|
58
|
+
@validation_type = :validates_max_length
|
59
|
+
self
|
60
|
+
end
|
61
|
+
|
62
|
+
def is_between(value)
|
63
|
+
unless value.is_a?(Range)
|
64
|
+
raise ArgumentError, "#is_between expects a Range, #{value.class} given"
|
65
|
+
end
|
66
|
+
|
67
|
+
@additionnal = value
|
68
|
+
@validation_type = :validates_length_range
|
69
|
+
self
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def validate_length(attribute)
|
74
|
+
ValidateLengthMatcher.new(attribute)
|
75
|
+
end
|
76
|
+
|
77
|
+
alias :validate_length_of :validate_length
|
78
|
+
alias :ensure_length_of :validate_length
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module SequelSpec
|
2
|
+
module Matchers
|
3
|
+
module Validation
|
4
|
+
class ValidateMatcher < Base
|
5
|
+
def valid?(db, instance, klass, attribute, options)
|
6
|
+
additionnal_param_check if self.respond_to?(:additionnal_param_check)
|
7
|
+
|
8
|
+
instance = instance.dup
|
9
|
+
instance.class.columns
|
10
|
+
|
11
|
+
called = false
|
12
|
+
|
13
|
+
proxy = Proc.new do |args|
|
14
|
+
called_options = args.last.is_a?(Hash) ? args.pop : {}
|
15
|
+
called_attributes = args_to_called_attributes(args)
|
16
|
+
called_additionnal = args.shift if additionnal_param_required?
|
17
|
+
|
18
|
+
if !args.empty?
|
19
|
+
@suffix << "but called with too many params"
|
20
|
+
elsif called_attributes.include?(attribute)
|
21
|
+
if additionnal_param_required? && @additionnal != called_additionnal
|
22
|
+
@suffix << "but called with #{called_additionnal} instead"
|
23
|
+
elsif !options.empty? && called_options != options
|
24
|
+
@suffix << "but called with option(s) #{hash_to_nice_string called_options} instead"
|
25
|
+
else
|
26
|
+
called = true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
instance.singleton_class.send(:define_method, validation_type,
|
32
|
+
Proc.new { |*args| proxy.call(args) }
|
33
|
+
)
|
34
|
+
|
35
|
+
# Run validations
|
36
|
+
instance.valid?
|
37
|
+
|
38
|
+
called
|
39
|
+
end
|
40
|
+
|
41
|
+
def allowing_nil
|
42
|
+
with_options :allow_nil => true
|
43
|
+
end
|
44
|
+
|
45
|
+
def allowing_blank
|
46
|
+
with_options :allow_blank => true
|
47
|
+
end
|
48
|
+
|
49
|
+
def allowing_missing
|
50
|
+
with_options :allow_missing => true
|
51
|
+
end
|
52
|
+
|
53
|
+
def with_message(message)
|
54
|
+
with_options :message => message
|
55
|
+
end
|
56
|
+
|
57
|
+
def additionnal_param_required?
|
58
|
+
false
|
59
|
+
end
|
60
|
+
|
61
|
+
def args_to_called_attributes(args)
|
62
|
+
[args.pop].flatten
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module SequelSpec
|
2
|
+
module Matchers
|
3
|
+
module Validation
|
4
|
+
class ValidateNotNullMatcher < ValidateMatcher
|
5
|
+
def description
|
6
|
+
desc = "validate that #{@attribute.inspect} is not null"
|
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_null
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def validate_not_null(attribute)
|
17
|
+
ValidateNotNullMatcher.new(attribute)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module SequelSpec
|
2
|
+
module Matchers
|
3
|
+
module Validation
|
4
|
+
class ValidateNumericMatcher < ValidateMatcher
|
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(attribute)
|
17
|
+
ValidateNumericMatcher.new(attribute)
|
18
|
+
end
|
19
|
+
|
20
|
+
alias :validate_numericality_of :validate_numeric
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module SequelSpec
|
2
|
+
module Matchers
|
3
|
+
module Validation
|
4
|
+
class ValidatePresenceMatcher < ValidateMatcher
|
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(attribute)
|
17
|
+
ValidatePresenceMatcher.new(attribute)
|
18
|
+
end
|
19
|
+
|
20
|
+
alias :validate_presence_of :validate_presence
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module SequelSpec
|
2
|
+
module Matchers
|
3
|
+
module Validation
|
4
|
+
class ValidateSchemaTypesMatcher < ValidateMatcher
|
5
|
+
def description
|
6
|
+
desc = "validate schema types 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_schema_types
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def validate_schema_types(attribute)
|
17
|
+
ValidateSchemaTypesMatcher.new(attribute)
|
18
|
+
end
|
19
|
+
|
20
|
+
alias :validate_schema_types_of :validate_schema_types
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module SequelSpec
|
2
|
+
module Matchers
|
3
|
+
module Validation
|
4
|
+
class ValidateTypeMatcher < ValidateMatcher
|
5
|
+
def description
|
6
|
+
desc = "validate that type of #{@attribute.inspect} is #{@additionnal.inspect}"
|
7
|
+
desc << " with option(s) #{hash_to_nice_string @options}" unless @options.empty?
|
8
|
+
desc
|
9
|
+
end
|
10
|
+
|
11
|
+
def additionnal_param_required?
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
def additionnal_param_check
|
16
|
+
unless @additionnal
|
17
|
+
raise ArgumentError, "You should specify the accepted types using #is"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def is(value)
|
22
|
+
unless value.is_a?(Class) || value.is_a?(Array)
|
23
|
+
raise ArgumentError, "#with expects a Class or an array of Classes"
|
24
|
+
end
|
25
|
+
|
26
|
+
@additionnal = value
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def validation_type
|
31
|
+
:validates_type
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def validate_type(attribute)
|
36
|
+
ValidateTypeMatcher.new(attribute)
|
37
|
+
end
|
38
|
+
|
39
|
+
alias :validate_type_of :validate_type
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module SequelSpec
|
2
|
+
module Matchers
|
3
|
+
module Validation
|
4
|
+
class ValidateUniqueMatcher < ValidateMatcher
|
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 args_to_called_attributes(args)
|
16
|
+
called_attributes = []
|
17
|
+
until args.empty?
|
18
|
+
called_attributes << args.shift
|
19
|
+
end
|
20
|
+
called_attributes
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def validate_unique(attribute)
|
25
|
+
ValidateUniqueMatcher.new(attribute)
|
26
|
+
end
|
27
|
+
|
28
|
+
alias :validate_uniqueness_of :validate_unique
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/sequel_spec.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
$: << File.expand_path('../lib', __FILE__)
|
3
|
+
|
4
|
+
require 'sequel_spec/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "sequel_spec"
|
8
|
+
spec.version = SequelSpec::VERSION
|
9
|
+
spec.authors = ["Adrià Planas", "Jonathan Tron", "Joseph Halter"]
|
10
|
+
spec.email = ["adriaplanas@liquidcodeworks.com"]
|
11
|
+
spec.summary = %q{RSpec Matchers for Sequel}
|
12
|
+
spec.homepage = "https://github.com/planas/sequel_spec"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.test_files = spec.files.grep('spec')
|
17
|
+
spec.require_paths = ["lib"]
|
18
|
+
|
19
|
+
spec.add_runtime_dependency "sequel", "~> 4.0"
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
22
|
+
spec.add_development_dependency "rspec", "~> 2.0"
|
23
|
+
spec.add_development_dependency "database_cleaner"
|
24
|
+
spec.add_development_dependency "sqlite3"
|
25
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
Sequel.migration do
|
2
|
+
change do
|
3
|
+
create_table :items do
|
4
|
+
primary_key :id
|
5
|
+
String :name
|
6
|
+
String :manufacturer
|
7
|
+
String :origin
|
8
|
+
String :owner
|
9
|
+
Float :price
|
10
|
+
end
|
11
|
+
|
12
|
+
create_table :comments do
|
13
|
+
primary_key :id
|
14
|
+
foreign_key :item_id, :items, :type => Fixnum
|
15
|
+
String :content
|
16
|
+
DateTime :created_at
|
17
|
+
index :item_id
|
18
|
+
end
|
19
|
+
|
20
|
+
create_table :comments_items do
|
21
|
+
foreign_key :comment_id, :comments, :type => Fixnum
|
22
|
+
foreign_key :item_id, :items, :type => Fixnum
|
23
|
+
index [:comment_id, :item_id], :unique => true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "have_many_to_many_matcher" do
|
4
|
+
before :all do
|
5
|
+
define_model :item
|
6
|
+
define_model :comment do
|
7
|
+
many_to_many :items
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
subject{ Comment }
|
12
|
+
|
13
|
+
describe "messages" do
|
14
|
+
describe "without option" do
|
15
|
+
it "should contain a description" do
|
16
|
+
@matcher = have_many_to_many :items
|
17
|
+
@matcher.description.should == "have a many_to_many association :items"
|
18
|
+
end
|
19
|
+
|
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).with_options :class_name => "Item"
|
30
|
+
@matcher.description.should == 'have a many_to_many association :items with option(s) :class_name => "Item"'
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should set failure messages" do
|
34
|
+
@matcher = have_many_to_many(:items).with_options :class_name => "Item"
|
35
|
+
@matcher.matches? subject
|
36
|
+
@matcher.failure_message.should == "expected Comment to " + @matcher.description
|
37
|
+
@matcher.negative_failure_message.should == "expected Comment to not " + @matcher.description
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should explicit used options if different than expected" do
|
41
|
+
@matcher = have_many_to_many(:items).with_options :class_name => "Price"
|
42
|
+
@matcher.matches? subject
|
43
|
+
explanation = ' expected :class_name == "Price" but found "Item" instead'
|
44
|
+
@matcher.failure_message.should == "expected Comment to " + @matcher.description + explanation
|
45
|
+
@matcher.negative_failure_message.should == "expected Comment to not " + @matcher.description + explanation
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "matchers" do
|
51
|
+
it{ should have_many_to_many(:items) }
|
52
|
+
it{ should have_many_to_many(:items).with_options :class_name => "Item", :join_table => :comments_items }
|
53
|
+
it{ should_not have_many_to_many(:prices) }
|
54
|
+
it{ should_not have_many_to_many(:items).with_options :class_name => "Price" }
|
55
|
+
it{ should_not have_many_to_many(:items).with_options :join_table => :items_comments }
|
56
|
+
end
|
57
|
+
end
|