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.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rubocop.yml +181 -2
- data/.ruby-version +1 -0
- data/.travis.yml +24 -9
- data/Appraisals +108 -10
- data/Gemfile +9 -5
- data/README.md +24 -17
- data/Rakefile +18 -13
- data/gemfiles/rails_4_2.gemfile +31 -0
- data/gemfiles/rails_4_2.gemfile.lock +240 -0
- data/gemfiles/rails_5_0.gemfile +29 -0
- data/gemfiles/rails_5_0.gemfile.lock +232 -0
- data/gemfiles/rails_5_1.gemfile +30 -0
- data/gemfiles/rails_5_1.gemfile.lock +249 -0
- data/gemfiles/rails_5_2.gemfile +32 -0
- data/gemfiles/rails_5_2.gemfile.lock +268 -0
- data/gemfiles/rails_6_0.gemfile +34 -0
- data/gemfiles/rails_6_0.gemfile.lock +285 -0
- data/lib/shoulda/version.rb +1 -1
- data/script/install_gems_in_all_appraisals +16 -0
- data/script/run_all_tests +16 -0
- data/script/supported_ruby_versions +7 -0
- data/script/update_gem_in_all_appraisals +17 -0
- data/script/update_gems_in_all_appraisals +16 -0
- data/shoulda.gemspec +3 -3
- data/test/acceptance/integrates_with_rails_test.rb +580 -0
- data/test/acceptance_test_helper.rb +32 -6
- data/test/support/acceptance/add_shoulda_to_project.rb +13 -18
- data/test/support/acceptance/matchers/have_output.rb +2 -0
- data/test/support/acceptance/matchers/indicate_that_tests_were_run.rb +109 -0
- data/test/support/acceptance/rails_application_with_shoulda.rb +47 -0
- data/test/support/{tests/current_bundle.rb → current_bundle.rb} +4 -4
- data/test/support/snowglobe.rb +5 -0
- data/test/test_helper.rb +9 -4
- metadata +37 -65
- data/.hound/ruby.yml +0 -1042
- data/gemfiles/4.2.gemfile +0 -17
- data/gemfiles/4.2.gemfile.lock +0 -174
- data/gemfiles/5.0.gemfile +0 -17
- data/gemfiles/5.0.gemfile.lock +0 -179
- data/test/acceptance/rails_integration_test.rb +0 -76
- data/test/report_warnings.rb +0 -7
- data/test/support/acceptance/helpers.rb +0 -19
- data/test/support/acceptance/helpers/active_model_helpers.rb +0 -11
- data/test/support/acceptance/helpers/base_helpers.rb +0 -14
- data/test/support/acceptance/helpers/command_helpers.rb +0 -54
- data/test/support/acceptance/helpers/file_helpers.rb +0 -19
- data/test/support/acceptance/helpers/gem_helpers.rb +0 -31
- data/test/support/acceptance/helpers/step_helpers.rb +0 -69
- data/test/support/acceptance/matchers/indicate_number_of_tests_was_run_matcher.rb +0 -54
- data/test/support/acceptance/matchers/indicate_that_tests_were_run_matcher.rb +0 -75
- data/test/support/tests/bundle.rb +0 -94
- data/test/support/tests/command_runner.rb +0 -230
- data/test/support/tests/filesystem.rb +0 -100
- data/test/support/tests/version.rb +0 -45
- data/test/warnings_spy.rb +0 -62
- data/test/warnings_spy/filesystem.rb +0 -45
- data/test/warnings_spy/partitioner.rb +0 -36
- data/test/warnings_spy/reader.rb +0 -53
- 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
|
data/test/warnings_spy.rb
DELETED
@@ -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
|