shoulda 3.5.0 → 3.6.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.
Files changed (54) hide show
  1. checksums.yaml +6 -14
  2. data/.gitignore +7 -7
  3. data/.hound.yml +3 -0
  4. data/.hound/ruby.yml +1042 -0
  5. data/.rubocop.yml +13 -0
  6. data/.travis.yml +11 -7
  7. data/Appraisals +13 -10
  8. data/CONTRIBUTING.md +6 -1
  9. data/Gemfile +8 -1
  10. data/README.md +58 -73
  11. data/Rakefile +21 -12
  12. data/gemfiles/4.2.gemfile +17 -0
  13. data/gemfiles/4.2.gemfile.lock +174 -0
  14. data/gemfiles/5.0.gemfile +17 -0
  15. data/gemfiles/5.0.gemfile.lock +179 -0
  16. data/lib/shoulda/version.rb +1 -1
  17. data/shoulda.gemspec +23 -23
  18. data/test/acceptance/rails_integration_test.rb +76 -0
  19. data/test/acceptance_test_helper.rb +17 -0
  20. data/test/report_warnings.rb +7 -0
  21. data/test/support/acceptance/add_shoulda_to_project.rb +78 -0
  22. data/test/support/acceptance/helpers.rb +19 -0
  23. data/test/support/acceptance/helpers/active_model_helpers.rb +11 -0
  24. data/test/support/acceptance/helpers/array_helpers.rb +13 -0
  25. data/test/support/acceptance/helpers/base_helpers.rb +14 -0
  26. data/test/support/acceptance/helpers/command_helpers.rb +54 -0
  27. data/test/support/acceptance/helpers/file_helpers.rb +19 -0
  28. data/test/support/acceptance/helpers/gem_helpers.rb +31 -0
  29. data/test/support/acceptance/helpers/pluralization_helpers.rb +13 -0
  30. data/test/support/acceptance/helpers/step_helpers.rb +69 -0
  31. data/test/support/acceptance/matchers/have_output.rb +31 -0
  32. data/test/support/acceptance/matchers/indicate_number_of_tests_was_run_matcher.rb +54 -0
  33. data/test/support/acceptance/matchers/indicate_that_tests_were_run_matcher.rb +75 -0
  34. data/test/support/tests/bundle.rb +94 -0
  35. data/test/support/tests/command_runner.rb +230 -0
  36. data/test/support/tests/current_bundle.rb +61 -0
  37. data/test/support/tests/filesystem.rb +100 -0
  38. data/test/support/tests/version.rb +45 -0
  39. data/test/test_helper.rb +18 -0
  40. data/test/warnings_spy.rb +62 -0
  41. data/test/warnings_spy/filesystem.rb +45 -0
  42. data/test/warnings_spy/partitioner.rb +36 -0
  43. data/test/warnings_spy/reader.rb +53 -0
  44. data/test/warnings_spy/reporter.rb +88 -0
  45. metadata +80 -121
  46. data/features/rails_integration.feature +0 -87
  47. data/features/step_definitions/rails_steps.rb +0 -77
  48. data/features/support/env.rb +0 -14
  49. data/gemfiles/3.0.gemfile +0 -7
  50. data/gemfiles/3.0.gemfile.lock +0 -127
  51. data/gemfiles/3.1.gemfile +0 -9
  52. data/gemfiles/3.1.gemfile.lock +0 -148
  53. data/gemfiles/3.2.gemfile +0 -9
  54. data/gemfiles/3.2.gemfile.lock +0 -146
@@ -0,0 +1,11 @@
1
+ require_relative 'gem_helpers'
2
+
3
+ module AcceptanceTests
4
+ module ActiveModelHelpers
5
+ include GemHelpers
6
+
7
+ def active_model_version
8
+ bundle_version_of('activemodel')
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ module AcceptanceTests
2
+ module ArrayHelpers
3
+ def to_sentence(array)
4
+ if array.size == 1
5
+ array[0]
6
+ elsif array.size == 2
7
+ array.join(' and ')
8
+ else
9
+ to_sentence(array[1..-2].join(', '), [array[-1]])
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ require_relative '../../tests/bundle'
2
+ require_relative '../../tests/filesystem'
3
+
4
+ module AcceptanceTests
5
+ module BaseHelpers
6
+ def fs
7
+ @_fs ||= Tests::Filesystem.new
8
+ end
9
+
10
+ def bundle
11
+ @_bundle ||= Tests::Bundle.new
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,54 @@
1
+ require_relative 'base_helpers'
2
+ require_relative '../../tests/command_runner'
3
+
4
+ module AcceptanceTests
5
+ module CommandHelpers
6
+ include BaseHelpers
7
+
8
+ def run_command(*args)
9
+ Tests::CommandRunner.run(*args) do |runner|
10
+ runner.directory = fs.project_directory
11
+ yield runner if block_given?
12
+ end
13
+ end
14
+
15
+ def run_command!(*args)
16
+ run_command(*args) do |runner|
17
+ runner.run_successfully = true
18
+ yield runner if block_given?
19
+ end
20
+ end
21
+
22
+ def run_command_within_bundle(*args)
23
+ run_command(*args) do |runner|
24
+ runner.command_prefix = 'bundle exec'
25
+ runner.env['BUNDLE_GEMFILE'] = fs.find_in_project('Gemfile').to_s
26
+
27
+ runner.around_command do |run_command|
28
+ Bundler.with_clean_env(&run_command)
29
+ end
30
+
31
+ yield runner if block_given?
32
+ end
33
+ end
34
+
35
+ def run_command_within_bundle!(*args)
36
+ run_command_within_bundle(*args) do |runner|
37
+ runner.run_successfully = true
38
+ yield runner if block_given?
39
+ end
40
+ end
41
+
42
+ def run_rake_tasks(*tasks)
43
+ options = tasks.last.is_a?(Hash) ? tasks.pop : {}
44
+ args = ['bundle', 'exec', 'rake', *tasks, '--trace'] + [options]
45
+ run_command(*args)
46
+ end
47
+
48
+ def run_rake_tasks!(*tasks)
49
+ options = tasks.last.is_a?(Hash) ? tasks.pop : {}
50
+ args = ['bundle', 'exec', 'rake', *tasks, '--trace'] + [options]
51
+ run_command!(*args)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,19 @@
1
+ require_relative 'base_helpers'
2
+
3
+ module AcceptanceTests
4
+ module FileHelpers
5
+ include BaseHelpers
6
+
7
+ def append_to_file(path, content, options = {})
8
+ fs.append_to_file(path, content, options)
9
+ end
10
+
11
+ def remove_from_file(path, pattern)
12
+ fs.remove_from_file(path, pattern)
13
+ end
14
+
15
+ def write_file(path, content)
16
+ fs.write(path, content)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,31 @@
1
+ require_relative 'base_helpers'
2
+ require_relative 'command_helpers'
3
+ require_relative 'file_helpers'
4
+
5
+ module AcceptanceTests
6
+ module GemHelpers
7
+ include BaseHelpers
8
+ include CommandHelpers
9
+ include FileHelpers
10
+
11
+ def add_gem(gem, *args)
12
+ bundle.add_gem(gem, *args)
13
+ end
14
+
15
+ def install_gems
16
+ bundle.install_gems
17
+ end
18
+
19
+ def updating_bundle(&block)
20
+ bundle.updating(&block)
21
+ end
22
+
23
+ def bundle_version_of(gem)
24
+ bundle.version_of(gem)
25
+ end
26
+
27
+ def bundle_includes?(gem)
28
+ bundle.includes?(gem)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,13 @@
1
+ module AcceptanceTests
2
+ module PluralizationHelpers
3
+ def pluralize(count, singular_version, plural_version = nil)
4
+ plural_version ||= singular_version + 's'
5
+
6
+ if count == 1
7
+ "#{count} #{singular_version}"
8
+ else
9
+ "#{count} #{plural_version}"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,69 @@
1
+ require_relative 'file_helpers'
2
+ require_relative 'gem_helpers'
3
+
4
+ module AcceptanceTests
5
+ module StepHelpers
6
+ include FileHelpers
7
+ include GemHelpers
8
+
9
+ def add_shoulda_to_project(options = {})
10
+ AddShouldaToProject.call(options)
11
+ end
12
+
13
+ def add_minitest_to_project
14
+ add_gem 'minitest-reporters'
15
+
16
+ append_to_file 'test/test_helper.rb', <<-FILE
17
+ require 'minitest/autorun'
18
+ require 'minitest/reporters'
19
+
20
+ Minitest::Reporters.use!(Minitest::Reporters::SpecReporter.new)
21
+ FILE
22
+ end
23
+
24
+ def run_n_unit_tests(*paths)
25
+ run_command_within_bundle 'ruby -I lib -I test', *paths
26
+ end
27
+
28
+ def run_n_unit_test_suite
29
+ run_rake_tasks('test', env: { TESTOPTS: '-v' })
30
+ end
31
+
32
+ def create_rails_application
33
+ fs.clean
34
+ rails_new
35
+ remove_unnecessary_gems
36
+ add_minitest_reporters_to_test_helper
37
+ end
38
+
39
+ private
40
+
41
+ def rails_new
42
+ command = "bundle exec rails new #{fs.project_directory} --skip-bundle --no-rc"
43
+
44
+ run_command!(command) do |runner|
45
+ runner.directory = nil
46
+ end
47
+
48
+ command
49
+ end
50
+
51
+ def remove_unnecessary_gems
52
+ updating_bundle do |bundle|
53
+ bundle.remove_gem 'turn'
54
+ bundle.remove_gem 'coffee-rails'
55
+ bundle.remove_gem 'uglifier'
56
+ bundle.remove_gem 'debugger'
57
+ bundle.remove_gem 'byebug'
58
+ bundle.remove_gem 'web-console'
59
+ end
60
+ end
61
+
62
+ def add_minitest_reporters_to_test_helper
63
+ fs.append_to_file 'test/test_helper.rb', <<-TEXT
64
+ require 'minitest/reporters'
65
+ Minitest::Reporters.use!(Minitest::Reporters::SpecReporter.new)
66
+ TEXT
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,31 @@
1
+ module AcceptanceTests
2
+ module Matchers
3
+ def have_output(output)
4
+ HaveOutputMatcher.new(output)
5
+ end
6
+
7
+ class HaveOutputMatcher
8
+ def initialize(output)
9
+ @output = output
10
+ end
11
+
12
+ def matches?(runner)
13
+ @runner = runner
14
+ runner.has_output?(output)
15
+ end
16
+
17
+ def failure_message
18
+ "Expected command to have output, but did not.\n\n" +
19
+ "Command: #{runner.formatted_command}\n\n" +
20
+ "Expected output:\n" +
21
+ output.inspect + "\n\n" +
22
+ "Actual output:\n" +
23
+ runner.output
24
+ end
25
+
26
+ protected
27
+
28
+ attr_reader :output, :runner
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,54 @@
1
+ require_relative '../helpers/pluralization_helpers'
2
+
3
+ module AcceptanceTests
4
+ module Matchers
5
+ def indicate_number_of_tests_was_run(expected_output)
6
+ IndicateNumberOfTestsWasRunMatcher.new(expected_output)
7
+ end
8
+
9
+ class IndicateNumberOfTestsWasRunMatcher
10
+ include PluralizationHelpers
11
+
12
+ def initialize(number)
13
+ @number = number
14
+ end
15
+
16
+ def matches?(runner)
17
+ @runner = runner
18
+ expected_output === actual_output
19
+ end
20
+
21
+ def failure_message
22
+ message = "Expected output to indicate that #{some_tests_were_run}.\n" +
23
+ "Expected output: #{expected_output}\n"
24
+
25
+ message <<
26
+ if actual_output.empty?
27
+ 'Actual output: (empty)'
28
+ else
29
+ "Actual output:\n#{actual_output}"
30
+ end
31
+
32
+ message
33
+ end
34
+
35
+ protected
36
+
37
+ attr_reader :number, :runner
38
+
39
+ private
40
+
41
+ def expected_output
42
+ /#{number} (?:tests?|runs?|examples?)(?:, #{number} assertions)?, 0 failures(?:, 0 errors(?:, 0 skips)?)?/
43
+ end
44
+
45
+ def actual_output
46
+ runner.output
47
+ end
48
+
49
+ def some_tests_were_run
50
+ pluralize(number, 'test was', 'tests were') + ' run'
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,75 @@
1
+ require_relative '../helpers/array_helpers'
2
+ require_relative '../helpers/pluralization_helpers'
3
+
4
+ module AcceptanceTests
5
+ module Matchers
6
+ def indicate_that_tests_were_run(series)
7
+ IndicateThatTestsWereRunMatcher.new(series)
8
+ end
9
+
10
+ class IndicateThatTestsWereRunMatcher
11
+ include ArrayHelpers
12
+ include PluralizationHelpers
13
+
14
+ def initialize(args)
15
+ @args = args
16
+ @series = args.values
17
+ end
18
+
19
+ def matches?(runner)
20
+ @runner = runner
21
+ !matching_expected_output.nil?
22
+ end
23
+
24
+ def failure_message
25
+ "Expected output to indicate that #{some_tests_were_run}.\n" +
26
+ "#{formatted_expected_output}\n" +
27
+ "#{formatted_actual_output}\n"
28
+ end
29
+
30
+ protected
31
+
32
+ attr_reader :args, :series, :runner
33
+
34
+ private
35
+
36
+ def matching_expected_output
37
+ @_matching_expected_output ||=
38
+ actual_output =~ expected_output
39
+ end
40
+
41
+ def expected_output
42
+ total = series.inject(:+)
43
+ /#{total} (tests|runs), #{total} assertions, 0 failures, 0 errors(, 0 skips)?/
44
+ end
45
+
46
+ def formatted_expected_output
47
+ if matching_expected_output
48
+ "Expected output:\n#{matching_actual_output}"
49
+ else
50
+ 'Expected output: (n/a)'
51
+ end
52
+ end
53
+
54
+ def actual_output
55
+ runner.output
56
+ end
57
+
58
+ def formatted_actual_output
59
+ if actual_output.empty?
60
+ 'Actual output: (empty)'
61
+ else
62
+ "Actual output:\n#{actual_output}"
63
+ end
64
+ end
65
+
66
+ def some_tests_were_run
67
+ clauses = args.map do |type, number|
68
+ pluralize(number, "#{type} test was run", "#{type} tests were run")
69
+ end
70
+
71
+ to_sentence(clauses)
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,94 @@
1
+ require_relative 'filesystem'
2
+ require_relative 'command_runner'
3
+ require_relative 'version'
4
+
5
+ module Tests
6
+ class Bundle
7
+ def initialize
8
+ @already_updating = false
9
+ @fs = Filesystem.new
10
+ end
11
+
12
+ def updating
13
+ if already_updating?
14
+ yield self
15
+ return
16
+ end
17
+
18
+ @already_updating = true
19
+
20
+ yield self
21
+
22
+ @already_updating = false
23
+
24
+ install_gems
25
+ end
26
+
27
+ def add_gem(gem, *args)
28
+ updating do
29
+ options = args.last.is_a?(Hash) ? args.pop : {}
30
+ version = args.shift
31
+ line = assemble_gem_line(gem, version, options)
32
+ fs.append_to_file('Gemfile', line)
33
+ end
34
+ end
35
+
36
+ def remove_gem(gem)
37
+ updating do
38
+ fs.comment_lines_matching('Gemfile', /^[ ]*gem ("|')#{gem}\1/)
39
+ end
40
+ end
41
+
42
+ def install_gems
43
+ CommandRunner.run!('bundle install --local') do |runner|
44
+ runner.retries = 5
45
+ end
46
+ end
47
+
48
+ def version_of(gem)
49
+ Version.new(Bundler.definition.specs[gem][0].version)
50
+ end
51
+
52
+ def includes?(gem)
53
+ Bundler.definition.dependencies.any? do |dependency|
54
+ dependency.name == gem
55
+ end
56
+ end
57
+
58
+ protected
59
+
60
+ attr_reader :fs
61
+
62
+ private
63
+
64
+ def already_updating?
65
+ @already_updating
66
+ end
67
+
68
+ def assemble_gem_line(gem, version, options)
69
+ formatted_options = options.
70
+ map { |key, value| "#{key}: #{formatted_value(value)}" }.
71
+ join(', ')
72
+
73
+ line = %(gem '#{gem}')
74
+
75
+ if version
76
+ line << %(, '#{version}')
77
+ end
78
+
79
+ if options.any?
80
+ line << %(, #{formatted_options})
81
+ end
82
+
83
+ line << "\n"
84
+ end
85
+
86
+ def formatted_value(value)
87
+ if value.is_a?(Pathname)
88
+ value.to_s.inspect
89
+ else
90
+ value.inspect
91
+ end
92
+ end
93
+ end
94
+ end