sequel_spec 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE +22 -0
  6. data/README.md +91 -0
  7. data/Rakefile +1 -0
  8. data/lib/sequel_spec.rb +8 -0
  9. data/lib/sequel_spec/association.rb +13 -0
  10. data/lib/sequel_spec/association/association_matcher.rb +32 -0
  11. data/lib/sequel_spec/association/have_many_to_many_matcher.rb +15 -0
  12. data/lib/sequel_spec/association/have_many_to_one_matcher.rb +15 -0
  13. data/lib/sequel_spec/association/have_one_through_one_matcher.rb +15 -0
  14. data/lib/sequel_spec/association/have_one_to_many_matcher.rb +15 -0
  15. data/lib/sequel_spec/association/have_one_to_one_matcher.rb +15 -0
  16. data/lib/sequel_spec/base.rb +45 -0
  17. data/lib/sequel_spec/integration/rspec.rb +6 -0
  18. data/lib/sequel_spec/validation.rb +18 -0
  19. data/lib/sequel_spec/validation/validate_format_matcher.rb +42 -0
  20. data/lib/sequel_spec/validation/validate_includes_matcher.rb +43 -0
  21. data/lib/sequel_spec/validation/validate_integer_matcher.rb +23 -0
  22. data/lib/sequel_spec/validation/validate_length_matcher.rb +81 -0
  23. data/lib/sequel_spec/validation/validate_matcher.rb +67 -0
  24. data/lib/sequel_spec/validation/validate_not_null_matcher.rb +21 -0
  25. data/lib/sequel_spec/validation/validate_numeric_matcher.rb +23 -0
  26. data/lib/sequel_spec/validation/validate_presence_matcher.rb +23 -0
  27. data/lib/sequel_spec/validation/validate_schema_types_matcher.rb +23 -0
  28. data/lib/sequel_spec/validation/validate_type_matcher.rb +42 -0
  29. data/lib/sequel_spec/validation/validate_unique_matcher.rb +31 -0
  30. data/lib/sequel_spec/version.rb +3 -0
  31. data/sequel_spec.gemspec +25 -0
  32. data/spec/migrations/001_create_tables.rb +26 -0
  33. data/spec/sequel_spec/association/have_many_to_many_matcher_spec.rb +57 -0
  34. data/spec/sequel_spec/association/have_many_to_one_matcher_spec.rb +57 -0
  35. data/spec/sequel_spec/association/have_one_through_one_matcher_spec.rb +57 -0
  36. data/spec/sequel_spec/association/have_one_to_many_matcher_spec.rb +57 -0
  37. data/spec/sequel_spec/association/have_one_to_one_matcher_spec.rb +57 -0
  38. data/spec/sequel_spec/validation/validate_format_matcher_spec.rb +88 -0
  39. data/spec/sequel_spec/validation/validate_includes_matcher_spec.rb +88 -0
  40. data/spec/sequel_spec/validation/validate_integer_matcher_spec.rb +76 -0
  41. data/spec/sequel_spec/validation/validate_length_matcher_spec.rb +252 -0
  42. data/spec/sequel_spec/validation/validate_not_null_matcher_spec.rb +83 -0
  43. data/spec/sequel_spec/validation/validate_numeric_matcher_spec.rb +76 -0
  44. data/spec/sequel_spec/validation/validate_presence_matcher_spec.rb +77 -0
  45. data/spec/sequel_spec/validation/validate_schema_types_matcher_spec.rb +83 -0
  46. data/spec/sequel_spec/validation/validate_type_matcher_spec.rb +88 -0
  47. data/spec/sequel_spec/validation/validate_unique_matcher_spec.rb +83 -0
  48. data/spec/spec_helper.rb +33 -0
  49. data/spec/support/test_helpers.rb +19 -0
  50. 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
@@ -0,0 +1,3 @@
1
+ module SequelSpec
2
+ VERSION = "0.1.0".freeze
3
+ end
@@ -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