shoulda 3.6.0 → 4.0.0.rc1

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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.rubocop.yml +181 -2
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +24 -9
  6. data/Appraisals +108 -10
  7. data/Gemfile +9 -5
  8. data/README.md +24 -17
  9. data/Rakefile +18 -13
  10. data/gemfiles/rails_4_2.gemfile +31 -0
  11. data/gemfiles/rails_4_2.gemfile.lock +240 -0
  12. data/gemfiles/rails_5_0.gemfile +29 -0
  13. data/gemfiles/rails_5_0.gemfile.lock +232 -0
  14. data/gemfiles/rails_5_1.gemfile +30 -0
  15. data/gemfiles/rails_5_1.gemfile.lock +249 -0
  16. data/gemfiles/rails_5_2.gemfile +32 -0
  17. data/gemfiles/rails_5_2.gemfile.lock +268 -0
  18. data/gemfiles/rails_6_0.gemfile +34 -0
  19. data/gemfiles/rails_6_0.gemfile.lock +285 -0
  20. data/lib/shoulda/version.rb +1 -1
  21. data/script/install_gems_in_all_appraisals +16 -0
  22. data/script/run_all_tests +16 -0
  23. data/script/supported_ruby_versions +7 -0
  24. data/script/update_gem_in_all_appraisals +17 -0
  25. data/script/update_gems_in_all_appraisals +16 -0
  26. data/shoulda.gemspec +3 -3
  27. data/test/acceptance/integrates_with_rails_test.rb +580 -0
  28. data/test/acceptance_test_helper.rb +32 -6
  29. data/test/support/acceptance/add_shoulda_to_project.rb +13 -18
  30. data/test/support/acceptance/matchers/have_output.rb +2 -0
  31. data/test/support/acceptance/matchers/indicate_that_tests_were_run.rb +109 -0
  32. data/test/support/acceptance/rails_application_with_shoulda.rb +47 -0
  33. data/test/support/{tests/current_bundle.rb → current_bundle.rb} +4 -4
  34. data/test/support/snowglobe.rb +5 -0
  35. data/test/test_helper.rb +9 -4
  36. metadata +37 -65
  37. data/.hound/ruby.yml +0 -1042
  38. data/gemfiles/4.2.gemfile +0 -17
  39. data/gemfiles/4.2.gemfile.lock +0 -174
  40. data/gemfiles/5.0.gemfile +0 -17
  41. data/gemfiles/5.0.gemfile.lock +0 -179
  42. data/test/acceptance/rails_integration_test.rb +0 -76
  43. data/test/report_warnings.rb +0 -7
  44. data/test/support/acceptance/helpers.rb +0 -19
  45. data/test/support/acceptance/helpers/active_model_helpers.rb +0 -11
  46. data/test/support/acceptance/helpers/base_helpers.rb +0 -14
  47. data/test/support/acceptance/helpers/command_helpers.rb +0 -54
  48. data/test/support/acceptance/helpers/file_helpers.rb +0 -19
  49. data/test/support/acceptance/helpers/gem_helpers.rb +0 -31
  50. data/test/support/acceptance/helpers/step_helpers.rb +0 -69
  51. data/test/support/acceptance/matchers/indicate_number_of_tests_was_run_matcher.rb +0 -54
  52. data/test/support/acceptance/matchers/indicate_that_tests_were_run_matcher.rb +0 -75
  53. data/test/support/tests/bundle.rb +0 -94
  54. data/test/support/tests/command_runner.rb +0 -230
  55. data/test/support/tests/filesystem.rb +0 -100
  56. data/test/support/tests/version.rb +0 -45
  57. data/test/warnings_spy.rb +0 -62
  58. data/test/warnings_spy/filesystem.rb +0 -45
  59. data/test/warnings_spy/partitioner.rb +0 -36
  60. data/test/warnings_spy/reader.rb +0 -53
  61. data/test/warnings_spy/reporter.rb +0 -88
@@ -1,230 +0,0 @@
1
- require 'timeout'
2
- require 'shellwords'
3
-
4
- module Tests
5
- class CommandRunner
6
- TimeoutError = Class.new(StandardError)
7
-
8
- def self.run(*args)
9
- new(*args).tap do |runner|
10
- yield runner
11
- runner.call
12
- end
13
- end
14
-
15
- def self.run!(*args)
16
- run(*args) do |runner|
17
- runner.run_successfully = true
18
- yield runner if block_given?
19
- end
20
- end
21
-
22
- attr_reader :status, :options, :env
23
- attr_accessor :command_prefix, :run_quickly, :run_successfully, :retries,
24
- :timeout
25
-
26
- def initialize(*args)
27
- @reader, @writer = IO.pipe
28
- options = (args.last.is_a?(Hash) ? args.pop : {})
29
- @args = args
30
- @options = options.merge(
31
- err: [:child, :out],
32
- out: writer,
33
- )
34
- @env = extract_env_from(@options)
35
-
36
- @wrapper = ->(block) { block.call }
37
- @command_prefix = ''
38
- self.directory = Dir.pwd
39
- @run_quickly = false
40
- @run_successfully = false
41
- @retries = 1
42
- @num_times_run = 0
43
- @timeout = 20
44
- end
45
-
46
- def around_command(&block)
47
- @wrapper = block
48
- end
49
-
50
- def directory
51
- @options[:chdir]
52
- end
53
-
54
- def directory=(directory)
55
- @options[:chdir] = directory || Dir.pwd
56
- end
57
-
58
- def formatted_command
59
- [formatted_env, Shellwords.join(command)].
60
- select { |value| !value.empty? }.
61
- join(' ')
62
- end
63
-
64
- def call
65
- possibly_retrying do
66
- possibly_running_quickly do
67
- run_with_debugging
68
-
69
- if run_successfully && !success?
70
- fail!
71
- end
72
- end
73
- end
74
-
75
- self
76
- end
77
-
78
- def stop
79
- unless writer.closed?
80
- writer.close
81
- end
82
- end
83
-
84
- def output
85
- @_output ||= begin
86
- stop
87
- without_colors(reader.read)
88
- end
89
- end
90
-
91
- def elided_output
92
- lines = output.split(/\n/)
93
- new_lines = lines[0..4]
94
-
95
- if lines.size > 10
96
- new_lines << "(...#{lines.size - 10} more lines...)"
97
- end
98
-
99
- new_lines << lines[-5..-1]
100
- new_lines.join("\n")
101
- end
102
-
103
- def success?
104
- status.success?
105
- end
106
-
107
- def exit_status
108
- status.exitstatus
109
- end
110
-
111
- def fail!
112
- raise <<-MESSAGE
113
- Command #{formatted_command.inspect} exited with status #{exit_status}.
114
- Output:
115
- #{divider('START') + output + divider('END')}
116
- MESSAGE
117
- end
118
-
119
- def has_output?(expected_output)
120
- if expected_output.is_a?(Regexp)
121
- output =~ expected_output
122
- else
123
- output.include?(expected_output)
124
- end
125
- end
126
-
127
- protected
128
-
129
- attr_reader :args, :reader, :writer, :wrapper
130
-
131
- private
132
-
133
- def extract_env_from(options)
134
- options.delete(:env) { {} }.inject({}) do |hash, (key, value)|
135
- hash[key.to_s] = value
136
- hash
137
- end
138
- end
139
-
140
- def command
141
- ([command_prefix] + args).flatten.flat_map do |word|
142
- Shellwords.split(word)
143
- end
144
- end
145
-
146
- def formatted_env
147
- env.map { |key, value| "#{key}=#{value.inspect}" }.join(' ')
148
- end
149
-
150
- def run
151
- pid = spawn(env, *command, options)
152
- Process.waitpid(pid)
153
- @status = $?
154
- end
155
-
156
- def run_with_wrapper
157
- wrapper.call(method(:run))
158
- end
159
-
160
- def run_with_debugging
161
- debug { "\n\e[33mChanging to directory:\e[0m #{directory}" }
162
- debug { "\e[32mRunning command:\e[0m #{formatted_command}" }
163
-
164
- run_with_wrapper
165
-
166
- debug { "\n" + divider('START') + output + divider('END') }
167
- end
168
-
169
- def possibly_running_quickly(&block)
170
- if run_quickly
171
- begin
172
- Timeout.timeout(timeout, &block)
173
- rescue Timeout::Error
174
- stop
175
-
176
- message =
177
- "Command timed out after #{timeout} seconds: #{formatted_command}\n" +
178
- "Output:\n" +
179
- output
180
-
181
- raise TimeoutError, message
182
- end
183
- else
184
- yield
185
- end
186
- end
187
-
188
- def possibly_retrying
189
- begin
190
- @num_times_run += 1
191
- yield
192
- rescue => error
193
- debug { "#{error.class}: #{error.message}" }
194
-
195
- if @num_times_run < @retries
196
- sleep @num_times_run
197
- retry
198
- else
199
- raise error
200
- end
201
- end
202
- end
203
-
204
- def divider(title = '')
205
- total_length = 72
206
- start_length = 3
207
-
208
- string = ''
209
- string << ('-' * start_length)
210
- string << title
211
- string << '-' * (total_length - start_length - title.length)
212
- string << "\n"
213
- string
214
- end
215
-
216
- def without_colors(string)
217
- string.gsub(/\e\[\d+(?:;\d+)?m(.+?)\e\[0m/, '\1')
218
- end
219
-
220
- def debugging_enabled?
221
- ENV['DEBUG_COMMANDS'] == '1'
222
- end
223
-
224
- def debug
225
- if debugging_enabled?
226
- puts yield
227
- end
228
- end
229
- end
230
- end
@@ -1,100 +0,0 @@
1
- require 'fileutils'
2
-
3
- module Tests
4
- class Filesystem
5
- PROJECT_NAME = 'test-project'.freeze
6
- ROOT_DIRECTORY = Pathname.new('../../../..').expand_path(__FILE__)
7
- TEMP_DIRECTORY = ROOT_DIRECTORY.join('tmp/acceptance')
8
- PROJECT_DIRECTORY = TEMP_DIRECTORY.join(PROJECT_NAME)
9
-
10
- def root_directory
11
- ROOT_DIRECTORY
12
- end
13
-
14
- def temp_directory
15
- TEMP_DIRECTORY
16
- end
17
-
18
- def project_directory
19
- PROJECT_DIRECTORY
20
- end
21
-
22
- def wrap(path)
23
- if path.is_a?(Pathname)
24
- path
25
- else
26
- find_in_project(path)
27
- end
28
- end
29
-
30
- def within_project(&block)
31
- Dir.chdir(project_directory, &block)
32
- end
33
-
34
- def clean
35
- if temp_directory.exist?
36
- temp_directory.rmtree
37
- end
38
- end
39
-
40
- def create
41
- project_directory.mkpath
42
- end
43
-
44
- def find_in_project(path)
45
- project_directory.join(path)
46
- end
47
-
48
- def open(path, *args, &block)
49
- find_in_project(path).open(*args, &block)
50
- end
51
-
52
- def read(path)
53
- find_in_project(path).read
54
- end
55
-
56
- def write(path, content)
57
- pathname = wrap(path)
58
- create_parents_of(pathname)
59
- pathname.open('w') { |f| f.write(content) }
60
- end
61
-
62
- def create_parents_of(path)
63
- wrap(path).dirname.mkpath
64
- end
65
-
66
- def append_to_file(path, content, _options = {})
67
- create_parents_of(path)
68
- open(path, 'a') { |f| f.puts(content + "\n") }
69
- end
70
-
71
- def remove_from_file(path, pattern)
72
- unless pattern.is_a?(Regexp)
73
- pattern = Regexp.new('^' + Regexp.escape(pattern) + '$')
74
- end
75
-
76
- transform(path) do |lines|
77
- lines.reject { |line| line =~ pattern }
78
- end
79
- end
80
-
81
- def comment_lines_matching(path, pattern)
82
- transform(path) do |lines|
83
- lines.map do |line|
84
- if line =~ pattern
85
- "###{line}"
86
- else
87
- line
88
- end
89
- end
90
- end
91
- end
92
-
93
- def transform(path)
94
- content = read(path)
95
- lines = content.split(/\n/)
96
- transformed_lines = yield lines
97
- write(path, transformed_lines.join("\n") + "\n")
98
- end
99
- end
100
- end
@@ -1,45 +0,0 @@
1
- module Tests
2
- class Version
3
- def initialize(version)
4
- @version = Gem::Version.new(version.to_s + '')
5
- end
6
-
7
- def <(other_version)
8
- compare?(:<, other_version)
9
- end
10
-
11
- def <=(other_version)
12
- compare?(:<=, other_version)
13
- end
14
-
15
- def ==(other_version)
16
- compare?(:==, other_version)
17
- end
18
-
19
- def >=(other_version)
20
- compare?(:>=, other_version)
21
- end
22
-
23
- def >(other_version)
24
- compare?(:>, other_version)
25
- end
26
-
27
- def =~(other_version)
28
- Gem::Requirement.new(other_version).satisfied_by?(version)
29
- end
30
-
31
- def to_s
32
- version.to_s
33
- end
34
-
35
- protected
36
-
37
- attr_reader :version
38
-
39
- private
40
-
41
- def compare?(op, other_version)
42
- Gem::Requirement.new("#{op} #{other_version}").satisfied_by?(version)
43
- end
44
- end
45
- end
@@ -1,62 +0,0 @@
1
- require 'forwardable'
2
-
3
- require File.expand_path('../warnings_spy/filesystem', __FILE__)
4
- require File.expand_path('../warnings_spy/reader', __FILE__)
5
- require File.expand_path('../warnings_spy/partitioner', __FILE__)
6
- require File.expand_path('../warnings_spy/reporter', __FILE__)
7
-
8
- class WarningsSpy
9
- extend Forwardable
10
-
11
- def initialize(project_name)
12
- filesystem = Filesystem.new
13
- @warnings_file = filesystem.warnings_file
14
- @reader = Reader.new(filesystem)
15
- @partitioner = Partitioner.new(reader, filesystem)
16
- @reporter = Reporter.new(partitioner, filesystem, project_name)
17
- end
18
-
19
- def capture_warnings
20
- $stderr.reopen(warnings_file.path)
21
- end
22
-
23
- def report_warnings_at_exit
24
- at_exit do
25
- printing_exceptions do
26
- report_and_exit
27
- end
28
- end
29
- end
30
-
31
- protected
32
-
33
- attr_reader :warnings_file, :reader, :partitioner, :reporter
34
-
35
- private
36
-
37
- def_delegators :partitioner, :relevant_warning_groups,
38
- :irrelevant_warning_groups
39
-
40
- def report_and_exit
41
- reader.read
42
- partitioner.partition
43
- reporter.report
44
- fail_build_if_there_are_any_warnings
45
- end
46
-
47
- def fail_build_if_there_are_any_warnings
48
- if relevant_warning_groups.any?
49
- exit(1)
50
- end
51
- end
52
-
53
- def printing_exceptions
54
- yield
55
- rescue => error
56
- puts "\n--- ERROR IN AT_EXIT --------------------------------"
57
- puts "#{error.class}: #{error.message}"
58
- puts error.backtrace.join("\n")
59
- puts '-----------------------------------------------------'
60
- raise error
61
- end
62
- end
@@ -1,45 +0,0 @@
1
- require 'fileutils'
2
-
3
- class WarningsSpy
4
- class Filesystem
5
- PROJECT_DIR = File.expand_path('../../..', __FILE__)
6
- TEMP_DIR = File.join(PROJECT_DIR, 'tmp')
7
-
8
- def initialize
9
- @files_by_name = Hash.new do |hash, name|
10
- FileUtils.mkdir_p(TEMP_DIR)
11
- hash[name] = file_for(name)
12
- end
13
- end
14
-
15
- def warnings_file
16
- files_by_name['all_warnings']
17
- end
18
-
19
- def irrelevant_warnings_file
20
- files_by_name['irrelevant_warnings']
21
- end
22
-
23
- def relevant_warnings_file
24
- files_by_name['relevant_warnings']
25
- end
26
-
27
- def project_dir
28
- PROJECT_DIR
29
- end
30
-
31
- protected
32
-
33
- attr_reader :files_by_name
34
-
35
- private
36
-
37
- def path_for(name)
38
- File.join(TEMP_DIR, "#{name}.txt")
39
- end
40
-
41
- def file_for(name)
42
- File.open(path_for(name), 'w+')
43
- end
44
- end
45
- end