rr 1.1.1 → 3.0.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 (223) hide show
  1. checksums.yaml +5 -5
  2. data/Appraisals +6 -0
  3. data/CHANGES.md +102 -1
  4. data/CREDITS.md +5 -0
  5. data/Gemfile +3 -0
  6. data/README.md +91 -110
  7. data/Rakefile +43 -0
  8. data/doc/02_syntax_comparison.md +1 -0
  9. data/gemfiles/ruby_19_rspec_2.gemfile +14 -0
  10. data/gemfiles/ruby_19_rspec_2.gemfile.lock +49 -0
  11. data/gemfiles/ruby_19_rspec_2_rails_4.gemfile +15 -0
  12. data/gemfiles/ruby_19_rspec_2_rails_4.gemfile.lock +119 -0
  13. data/lib/rr/class_instance_method_defined.rb +1 -1
  14. data/lib/rr/core_ext/array.rb +2 -0
  15. data/lib/rr/core_ext/hash.rb +2 -0
  16. data/lib/rr/deprecations.rb +97 -0
  17. data/lib/rr/double.rb +28 -10
  18. data/lib/rr/double_definitions/double_definition.rb +39 -16
  19. data/lib/rr/double_definitions/double_definition_create.rb +5 -5
  20. data/lib/rr/double_definitions/double_definition_create_blank_slate.rb +10 -4
  21. data/lib/rr/double_definitions/double_injections/any_instance_of.rb +1 -1
  22. data/lib/rr/double_definitions/double_injections/instance.rb +2 -2
  23. data/lib/rr/double_definitions/strategies/strategy.rb +27 -8
  24. data/lib/rr/double_definitions/strategies/verification/mock.rb +8 -2
  25. data/lib/rr/double_matches.rb +4 -3
  26. data/lib/rr/dsl.rb +152 -0
  27. data/lib/rr/expectations/any_argument_expectation.rb +4 -4
  28. data/lib/rr/expectations/argument_equality_expectation.rb +43 -5
  29. data/lib/rr/injections/double_injection.rb +67 -19
  30. data/lib/rr/injections/method_missing_injection.rb +37 -6
  31. data/lib/rr/integrations.rb +13 -12
  32. data/lib/rr/integrations/decorator.rb +4 -1
  33. data/lib/rr/integrations/minitest_4.rb +1 -1
  34. data/lib/rr/integrations/minitest_4_active_support.rb +1 -1
  35. data/lib/rr/integrations/rspec/invocation_matcher.rb +0 -8
  36. data/lib/rr/integrations/rspec_2.rb +28 -3
  37. data/lib/rr/keyword_arguments.rb +15 -0
  38. data/lib/rr/method_dispatches/base_method_dispatch.rb +22 -5
  39. data/lib/rr/method_dispatches/method_dispatch.rb +21 -10
  40. data/lib/rr/method_dispatches/method_missing_dispatch.rb +14 -5
  41. data/lib/rr/recorded_call.rb +35 -0
  42. data/lib/rr/recorded_calls.rb +23 -9
  43. data/lib/rr/space.rb +15 -5
  44. data/lib/rr/spy_verification.rb +13 -5
  45. data/lib/rr/version.rb +1 -2
  46. data/lib/rr/wildcard_matchers.rb +10 -10
  47. data/lib/rr/without_autohook.rb +7 -14
  48. data/rr.gemspec +14 -5
  49. data/spec/custom_formatter_for_rspec.rb +18 -0
  50. data/spec/custom_formatter_for_rspec_2.rb +40 -0
  51. data/spec/defines_spec_suite_tasks.rb +57 -0
  52. data/spec/fixtures/rubygems_patch_for_187.rb +598 -0
  53. data/spec/global_helper.rb +38 -0
  54. data/spec/spec.opts +3 -0
  55. data/spec/spec_suite_configuration.rb +126 -0
  56. data/spec/spec_suite_runner.rb +47 -0
  57. data/spec/suites.yml +10 -0
  58. data/spec/suites/rspec_2/functional/any_instance_of_spec.rb +147 -0
  59. data/spec/suites/rspec_2/functional/dont_allow_spec.rb +17 -0
  60. data/spec/suites/rspec_2/functional/mock_bang_spec.rb +20 -0
  61. data/spec/suites/rspec_2/functional/mock_instance_of_spec.rb +14 -0
  62. data/spec/suites/rspec_2/functional/mock_instance_of_strong_spec.rb +15 -0
  63. data/spec/suites/rspec_2/functional/mock_proxy_instance_of_spec.rb +15 -0
  64. data/spec/suites/rspec_2/functional/mock_proxy_spec.rb +14 -0
  65. data/spec/suites/rspec_2/functional/mock_spec.rb +17 -0
  66. data/spec/suites/rspec_2/functional/mock_strong_spec.rb +14 -0
  67. data/spec/suites/rspec_2/functional/received_spec.rb +16 -0
  68. data/spec/suites/rspec_2/functional/spy_spec.rb +102 -0
  69. data/spec/suites/rspec_2/functional/stub_bang_spec.rb +20 -0
  70. data/spec/suites/rspec_2/functional/stub_instance_of_spec.rb +15 -0
  71. data/spec/suites/rspec_2/functional/stub_instance_of_strong_spec.rb +15 -0
  72. data/spec/suites/rspec_2/functional/stub_proxy_instance_of_spec.rb +16 -0
  73. data/spec/suites/rspec_2/functional/stub_proxy_spec.rb +45 -0
  74. data/spec/suites/rspec_2/functional/stub_spec.rb +71 -0
  75. data/spec/suites/rspec_2/functional/stub_strong_spec.rb +15 -0
  76. data/spec/suites/rspec_2/functional/wildcard_matchers_spec.rb +128 -0
  77. data/spec/suites/rspec_2/helper.rb +28 -0
  78. data/spec/suites/rspec_2/integration/minitest_4_spec.rb +109 -0
  79. data/spec/suites/rspec_2/integration/minitest_spec.rb +109 -0
  80. data/spec/suites/rspec_2/spec_helper.rb +3 -0
  81. data/spec/suites/rspec_2/support/matchers/wildcard_matcher_matchers.rb +32 -0
  82. data/spec/suites/rspec_2/support/mixins/double_definition_creator_helpers.rb +173 -0
  83. data/spec/suites/rspec_2/support/mixins/mock_definition_creator_helpers.rb +45 -0
  84. data/spec/suites/rspec_2/support/mixins/proxy_definition_creator_helpers.rb +33 -0
  85. data/spec/suites/rspec_2/support/mixins/stub_creator_helpers.rb +43 -0
  86. data/spec/suites/rspec_2/support/mixins/stub_definition_creator_helpers.rb +45 -0
  87. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/argument_expectations_with_never_called_qualifier.rb +39 -0
  88. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/argument_expectations_with_times_called_qualifier.rb +50 -0
  89. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/argument_expectations_without_qualifiers.rb +131 -0
  90. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/dont_allow.rb +148 -0
  91. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/mock_instance_of.rb +26 -0
  92. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/mock_instance_of_strong.rb +28 -0
  93. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/mock_proxy.rb +11 -0
  94. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/mock_strong.rb +37 -0
  95. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/mocking.rb +107 -0
  96. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/stub_instance_of.rb +32 -0
  97. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/stub_instance_of_strong.rb +39 -0
  98. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/stub_proxy.rb +11 -0
  99. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/stub_strong.rb +37 -0
  100. data/spec/suites/rspec_2/support/shared_contexts/double_definition_creators/stubbing.rb +57 -0
  101. data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/array_flatten_bug.rb +35 -0
  102. data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/block_form.rb +31 -0
  103. data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/comparing_arity.rb +63 -0
  104. data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/object_is_proxy.rb +43 -0
  105. data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/sequential_invocations.rb +26 -0
  106. data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/setting_implementation.rb +51 -0
  107. data/spec/suites/rspec_2/support/shared_examples/double_definition_creators/yields.rb +81 -0
  108. data/spec/suites/rspec_2/support/shared_examples/space.rb +13 -0
  109. data/spec/suites/rspec_2/support/shared_examples/times_called_expectation.rb +9 -0
  110. data/spec/suites/rspec_2/unit/core_ext/array_spec.rb +39 -0
  111. data/spec/suites/rspec_2/unit/core_ext/enumerable_spec.rb +53 -0
  112. data/spec/suites/rspec_2/unit/core_ext/hash_spec.rb +55 -0
  113. data/spec/suites/rspec_2/unit/core_ext/range_spec.rb +41 -0
  114. data/spec/suites/rspec_2/unit/core_ext/regexp_spec.rb +41 -0
  115. data/spec/suites/rspec_2/unit/deprecations_spec.rb +27 -0
  116. data/spec/suites/rspec_2/unit/double_definitions/child_double_definition_create_spec.rb +114 -0
  117. data/spec/suites/rspec_2/unit/double_definitions/double_definition_create_blank_slate_spec.rb +93 -0
  118. data/spec/suites/rspec_2/unit/double_definitions/double_definition_create_spec.rb +446 -0
  119. data/spec/suites/rspec_2/unit/dsl/double_creators_spec.rb +133 -0
  120. data/spec/suites/rspec_2/unit/dsl/space_spec.rb +99 -0
  121. data/spec/suites/rspec_2/unit/dsl/wildcard_matchers_spec.rb +67 -0
  122. data/spec/suites/rspec_2/unit/errors/rr_error_spec.rb +67 -0
  123. data/spec/suites/rspec_2/unit/expectations/any_argument_expectation_spec.rb +48 -0
  124. data/spec/suites/rspec_2/unit/expectations/anything_argument_equality_expectation_spec.rb +14 -0
  125. data/spec/suites/rspec_2/unit/expectations/argument_equality_expectation_spec.rb +135 -0
  126. data/spec/suites/rspec_2/unit/expectations/boolean_argument_equality_expectation_spec.rb +30 -0
  127. data/spec/suites/rspec_2/unit/expectations/hash_including_argument_equality_expectation_spec.rb +92 -0
  128. data/spec/suites/rspec_2/unit/expectations/satisfy_argument_equality_expectation_spec.rb +61 -0
  129. data/spec/suites/rspec_2/unit/expectations/times_called_expectation/any_times_matcher_spec.rb +22 -0
  130. data/spec/suites/rspec_2/unit/expectations/times_called_expectation/at_least_matcher_spec.rb +37 -0
  131. data/spec/suites/rspec_2/unit/expectations/times_called_expectation/at_most_matcher_spec.rb +43 -0
  132. data/spec/suites/rspec_2/unit/expectations/times_called_expectation/integer_matcher_spec.rb +58 -0
  133. data/spec/suites/rspec_2/unit/expectations/times_called_expectation/proc_matcher_spec.rb +35 -0
  134. data/spec/suites/rspec_2/unit/expectations/times_called_expectation/range_matcher_spec.rb +39 -0
  135. data/spec/suites/rspec_2/unit/hash_with_object_id_key_spec.rb +88 -0
  136. data/spec/suites/rspec_2/unit/injections/double_injection/double_injection_spec.rb +533 -0
  137. data/spec/suites/rspec_2/unit/injections/double_injection/double_injection_verify_spec.rb +32 -0
  138. data/spec/suites/rspec_2/unit/integrations/rspec/invocation_matcher_spec.rb +297 -0
  139. data/spec/suites/rspec_2/unit/integrations/rspec_spec.rb +70 -0
  140. data/spec/suites/rspec_2/unit/rr_spec.rb +28 -0
  141. data/spec/suites/rspec_2/unit/space_spec.rb +598 -0
  142. data/spec/suites/rspec_2/unit/spy_verification_spec.rb +133 -0
  143. data/spec/suites/rspec_2/unit/times_called_matchers/any_times_matcher_spec.rb +46 -0
  144. data/spec/suites/rspec_2/unit/times_called_matchers/at_least_matcher_spec.rb +54 -0
  145. data/spec/suites/rspec_2/unit/times_called_matchers/at_most_matcher_spec.rb +69 -0
  146. data/spec/suites/rspec_2/unit/times_called_matchers/integer_matcher_spec.rb +69 -0
  147. data/spec/suites/rspec_2/unit/times_called_matchers/proc_matcher_spec.rb +54 -0
  148. data/spec/suites/rspec_2/unit/times_called_matchers/range_matcher_spec.rb +75 -0
  149. data/spec/suites/rspec_2/unit/times_called_matchers/times_called_matcher_spec.rb +117 -0
  150. data/spec/suites/rspec_2/unit/wildcard_matchers/anything_spec.rb +33 -0
  151. data/spec/suites/rspec_2/unit/wildcard_matchers/boolean_spec.rb +45 -0
  152. data/spec/suites/rspec_2/unit/wildcard_matchers/duck_type_spec.rb +64 -0
  153. data/spec/suites/rspec_2/unit/wildcard_matchers/hash_including_spec.rb +64 -0
  154. data/spec/suites/rspec_2/unit/wildcard_matchers/is_a_spec.rb +55 -0
  155. data/spec/suites/rspec_2/unit/wildcard_matchers/numeric_spec.rb +46 -0
  156. data/spec/suites/rspec_2/unit/wildcard_matchers/satisfy_spec.rb +57 -0
  157. data/spec/support/adapter.rb +22 -0
  158. data/spec/support/adapter_tests/base.rb +45 -0
  159. data/spec/support/adapter_tests/minitest.rb +7 -0
  160. data/spec/support/adapter_tests/rspec.rb +70 -0
  161. data/spec/support/adapter_tests/test_unit.rb +47 -0
  162. data/spec/support/command_runner.rb +105 -0
  163. data/spec/support/generator.rb +56 -0
  164. data/spec/support/integration_tests/base.rb +64 -0
  165. data/spec/support/integration_tests/rails.rb +60 -0
  166. data/spec/support/integration_tests/rails_minitest.rb +13 -0
  167. data/spec/support/integration_tests/rails_rspec.rb +13 -0
  168. data/spec/support/integration_tests/rails_test_unit.rb +13 -0
  169. data/spec/support/integration_tests/rails_test_unit_like.rb +13 -0
  170. data/spec/support/integration_tests/ruby.rb +7 -0
  171. data/spec/support/integration_tests/ruby_minitest.rb +13 -0
  172. data/spec/support/integration_tests/ruby_rspec.rb +13 -0
  173. data/spec/support/integration_tests/ruby_test_unit.rb +13 -0
  174. data/spec/support/matchers/be_a_subset_of_matcher.rb +24 -0
  175. data/spec/support/project/cucumber.rb +50 -0
  176. data/spec/support/project/generator.rb +348 -0
  177. data/spec/support/project/minitest.rb +39 -0
  178. data/spec/support/project/rails.rb +199 -0
  179. data/spec/support/project/rails_minitest.rb +17 -0
  180. data/spec/support/project/rails_rspec.rb +50 -0
  181. data/spec/support/project/rails_test_unit.rb +17 -0
  182. data/spec/support/project/rails_test_unit_like.rb +17 -0
  183. data/spec/support/project/rspec.rb +69 -0
  184. data/spec/support/project/ruby.rb +34 -0
  185. data/spec/support/project/ruby_minitest.rb +11 -0
  186. data/spec/support/project/ruby_rspec.rb +29 -0
  187. data/spec/support/project/ruby_test_unit.rb +11 -0
  188. data/spec/support/project/ruby_test_unit_like.rb +21 -0
  189. data/spec/support/project/test_unit.rb +29 -0
  190. data/spec/support/project/test_unit_like.rb +7 -0
  191. data/spec/support/project/tests_runner.rb +22 -0
  192. data/spec/support/test.sqlite3 +0 -0
  193. data/spec/support/test_case/generator.rb +53 -0
  194. data/spec/support/test_case/minitest.rb +13 -0
  195. data/spec/support/test_case/rspec.rb +19 -0
  196. data/spec/support/test_case/test_unit.rb +21 -0
  197. data/spec/support/test_file/generator.rb +120 -0
  198. data/spec/support/test_file/minitest.rb +19 -0
  199. data/spec/support/test_file/rails_minitest.rb +7 -0
  200. data/spec/support/test_file/rails_rspec.rb +12 -0
  201. data/spec/support/test_file/rails_test_unit.rb +25 -0
  202. data/spec/support/test_file/rspec.rb +33 -0
  203. data/spec/support/test_file/test_unit.rb +36 -0
  204. data/spec/support/test_helper/generator.rb +27 -0
  205. data/spec/support/test_helper/minitest.rb +7 -0
  206. data/spec/support/test_helper/rails.rb +31 -0
  207. data/spec/support/test_helper/rails_minitest.rb +7 -0
  208. data/spec/support/test_helper/rails_rspec.rb +25 -0
  209. data/spec/support/test_helper/rails_test_unit.rb +23 -0
  210. data/spec/support/test_helper/rspec.rb +7 -0
  211. data/spec/support/test_helper/ruby.rb +31 -0
  212. data/spec/support/test_helper/test_unit.rb +7 -0
  213. metadata +240 -19
  214. data/VERSION +0 -1
  215. data/lib/rr/adapters.rb +0 -44
  216. data/lib/rr/adapters/rr_methods.rb +0 -142
  217. data/lib/rr/integrations/rspec_1.rb +0 -46
  218. data/lib/rr/integrations/test_unit_1.rb +0 -63
  219. data/lib/rr/integrations/test_unit_2.rb +0 -15
  220. data/lib/rr/integrations/test_unit_200.rb +0 -27
  221. data/lib/rr/integrations/test_unit_200_active_support.rb +0 -25
  222. data/lib/rr/integrations/test_unit_2_active_support.rb +0 -38
  223. data/lib/rr/proc_from_block.rb +0 -11
@@ -0,0 +1,22 @@
1
+ require 'appraisal/file'
2
+
3
+ class Adapter
4
+ attr_reader :name
5
+
6
+ def initialize(name)
7
+ @name = name
8
+ end
9
+
10
+ def appraisal_name
11
+ parts = []
12
+ parts << 'ruby_19'
13
+ parts << name
14
+ parts.join('_')
15
+ end
16
+
17
+ def appraisal
18
+ @appraisal ||= Appraisal::File.new.appraisals.find do |appraisal|
19
+ appraisal.name == appraisal_name
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,45 @@
1
+ require 'set'
2
+
3
+ module AdapterTests
4
+ module Base
5
+ private
6
+
7
+ def assert_stubs_work
8
+ subject = Object.new
9
+ stub(subject).foobar { :baz }
10
+ assert_equal :baz, subject.foobar("any", "thing")
11
+ end
12
+
13
+ def assert_mocks_work
14
+ subject = Object.new
15
+ mock(subject).foobar(1, 2) { :baz }
16
+ assert_equal :baz, subject.foobar(1, 2)
17
+ end
18
+
19
+ def assert_stub_proxies_work
20
+ subject = Object.new
21
+ def subject.foobar; :baz; end
22
+ stub.proxy(subject).foobar
23
+ assert_equal :baz, subject.foobar
24
+ end
25
+
26
+ def assert_mock_proxies_work
27
+ subject = Object.new
28
+ def subject.foobar; :baz; end
29
+ mock.proxy(subject).foobar
30
+ assert_equal :baz, subject.foobar
31
+ end
32
+
33
+ def assert_times_called_verifications_work
34
+ subject = Object.new
35
+ mock(subject).foobar(1, 2) { :baz }
36
+ assert_raises RR::Errors.error_class(:TimesCalledError) do
37
+ RR.verify
38
+ end
39
+ end
40
+
41
+ def assert_adapters_loaded(matching_adapters)
42
+ assert_subset Set.new(matching_adapters), Set.new(RR.loaded_adapter_names)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,7 @@
1
+ require File.expand_path('../test_unit', __FILE__)
2
+
3
+ module AdapterTests
4
+ module Minitest
5
+ include TestUnit
6
+ end
7
+ end
@@ -0,0 +1,70 @@
1
+ require File.expand_path('../base', __FILE__)
2
+ require File.expand_path('../../matchers/be_a_subset_of_matcher', __FILE__)
3
+
4
+ module AdapterTests
5
+ module RSpec
6
+ include Base
7
+
8
+ def self.included(base)
9
+ base.class_eval do
10
+ specify 'stubs work' do
11
+ assert_stubs_work
12
+ end
13
+
14
+ specify 'mocks work' do
15
+ assert_mocks_work
16
+ end
17
+
18
+ specify 'stub proxies work' do
19
+ assert_stub_proxies_work
20
+ end
21
+
22
+ specify 'mock proxies work' do
23
+ assert_mock_proxies_work
24
+ end
25
+
26
+ specify 'times-called verifications work' do
27
+ assert_times_called_verifications_work
28
+ end
29
+
30
+ specify 'have_received works' do
31
+ subject = Object.new
32
+ stub(subject).foobar(1, 2)
33
+ subject.foobar(1, 2)
34
+ subject.should have_received.foobar(1, 2)
35
+
36
+ expect {
37
+ subject.should have_received.foobar(1, 2, 3)
38
+ }.to raise_error(
39
+ expectation_not_met_error,
40
+ /Expected foobar\(1, 2, 3\).+to be called 1 time/m
41
+ )
42
+ end
43
+ end
44
+ end
45
+
46
+ def expectation_not_met_error
47
+ if defined?(::RSpec)
48
+ ::RSpec::Expectations::ExpectationNotMetError
49
+ else
50
+ Spec::Expectations::ExpectationNotMetError
51
+ end
52
+ end
53
+
54
+ def assert_equal(expected, actual)
55
+ expected.should be == actual
56
+ end
57
+
58
+ def assert_subset(subset, set)
59
+ subset.should be_a_subset_of(set)
60
+ end
61
+
62
+ def assert_raises(error, &block)
63
+ expect(&block).to raise_error(error)
64
+ end
65
+
66
+ def be_a_subset_of(set)
67
+ BeASubsetOfMatcher.new(set)
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,47 @@
1
+ require File.expand_path('../base', __FILE__)
2
+
3
+ module AdapterTests
4
+ module TestUnit
5
+ include Base
6
+
7
+ def test_that_stubs_work
8
+ assert_stubs_work
9
+ end
10
+
11
+ def test_that_mocks_work
12
+ assert_mocks_work
13
+ end
14
+
15
+ def test_that_stub_proxies_work
16
+ assert_stub_proxies_work
17
+ end
18
+
19
+ def test_that_mock_proxies_work
20
+ assert_mock_proxies_work
21
+ end
22
+
23
+ def test_that_times_called_verifications_work
24
+ assert_times_called_verifications_work
25
+ end
26
+
27
+ def test_using_assert_received
28
+ subject = Object.new
29
+ stub(subject).foobar(1, 2)
30
+ subject.foobar(1, 2)
31
+ assert_received(subject) {|s| s.foobar(1, 2) }
32
+
33
+ error_class = RR::Errors.error_class(
34
+ RR::Errors::SpyVerificationErrors::InvocationCountError
35
+ )
36
+ assert_raises(error_class) do
37
+ assert_received(subject) {|s| s.foobar(1, 2, 3) }
38
+ end
39
+ end
40
+
41
+ def assert_subset(subset, set)
42
+ value = (subset - set).empty?
43
+ message = "Set 1 was not a subset of set 2.\nSet 1: #{subset.inspect}\nSet 2: #{set.inspect}"
44
+ assert value, message
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,105 @@
1
+ require 'open3'
2
+
3
+ class CommandRunner
4
+ # http://stackoverflow.com/questions/6407141/how-can-i-have-ruby-logger-log-output-to-stdout-as-well-as-file
5
+ class MultiIO
6
+ def initialize(*targets)
7
+ @targets = targets
8
+ end
9
+
10
+ def write(*args)
11
+ @targets.each {|t| t.write(*args) }
12
+ end
13
+ alias_method :<<, :write
14
+
15
+ def close
16
+ @targets.each(&:close)
17
+ end
18
+ end
19
+
20
+ def self.call(command, options={})
21
+ new(command, options).call
22
+ end
23
+
24
+ attr_reader :command, :output, :exit_status
25
+
26
+ def initialize(command, options)
27
+ @command = command
28
+ #@command << " 2>&1" unless @command =~ / 2>&1$/
29
+ @output = ""
30
+ end
31
+
32
+ def call
33
+ @stdout_buffer = StringIO.new
34
+
35
+ puts "Running: #{@command}"
36
+
37
+ if defined?(JRUBY_VERSION)
38
+ call_using_popen4
39
+ else
40
+ call_using_spawn
41
+ end
42
+
43
+ if RR.debug?
44
+ puts "~ Output from `#{@command}` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
45
+ puts @output
46
+ puts "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
47
+ end
48
+
49
+ self
50
+ end
51
+
52
+ def success?
53
+ @exit_status == 0
54
+ end
55
+
56
+ private
57
+
58
+ def call_using_session
59
+ reader, writer = IO.pipe
60
+ require 'session'
61
+ session = Session::Bash.new
62
+ session.execute(@command, :stdout => writer, :stderr => writer)
63
+ writer.close
64
+ @exit_status = session.exit_status
65
+ @output = reader.read
66
+ end
67
+
68
+ def call_using_popen4
69
+ reader, writer = IO.pipe
70
+
71
+ # Using popen4 here without a block will always result in an Errno::ECHILD
72
+ # error under JRuby: <http://jira.codehaus.org/browse/JRUBY-5684>
73
+ block = lambda { |pid, _, stdout, _| writer.write(stdout.read) }
74
+
75
+ if defined?(JRUBY_VERSION)
76
+ IO.popen4("#{@command} 2>&1", &block)
77
+ else
78
+ require 'open4'
79
+ Open4.popen4("#{@command} 2>&1", &block)
80
+ end
81
+
82
+ writer.close
83
+ @exit_status = $?.exitstatus
84
+ @output = reader.read
85
+ end
86
+
87
+ def call_using_spawn
88
+ reader, writer = IO.pipe
89
+ args = [@command, {[:out, :err] => writer}]
90
+ require 'posix-spawn'
91
+ pid = POSIX::Spawn.spawn(*args)
92
+ Process.waitpid(pid)
93
+ writer.close
94
+ @exit_status = $?.exitstatus
95
+ @output = reader.read
96
+ end
97
+
98
+ def build_stdout
99
+ ios = [@stdout_buffer]
100
+ #if RR.debug?
101
+ # ios << $stdout
102
+ #end
103
+ MultiIO.new(*ios)
104
+ end
105
+ end
@@ -0,0 +1,56 @@
1
+ module Generator
2
+ module ClassMethods
3
+ attr_reader :configurators
4
+
5
+ def factory
6
+ klass = Class.new(self)
7
+ yield klass if block_given?
8
+ klass
9
+ end
10
+
11
+ def call(*args, &block)
12
+ new(*args, &block).tap { |object| object.call }
13
+ end
14
+
15
+ def generate(&block)
16
+ factory.call(&block)
17
+ end
18
+
19
+ def mixin(mod)
20
+ include mod
21
+ end
22
+
23
+ def configure(&block)
24
+ configurators << block
25
+ end
26
+
27
+ def configurators
28
+ @configurators ||= []
29
+ end
30
+ end
31
+
32
+ def self.included(base)
33
+ base.extend(ClassMethods)
34
+ end
35
+
36
+ def initialize(*args)
37
+ setup(*args)
38
+ run_configurators
39
+ configure(*args)
40
+ yield self if block_given?
41
+ end
42
+
43
+ def setup(*args)
44
+ end
45
+
46
+ def configure(*args)
47
+ end
48
+
49
+ private
50
+
51
+ def run_configurators
52
+ self.class.configurators.each do |configurator|
53
+ configurator.call(self)
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,64 @@
1
+ require File.expand_path('../../project/generator', __FILE__)
2
+
3
+ module IntegrationTests
4
+ module Base
5
+ class FailWithOutputMatcher < Struct.new(:pattern)
6
+ def matches?(result)
7
+ result.output =~ pattern
8
+ end
9
+
10
+ def description
11
+ "fail with output #{pattern.inspect}"
12
+ end
13
+
14
+ def failure_message_for_should
15
+ "Expected running the test to produce output #{pattern.inspect} but it didn't"
16
+ end
17
+
18
+ def failure_message_for_should_not
19
+ "Expected running the test to not produce output #{pattern.inspect} but it did"
20
+ end
21
+ end
22
+
23
+ class HaveErrorsOrFailuresMatcher
24
+ def matches?(result)
25
+ match = result.output.match(/(\d+) error|(\d+) failure/)
26
+ match && match.captures.any? {|value| value && value.to_i > 0 }
27
+ end
28
+
29
+ def description
30
+ "have errors or failures"
31
+ end
32
+
33
+ def failure_message_for_should
34
+ "Expected running the test to result in errors or failures but it did not"
35
+ end
36
+
37
+ def failure_message_for_should_not
38
+ "Expected running the test to not result in errors or failures, but it did "
39
+ end
40
+ end
41
+
42
+ def build_project_generator
43
+ Project::Generator.factory do |project_generator|
44
+ configure_project_generator(project_generator)
45
+ yield project_generator if block_given?
46
+ end
47
+ end
48
+
49
+ def generate_project(&block)
50
+ build_project_generator.call(&block)
51
+ end
52
+
53
+ def configure_project_generator(generator)
54
+ end
55
+
56
+ def fail_with_output(pattern)
57
+ FailWithOutputMatcher.new(pattern)
58
+ end
59
+
60
+ def have_errors_or_failures
61
+ HaveErrorsOrFailuresMatcher.new
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,60 @@
1
+ require File.expand_path('../base', __FILE__)
2
+ require File.expand_path('../../project/rails', __FILE__)
3
+
4
+ module IntegrationTests
5
+ module Rails
6
+ class LeaveDatabaseTableClearMatcher < Struct.new(:project, :table_name)
7
+ def matches?(block)
8
+ @old_number_of_rows = number_of_rows
9
+ block.call
10
+ @new_number_of_rows = number_of_rows
11
+ @old_number_of_rows == 0 && @new_number_of_rows == 0
12
+ end
13
+
14
+ def description
15
+ "leave the database table #{table_name} unchanged"
16
+ end
17
+
18
+ def failure_message_for_should
19
+ "Expected for database table #{table_name} to have been left clear, but it was changed (there are now #{@new_number_of_rows} rows)"
20
+ end
21
+
22
+ def failure_message_for_should_not
23
+ "Expected for database table #{table_name} to not have been left clear, but it was"
24
+ end
25
+
26
+ private
27
+
28
+ def number_of_rows
29
+ result = project.exec!("echo 'select count(*) from #{table_name};' | sqlite3 #{project.database_file_path}")
30
+ result.output.chomp.to_i
31
+ end
32
+ end
33
+
34
+ include Base
35
+
36
+ def configure_project_generator(project_generator)
37
+ super
38
+ configure_rails_project_generator(project_generator)
39
+ end
40
+
41
+ def build_rails_project_generator
42
+ Project::Generator.factory do |project_generator|
43
+ configure_rails_project_generator(project_generator)
44
+ yield project_generator if block_given?
45
+ end
46
+ end
47
+
48
+ def generate_rails_project(&block)
49
+ build_rails_project_generator.call(&block)
50
+ end
51
+
52
+ def configure_rails_project_generator(project_generator)
53
+ project_generator.mixin Project::Rails
54
+ end
55
+
56
+ def leave_database_table_clear(project, table_name)
57
+ LeaveDatabaseTableClearMatcher.new(project, table_name)
58
+ end
59
+ end
60
+ end