rspec-sequel_expectations 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,62 @@
1
+ module RSpec
2
+ module Matchers
3
+ module Sequel
4
+
5
+ class HavePrimaryKey
6
+
7
+ def matches?(subject)
8
+ @table = subject
9
+
10
+ get_keys
11
+
12
+ includes_all?
13
+ end
14
+
15
+ def description
16
+ %(have #{wording(@names)})
17
+ end
18
+
19
+ def failure_message
20
+ %(expected #{@table} to #{description} but #{@table} have #{wording(@keys)})
21
+ end
22
+
23
+ def failure_message_when_negated
24
+ %(did not expect #{@table} to #{description})
25
+ end
26
+
27
+ private
28
+
29
+ def initialize(*names)
30
+ @names = names
31
+ @keys = []
32
+ end
33
+
34
+ def get_keys
35
+ @keys = DB.schema(@table).reject { |tuple| !tuple.last[:primary_key] }.map(&:first)
36
+ end
37
+
38
+ def includes_all?
39
+ @names.reject { |k| @keys.include?(k) }.empty?
40
+ end
41
+
42
+ def wording(arr)
43
+ case arr.length
44
+ when 0
45
+ %(no primary keys)
46
+ when 1
47
+ %(primary key "#{arr.first}")
48
+ else
49
+ %(primary keys #{arr.inspect})
50
+ end
51
+ end
52
+
53
+ end
54
+
55
+ def have_primary_key(*names)
56
+ HavePrimaryKey.new(*names)
57
+ end
58
+ alias :have_primary_keys :have_primary_key
59
+
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,123 @@
1
+ module RSpec
2
+ module Matchers
3
+ module Sequel
4
+ class ReferTo
5
+ def matches?(subject)
6
+ get_reference_for(subject)
7
+
8
+ refer_to? && correct_fk? && correct_pk? && correct_update? && correct_delete?
9
+ end
10
+
11
+ def from_fk(key)
12
+ @foreign_key = key
13
+ self
14
+ end
15
+
16
+ def to_pk(key)
17
+ @primary_key = key
18
+ self
19
+ end
20
+
21
+ def on_update(action)
22
+ @on_update = action
23
+ self
24
+ end
25
+
26
+ def on_delete(action)
27
+ @on_delete = action
28
+ self
29
+ end
30
+
31
+ def description
32
+ text = [%(have reference to "#{@table}")]
33
+ text << %(with column "#{@foreign_key}") if @foreign_key
34
+ text << %(with primary key column "#{@primary_key}") if @primary_key
35
+ text << %(with "#{@on_update}" action on update) if @on_update
36
+ text << %(with "#{@on_delete}" action on delete) if @on_delete
37
+
38
+ text.join(' ')
39
+ end
40
+
41
+ def failure_message
42
+ %(expected "#{@relation}" to #{description} but #{@error})
43
+ end
44
+
45
+ def failure_message_when_negated
46
+ %(did not expect "#{@relation}" to #{description})
47
+ end
48
+
49
+ private
50
+
51
+ def initialize(table)
52
+ @table = table
53
+ @foreign_key = nil
54
+ @primary_key = nil
55
+ @on_update = nil
56
+ @on_delete = nil
57
+ end
58
+
59
+ def refer_to?
60
+ if @reference
61
+ true
62
+ else
63
+ @error = %("#{@relation}" does not have a reference to "#{@table}")
64
+ false
65
+ end
66
+ end
67
+
68
+ def correct_fk?
69
+ return true unless @foreign_key
70
+
71
+ if @reference[:columns].include?(@foreign_key)
72
+ true
73
+ else
74
+ @error = %("#{@relation}" does not have a foreign key column "#{@foreign_key}")
75
+ false
76
+ end
77
+ end
78
+
79
+ def correct_pk?
80
+ return true unless @primary_key
81
+
82
+ if @reference[:key].first == @primary_key
83
+ true
84
+ else
85
+ @error = %("#{@table}" does not have a primary key column "#{@primary_key}")
86
+ false
87
+ end
88
+ end
89
+
90
+ def correct_update?
91
+ return true unless @on_update
92
+
93
+ if @reference[:on_update] == @on_update
94
+ true
95
+ else
96
+ @error = %(reference does not have action "#{@on_update}" on update)
97
+ false
98
+ end
99
+ end
100
+
101
+ def correct_delete?
102
+ return true unless @on_delete
103
+
104
+ if @reference[:on_delete] == @on_delete
105
+ true
106
+ else
107
+ @error = %(reference does not have action "#{@on_delete}" on delete)
108
+ false
109
+ end
110
+ end
111
+
112
+ def get_reference_for(relation)
113
+ @relation = relation
114
+ @reference = DB.foreign_key_list(relation).select { |fk| fk[:table] == @table }.first
115
+ end
116
+ end
117
+
118
+ def refer_to(table)
119
+ ReferTo.new(table)
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,5 @@
1
+ module Rspec
2
+ module SequelExpectations
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rspec/sequel_expectations/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rspec-sequel_expectations"
8
+ spec.version = Rspec::SequelExpectations::VERSION
9
+ spec.authors = ["Andrey Savchenko"]
10
+ spec.email = ["andrey@aejis.eu"]
11
+ spec.summary = %q{RSpec matchers for Sequel}
12
+ spec.description = %q{RSpec matchers for Sequel which tests database, not model}
13
+ spec.homepage = "https://github.com/Ptico/rspec-sequel_expectations"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "sequel", "~> 4.15"
22
+ spec.add_dependency "rspec-expectations", "~> 3.0"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.6"
25
+ spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "sequel_pg"
27
+ spec.add_development_dependency "rspec", "~> 3.0"
28
+ spec.add_development_dependency "pry"
29
+ spec.add_development_dependency "faker"
30
+ end
@@ -0,0 +1,188 @@
1
+ require 'spec_helper'
2
+
3
+ describe RSpec::Matchers::Sequel::HaveColumn do
4
+ before :all do
5
+ DB.create_table(:users) do
6
+ column :full_name, String
7
+ column :age, Integer, default: 18, null: false
8
+ end
9
+ end
10
+
11
+ after :all do
12
+ DB.drop_table(:users)
13
+ end
14
+
15
+ let(:table) { :users }
16
+
17
+ let(:result) { matcher.matches?(table) }
18
+
19
+ describe 'column exists' do
20
+ context 'when exists' do
21
+ let(:matcher) { have_column(:full_name) }
22
+
23
+ it 'should success' do
24
+ expect(result).to be(true)
25
+ end
26
+
27
+ it 'should have description' do
28
+ expect(matcher.description).to eql('have column named "full_name"')
29
+ end
30
+ end
31
+
32
+ context 'column not exists' do
33
+ let(:matcher) { have_column(:abyrvalg) }
34
+
35
+ it 'should fail' do
36
+ expect(result).to be(false)
37
+ end
38
+
39
+ it 'should set error message' do
40
+ expect { result }.to change {
41
+ matcher.failure_message
42
+ }.to %(expected users to #{matcher.description} but users does not have a column named "abyrvalg")
43
+ end
44
+
45
+ it 'should set negative error message' do
46
+ expect { result }.to change {
47
+ matcher.failure_message_when_negated
48
+ }.to("did not expect users to #{matcher.description}")
49
+ end
50
+ end
51
+ end
52
+
53
+ describe 'column type' do
54
+ context 'when correct type' do
55
+ [String, :string, 'string', 'text'].each do |type|
56
+ context "with #{type}" do
57
+ let(:matcher) { have_column(:full_name).of_type(type) }
58
+
59
+ it 'should success' do
60
+ expect(result).to be(true)
61
+ end
62
+
63
+ it 'should have description' do
64
+ expect(matcher.description).to eql %(have column named "full_name" of type #{type})
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ context 'when incorrect type' do
71
+ let(:matcher) { have_column(:full_name).of_type(Integer) }
72
+
73
+ it 'should fail' do
74
+ expect(result).to be(false)
75
+ end
76
+
77
+ it 'should set error message' do
78
+ expect { result }.to change {
79
+ matcher.failure_message
80
+ }.to %(expected users to #{matcher.description} but it have type [string, text])
81
+ end
82
+
83
+ it 'should set negative error message' do
84
+ expect { result }.to change {
85
+ matcher.failure_message_when_negated
86
+ }.to %(did not expect users to #{matcher.description})
87
+ end
88
+ end
89
+ end
90
+
91
+ describe 'with_default' do
92
+ context 'when match' do
93
+ let(:matcher) { have_column(:age).with_default(18) }
94
+
95
+ it 'should success' do
96
+ expect(result).to be(true)
97
+ end
98
+
99
+ it 'should have description' do
100
+ expect(matcher.description).to eql('have column named "age" with default value "18"')
101
+ end
102
+ end
103
+
104
+ context 'when did not match' do
105
+ let(:matcher) { have_column(:age).with_default(2) }
106
+
107
+ it 'should fail' do
108
+ expect(result).to be(false)
109
+ end
110
+
111
+ it 'should have description' do
112
+ expect(matcher.description).to eql('have column named "age" with default value "2"')
113
+ end
114
+
115
+ it 'should set error message' do
116
+ expect { result }.to change {
117
+ matcher.failure_message
118
+ }.to %(expected users to #{matcher.description} but it has default value "18")
119
+ end
120
+ end
121
+ end
122
+
123
+ describe 'allow_null' do
124
+ context 'when match' do
125
+ let(:matcher) { have_column(:full_name).allow_null }
126
+
127
+ it 'should success' do
128
+ expect(result).to be(true)
129
+ end
130
+
131
+ it 'should have description' do
132
+ expect(matcher.description).to eql('have column named "full_name" allowing null')
133
+ end
134
+ end
135
+
136
+ context 'when did not match' do
137
+ let(:matcher) { have_column(:age).allow_null }
138
+
139
+ it 'should fail' do
140
+ expect(result).to be(false)
141
+ end
142
+
143
+ it 'should have description' do
144
+ expect(matcher.description).to eql('have column named "age" allowing null')
145
+ end
146
+
147
+ it 'should set error message' do
148
+ expect { result }.to change {
149
+ matcher.failure_message
150
+ }.to %(expected users to #{matcher.description} but it does not allow null)
151
+ end
152
+ end
153
+ end
154
+
155
+ describe 'not_null' do
156
+ context 'when match' do
157
+ let(:matcher) { have_column(:age).not_null }
158
+
159
+ it 'should success' do
160
+ expect(result).to be(true)
161
+ end
162
+
163
+ it 'should have description' do
164
+ expect(matcher.description).to eql('have column named "age" not allowing null')
165
+ end
166
+ end
167
+
168
+ context 'when did not match' do
169
+ let(:matcher) { have_column(:full_name).not_null }
170
+
171
+ it 'should fail' do
172
+ expect(result).to be(false)
173
+ end
174
+
175
+ it 'should have description' do
176
+ expect(matcher.description).to eql('have column named "full_name" not allowing null')
177
+ end
178
+
179
+ it 'should set error message' do
180
+ expect { result }.to change {
181
+ matcher.failure_message
182
+ }.to %(expected users to #{matcher.description} but it allow null)
183
+ end
184
+ end
185
+ end
186
+
187
+
188
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe RSpec::Matchers::Sequel::HaveEnum do
4
+ before :all do
5
+ @enum_name = Faker::Lorem.word
6
+ @values = %w(admin manager user inspector)
7
+ DB.create_enum(@enum_name, @values)
8
+ end
9
+
10
+ after :all do
11
+ DB.drop_enum(@enum_name)
12
+ end
13
+
14
+ describe '#have_enum' do
15
+ it 'return true if enum exists' do
16
+ expect(DB).to have_enum(@enum_name)
17
+ end
18
+
19
+ it 'accept symbol as enum name' do
20
+ expect(DB).to have_enum(@enum_name.to_sym)
21
+ end
22
+
23
+ it 'return false if enum does not exists' do
24
+ expect(DB).to_not have_enum(@enum_name + "1")
25
+ end
26
+ end
27
+
28
+ describe '#with_values' do
29
+
30
+ it 'returns true if enum have exactly that values' do
31
+ expect(DB).to have_enum(@enum_name).with_values(@values)
32
+ end
33
+
34
+ it 'returns false if enum values differ' do
35
+ expect(DB).not_to have_enum(@enum_name).with_values(@values.dup.push "something_new" )
36
+ end
37
+ end
38
+ end