rspec-sequel_expectations 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.
@@ -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