shoulda 3.5.0 → 3.6.0

Sign up to get free protection for your applications and to get access to all the features.
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