minitest-sequel 0.1.0 → 0.2.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.
data/Rakefile CHANGED
@@ -1,10 +1,31 @@
1
- require "bundler/gem_tasks"
2
- require "rake/testtask"
1
+ OSX = RUBY_PLATFORM.match(/darwin/)
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
3
5
 
4
6
  Rake::TestTask.new(:spec) do |t|
5
- t.libs << "spec"
6
- t.libs << "lib"
7
+ t.libs << 'spec'
8
+ t.libs << 'lib'
7
9
  t.test_files = FileList['spec/**/*_spec.rb']
8
10
  end
9
11
 
10
12
  task :default => :spec
13
+
14
+ desc "Run specs with coverage"
15
+ task :coverage do
16
+ ENV['COVERAGE'] = '1'
17
+ Rake::Task['spec'].invoke
18
+ `open coverage/index.html` if OSX
19
+ end
20
+
21
+
22
+ desc 'Run Rubocop report'
23
+ task :rubocop do
24
+ res = `which rubocop`
25
+ if res != ""
26
+ `rubocop -f html -o ./rubocop/report.html lib/`
27
+ `open rubocop/report.html` if OSX
28
+ else
29
+ puts "\nERROR: 'rubocop' gem is not installed or available. Please install with 'gem install rubocop'."
30
+ end
31
+ end
@@ -0,0 +1,183 @@
1
+ require 'minitest/sequel'
2
+
3
+ # reopening to add association functionality
4
+ module Minitest::Assertions
5
+
6
+ # Test for a :one_to_one association for the current model
7
+ #
8
+ # let(:m) { Post.first }
9
+ #
10
+ # it { assert_association_one_to_one(m, :first_comment, { class: :Comment, order: :id }) }
11
+ # it { m.must_have_one_to_one_association(:first_comment, { class: :Comment, order: :id }) }
12
+ #
13
+ def assert_association_one_to_one(obj, attribute, opts = {}, msg = nil)
14
+ assert_association(obj.class, :one_to_one, attribute, opts, msg)
15
+ end
16
+
17
+ # Test for a :one_to_many association for the current model
18
+ #
19
+ # let(:m) { Post.first }
20
+ #
21
+ # it { assert_association_one_to_many(m, :comments) }
22
+ # it { m.must_have_one_to_many_association(:comments) }
23
+ #
24
+ def assert_association_one_to_many(obj, attribute, opts = {}, msg = nil)
25
+ assert_association(obj.class, :one_to_many, attribute, opts, msg)
26
+ end
27
+
28
+ # Test for a :many_to_one association for the current model
29
+ #
30
+ # let(:m) { Post.first }
31
+ #
32
+ # it { assert_association_many_to_one(m, :author) }
33
+ # it { m.must_have_many_to_one_association(:author) }
34
+ #
35
+ def assert_association_many_to_one(obj, attribute, opts = {}, msg = nil)
36
+ assert_association(obj.class, :many_to_one, attribute, opts, msg)
37
+ end
38
+
39
+ # Test for a :many_to_many association for the current model
40
+ #
41
+ # let(:m) { Post.first }
42
+ #
43
+ # it { assert_association_many_to_many(m, :tags) }
44
+ # it { m.must_have_many_to_many_association(:tags) }
45
+ #
46
+ def assert_association_many_to_many(obj, attribute, opts = {}, msg = nil)
47
+ assert_association(obj.class, :many_to_many, attribute, opts, msg)
48
+ end
49
+
50
+ # Test for associations for the current model by passing the :association_type
51
+ #
52
+ # it { assert_association(Post, :many_to_many, :tags) }
53
+ #
54
+ def assert_association(klass, association_type, attribute, opts = {}, msg = nil)
55
+ msg = msg.nil? ? '' : "#{msg}\n"
56
+ msg << "Expected #{klass.inspect} to have a #{association_type.inspect}"
57
+ msg << " association #{attribute.inspect}"
58
+ assoc = klass.association_reflection(attribute) || {}
59
+ if assoc.empty?
60
+ msg << " but no association '#{attribute.inspect}' was found"
61
+ arr = []
62
+ klass.associations.each do |a|
63
+ o = klass.association_reflection(a)
64
+ if o[:type] == :many_to_many
65
+ arr << {
66
+ attribute: o[:name],
67
+ type: o[:type],
68
+ class: o[:class_name].to_sym,
69
+ join_table: o[:join_table],
70
+ left_keys: o[:left_keys],
71
+ right_keys: o[:right_keys]
72
+ }
73
+ else
74
+ arr << {
75
+ attribute: o[:name],
76
+ type: o[:type],
77
+ class: o[:class_name].to_sym,
78
+ keys: o[:keys]
79
+ }
80
+ end
81
+ end
82
+ msg << " - \navailable associations are: [ #{arr.join(', ')} ]\n"
83
+ assert(false, msg)
84
+ else
85
+ matching = assoc[:type] == association_type
86
+ err_msg = []
87
+ conf_msg = []
88
+ opts.each do |key, value|
89
+ conf_msg << { key => value }
90
+ if assoc[key] != value
91
+ err_msg << { key => assoc[key] }
92
+ matching = false
93
+ end
94
+ end
95
+ msg << " with given options: #{conf_msg.join(', ')} but should be #{err_msg.join(', ')}"
96
+ assert(matching, msg)
97
+ end
98
+ end
99
+
100
+
101
+ # Test to ensure there is no :one_to_one association for the current model
102
+ #
103
+ # let(:m) { Post.first }
104
+ #
105
+ # it { refute_association_one_to_one(m, :first_comment, { class: :Comment, order: :id }) }
106
+ # it { m.must_have_one_to_one_association(:first_comment, { class: :Comment, order: :id }) }
107
+ #
108
+ def refute_association_one_to_one(obj, attribute, opts = {}, msg = nil)
109
+ refute_association(obj.class, :one_to_one, attribute, opts, msg)
110
+ end
111
+
112
+ # Test to ensure there is no :one_to_many association for the current model
113
+ #
114
+ # let(:m) { Post.first }
115
+ #
116
+ # it { refute_association_one_to_many(m, :comments) }
117
+ # it { m.must_have_one_to_many_association(:comments) }
118
+ #
119
+ def refute_association_one_to_many(obj, attribute, opts = {}, msg = nil)
120
+ refute_association(obj.class, :one_to_many, attribute, opts, msg)
121
+ end
122
+
123
+ # Test to ensure there is no :many_to_one association for the current model
124
+ #
125
+ # let(:m) { Post.first }
126
+ #
127
+ # it { refute_association_many_to_one(m, :author) }
128
+ # it { m.must_have_many_to_one_association(:author) }
129
+ #
130
+ def refute_association_many_to_one(obj, attribute, opts = {}, msg = nil)
131
+ refute_association(obj.class, :many_to_one, attribute, opts, msg)
132
+ end
133
+
134
+ # Test to ensure there is no :many_to_many association for the current model
135
+ #
136
+ # let(:m) { Post.first }
137
+ #
138
+ # it { refute_association_many_to_many(m, :tags) }
139
+ # it { m.must_have_many_to_many_association(:tags) }
140
+ #
141
+ def refute_association_many_to_many(obj, attribute, opts = {}, msg = nil)
142
+ refute_association(obj.class, :many_to_many, attribute, opts, msg)
143
+ end
144
+
145
+ # Test to ensure the current model does NOT have an association by type :association_type
146
+ #
147
+ # it { refute_association(Post, :many_to_many, :tags) }
148
+ #
149
+ def refute_association(klass, association_type, attribute, opts = {}, msg = nil)
150
+ msg = msg.nil? ? '' : "#{msg}\n"
151
+ msg << "Expected #{klass.inspect} to NOT have a #{association_type.inspect}"
152
+ msg << " association #{attribute.inspect}"
153
+ assoc = klass.association_reflection(attribute) || {}
154
+
155
+ if assoc.empty?
156
+ assert(true, msg)
157
+ else
158
+ matching = false if assoc[:type] == association_type
159
+ msg << ", but such an association was found"
160
+ assert(matching, msg)
161
+ end
162
+
163
+ end
164
+
165
+ end
166
+
167
+
168
+ # add support for Spec syntax
169
+ module Minitest::Expectations
170
+
171
+ infect_an_assertion :assert_association, :must_have_association, :reverse
172
+ infect_an_assertion :assert_association_one_to_one, :must_have_one_to_one_association, :reverse
173
+ infect_an_assertion :assert_association_one_to_many, :must_have_one_to_many_association, :reverse
174
+ infect_an_assertion :assert_association_many_to_one, :must_have_many_to_one_association, :reverse
175
+ infect_an_assertion :assert_association_many_to_many, :must_have_many_to_many_association, :reverse
176
+
177
+ infect_an_assertion :refute_association, :wont_have_association, :reverse
178
+ infect_an_assertion :refute_association_one_to_one, :wont_have_one_to_one_association, :reverse
179
+ infect_an_assertion :refute_association_one_to_many, :wont_have_one_to_many_association, :reverse
180
+ infect_an_assertion :refute_association_many_to_one, :wont_have_many_to_one_association, :reverse
181
+ infect_an_assertion :refute_association_many_to_many, :wont_have_many_to_many_association, :reverse
182
+
183
+ end
@@ -0,0 +1,161 @@
1
+ require 'minitest/sequel'
2
+
3
+ # reopening to add schema validation functionality
4
+ module Minitest::Assertions
5
+
6
+ # Conveniently test your Model definitions as follows:
7
+ #
8
+ # let(:m) { Post.first }
9
+ #
10
+ # it { assert_have_column(m, :title, type: :string, db_type: 'varchar(250)') }
11
+ # it { m.must_have_column(:title, type: :string, db_type: 'varchar(250)') }
12
+ #
13
+ # # assert_have_column(<instance>, <column_name>, <options>, <custom_error_message>)
14
+ #
15
+ # # <instance>.must_have_column(<column_name>, <options>, <custom_error_message>)
16
+ #
17
+ #
18
+ # `assert_have_column()` first tests if the column name is defined in the Model and then checks
19
+ # all passed options. The following options are valid and checked:
20
+ #
21
+ # * :type
22
+ # * :db_type
23
+ # * :allow_null
24
+ # * :max_length
25
+ # * :default
26
+ # * :primary_key
27
+ # * :auto_increment
28
+ #
29
+ # In the event the specs differ from the actual database implementation an extensive error
30
+ # message with the differing option(s) is provided to help speed up debugging the issue:
31
+ #
32
+ # Expected Post model to have column: :title with: \
33
+ # { type: 'string', db_type: 'varchar(250)', allow_null: 'false' } \
34
+ # but found: { db_type: 'varchar(255)' }
35
+ #
36
+ #
37
+ # **Please NOTE!**
38
+ #
39
+ # To test options with a value that is either `nil`, `true` or `false`, please use `:nil`,
40
+ # `:false` or `:true` and provide numbers as 'strings' instead.
41
+ #
42
+ #
43
+ def assert_have_column(obj, attribute, opts = {}, msg = nil)
44
+ msg = msg.nil? ? '' : "#{msg}\n"
45
+ msg << "Expected #{obj.class} model to have column: :#{attribute}"
46
+ err_msg = []
47
+ conf_msg = []
48
+ # check if column exists
49
+ col = obj.db.schema(obj.class.table_name).detect { |c| c[0] == attribute }
50
+ matching = !col.nil?
51
+
52
+ # bail out if no matching column
53
+ unless matching
54
+ msg << ' but no such column exists'
55
+ assert(false, msg)
56
+ end
57
+
58
+ # bail out if options provided are invalid
59
+ val_opts = [:type, :db_type, :allow_null, :max_length, :default, :primary_key, :auto_increment]
60
+ invalid_opts = opts.keys.reject { |o| val_opts.include?(o) }
61
+ unless invalid_opts.empty?
62
+ msg << ', but the following invalid option(s) was found: { '
63
+ invalid_opts.each { |o| msg << "#{o.inspect}; " }
64
+ msg << " }. Valid options are: #{val_opts.inspect}"
65
+ assert(false, msg)
66
+ end
67
+
68
+ # TODO: simplify this mess. quick fix didn't work, so look at it again when time permits.
69
+
70
+ unless opts[:type].nil?
71
+ expected = (col[1][:type].to_s == opts[:type].to_s)
72
+ conf_msg << "type: '#{opts[:type]}'"
73
+ unless expected
74
+ err_msg << "type: '#{col[1][:type]}'"
75
+ end
76
+ matching &&= expected
77
+ end
78
+
79
+ unless opts[:db_type].nil?
80
+ expected = (col[1][:db_type].to_s == opts[:db_type].to_s)
81
+ conf_msg << "db_type: '#{opts[:db_type]}'"
82
+ unless expected
83
+ err_msg << "db_type: '#{col[1][:db_type]}'"
84
+ end
85
+ matching &&= expected
86
+ end
87
+
88
+ unless opts[:max_length].nil?
89
+ expected = (col[1][:max_length] === opts[:max_length])
90
+ conf_msg << "max_length: '#{opts[:max_length]}'"
91
+ unless expected
92
+ err_msg << "max_length: '#{col[1][:max_length]}'"
93
+ end
94
+ matching &&= expected
95
+ end
96
+
97
+ unless opts[:allow_null].nil?
98
+ v = _convert_value(opts[:allow_null])
99
+ expected = (opts[:allow_null] === v)
100
+ conf_msg << "allow_null: '#{opts[:allow_null]}'"
101
+ unless expected
102
+ err_msg << "allow_null: '#{col[1][:allow_null]}'"
103
+ end
104
+ matching &&= expected
105
+ end
106
+
107
+ unless opts[:default].nil?
108
+ v = _convert_value(opts[:default])
109
+ expected = (col[1][:default] === v)
110
+ conf_msg << "default: '#{opts[:default]}'"
111
+ unless expected
112
+ err_msg << "default: '#{col[1][:default].inspect}'"
113
+ end
114
+ matching &&= expected
115
+ end
116
+
117
+ unless opts[:primary_key].nil?
118
+ v = _convert_value(opts[:primary_key])
119
+ expected = (col[1][:primary_key] === v)
120
+ conf_msg << "primary_key: '#{opts[:primary_key]}'"
121
+ unless expected
122
+ err_msg << "primary_key: '#{col[1][:primary_key]}'"
123
+ end
124
+ matching &&= expected
125
+ end
126
+
127
+ unless opts[:auto_increment].nil?
128
+ v = _convert_value(opts[:auto_increment])
129
+ expected = (col[1][:auto_increment] === v)
130
+ conf_msg << "auto_increment: '#{opts[:auto_increment]}'"
131
+ unless expected
132
+ err_msg << "auto_increment: '#{col[1][:auto_increment]}'"
133
+ end
134
+ matching &&= expected
135
+ end
136
+
137
+ msg = msg << " with: { #{conf_msg.join(', ')} } but found: { #{err_msg.join(', ')} }"
138
+ assert(matching, msg)
139
+ end
140
+
141
+ #
142
+ def refute_have_column(obj, attribute, opts = {}, msg = nil)
143
+ msg = msg.nil? ? '' : "#{msg}\n"
144
+ msg << "Expected #{obj.class} model to NOT have column: :#{attribute}"
145
+ # check if column exists
146
+ col = obj.db.schema(obj.class.table_name).detect { |col| col[0] == attribute }
147
+ matching = col.nil?
148
+ unless matching
149
+ msg << ' but such a column was found'
150
+ assert(matching, msg)
151
+ end
152
+ end
153
+
154
+ end
155
+
156
+
157
+ # add support for Spec syntax
158
+ module Minitest::Expectations
159
+ infect_an_assertion :assert_have_column, :must_have_column, :reverse
160
+ infect_an_assertion :refute_have_column, :wont_have_column, :reverse
161
+ end