mocha 0.5.6 → 3.0.2
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 +7 -0
- data/.gemtest +0 -0
- data/.github/FUNDING.yml +1 -0
- data/.rubocop.yml +92 -0
- data/.rubocop_todo.yml +39 -0
- data/.yardopts +25 -0
- data/CONTRIBUTING.md +7 -0
- data/COPYING.md +3 -0
- data/Gemfile +17 -0
- data/{MIT-LICENSE → MIT-LICENSE.md} +2 -2
- data/README.md +361 -0
- data/RELEASE.md +1235 -0
- data/Rakefile +165 -123
- data/gemfiles/Gemfile.minitest.latest +8 -0
- data/gemfiles/Gemfile.rubocop +9 -0
- data/gemfiles/Gemfile.test-unit.latest +8 -0
- data/lib/mocha/any_instance_method.rb +12 -26
- data/lib/mocha/any_instance_receiver.rb +20 -0
- data/lib/mocha/api.rb +213 -0
- data/lib/mocha/argument_iterator.rb +17 -0
- data/lib/mocha/backtrace_filter.rb +15 -0
- data/lib/mocha/block_matchers.rb +33 -0
- data/lib/mocha/cardinality.rb +110 -0
- data/lib/mocha/central.rb +33 -22
- data/lib/mocha/change_state_side_effect.rb +17 -0
- data/lib/mocha/class_methods.rb +67 -0
- data/lib/mocha/configuration.rb +338 -0
- data/lib/mocha/default_name.rb +15 -0
- data/lib/mocha/default_receiver.rb +13 -0
- data/lib/mocha/deprecation.rb +19 -14
- data/lib/mocha/detection/minitest.rb +25 -0
- data/lib/mocha/detection/test_unit.rb +30 -0
- data/lib/mocha/error_with_filtered_backtrace.rb +15 -0
- data/lib/mocha/exception_raiser.rb +11 -10
- data/lib/mocha/expectation.rb +553 -168
- data/lib/mocha/expectation_error.rb +9 -14
- data/lib/mocha/expectation_error_factory.rb +37 -0
- data/lib/mocha/expectation_list.rb +30 -14
- data/lib/mocha/hooks.rb +55 -0
- data/lib/mocha/ignoring_warning.rb +20 -0
- data/lib/mocha/impersonating_any_instance_name.rb +13 -0
- data/lib/mocha/impersonating_name.rb +13 -0
- data/lib/mocha/in_state_ordering_constraint.rb +17 -0
- data/lib/mocha/inspect.rb +56 -22
- data/lib/mocha/instance_method.rb +17 -4
- data/lib/mocha/integration/assertion_counter.rb +15 -0
- data/lib/mocha/integration/minitest/adapter.rb +71 -0
- data/lib/mocha/integration/minitest.rb +29 -0
- data/lib/mocha/integration/monkey_patcher.rb +26 -0
- data/lib/mocha/integration/test_unit/adapter.rb +61 -0
- data/lib/mocha/integration/test_unit.rb +29 -0
- data/lib/mocha/integration.rb +5 -0
- data/lib/mocha/invocation.rb +76 -0
- data/lib/mocha/logger.rb +13 -0
- data/lib/mocha/macos_version.rb +7 -0
- data/lib/mocha/method_matcher.rb +8 -10
- data/lib/mocha/minitest.rb +7 -0
- data/lib/mocha/mock.rb +333 -108
- data/lib/mocha/mockery.rb +199 -0
- data/lib/mocha/name.rb +13 -0
- data/lib/mocha/not_initialized_error.rb +9 -0
- data/lib/mocha/object_methods.rb +183 -0
- data/lib/mocha/object_receiver.rb +20 -0
- data/lib/mocha/parameter_matchers/all_of.rb +38 -28
- data/lib/mocha/parameter_matchers/any_of.rb +44 -33
- data/lib/mocha/parameter_matchers/any_parameters.rb +33 -26
- data/lib/mocha/parameter_matchers/anything.rb +31 -22
- data/lib/mocha/parameter_matchers/base_methods.rb +64 -0
- data/lib/mocha/parameter_matchers/equals.rb +36 -25
- data/lib/mocha/parameter_matchers/equivalent_uri.rb +65 -0
- data/lib/mocha/parameter_matchers/has_entries.rb +48 -29
- data/lib/mocha/parameter_matchers/has_entry.rb +90 -42
- data/lib/mocha/parameter_matchers/has_key.rb +39 -26
- data/lib/mocha/parameter_matchers/has_keys.rb +59 -0
- data/lib/mocha/parameter_matchers/has_value.rb +39 -26
- data/lib/mocha/parameter_matchers/includes.rb +88 -23
- data/lib/mocha/parameter_matchers/instance_methods.rb +28 -0
- data/lib/mocha/parameter_matchers/instance_of.rb +37 -26
- data/lib/mocha/parameter_matchers/is_a.rb +38 -26
- data/lib/mocha/parameter_matchers/kind_of.rb +39 -26
- data/lib/mocha/parameter_matchers/not.rb +37 -26
- data/lib/mocha/parameter_matchers/optionally.rb +52 -17
- data/lib/mocha/parameter_matchers/positional_or_keyword_hash.rb +91 -0
- data/lib/mocha/parameter_matchers/regexp_matches.rb +37 -25
- data/lib/mocha/parameter_matchers/responds_with.rb +82 -0
- data/lib/mocha/parameter_matchers/yaml_equivalent.rb +55 -0
- data/lib/mocha/parameter_matchers.rb +12 -5
- data/lib/mocha/parameters_matcher.rb +28 -19
- data/lib/mocha/raised_exception.rb +13 -0
- data/lib/mocha/return_values.rb +13 -18
- data/lib/mocha/ruby_version.rb +7 -0
- data/lib/mocha/sequence.rb +23 -17
- data/lib/mocha/single_return_value.rb +8 -18
- data/lib/mocha/state_machine.rb +95 -0
- data/lib/mocha/stubbed_method.rb +96 -0
- data/lib/mocha/stubbing_error.rb +10 -0
- data/lib/mocha/test_unit.rb +7 -0
- data/lib/mocha/thrower.rb +15 -0
- data/lib/mocha/thrown_object.rb +14 -0
- data/lib/mocha/version.rb +5 -0
- data/lib/mocha/yield_parameters.rb +12 -20
- data/lib/mocha.rb +19 -17
- data/mise.toml +2 -0
- data/mocha.gemspec +40 -0
- metadata +130 -145
- data/COPYING +0 -3
- data/README +0 -35
- data/RELEASE +0 -188
- data/examples/misc.rb +0 -44
- data/examples/mocha.rb +0 -26
- data/examples/stubba.rb +0 -65
- data/lib/mocha/auto_verify.rb +0 -118
- data/lib/mocha/class_method.rb +0 -66
- data/lib/mocha/infinite_range.rb +0 -25
- data/lib/mocha/is_a.rb +0 -9
- data/lib/mocha/metaclass.rb +0 -7
- data/lib/mocha/missing_expectation.rb +0 -17
- data/lib/mocha/multiple_yields.rb +0 -20
- data/lib/mocha/no_yields.rb +0 -11
- data/lib/mocha/object.rb +0 -110
- data/lib/mocha/parameter_matchers/base.rb +0 -15
- data/lib/mocha/parameter_matchers/object.rb +0 -9
- data/lib/mocha/pretty_parameters.rb +0 -28
- data/lib/mocha/setup_and_teardown.rb +0 -23
- data/lib/mocha/single_yield.rb +0 -18
- data/lib/mocha/standalone.rb +0 -32
- data/lib/mocha/stub.rb +0 -18
- data/lib/mocha/test_case_adapter.rb +0 -49
- data/lib/mocha_standalone.rb +0 -2
- data/lib/stubba.rb +0 -2
- data/test/acceptance/expected_invocation_count_acceptance_test.rb +0 -187
- data/test/acceptance/mocha_acceptance_test.rb +0 -98
- data/test/acceptance/mock_with_initializer_block_acceptance_test.rb +0 -44
- data/test/acceptance/mocked_methods_dispatch_acceptance_test.rb +0 -71
- data/test/acceptance/optional_parameters_acceptance_test.rb +0 -63
- data/test/acceptance/parameter_matcher_acceptance_test.rb +0 -117
- data/test/acceptance/partial_mocks_acceptance_test.rb +0 -40
- data/test/acceptance/sequence_acceptance_test.rb +0 -179
- data/test/acceptance/standalone_acceptance_test.rb +0 -131
- data/test/acceptance/stubba_acceptance_test.rb +0 -102
- data/test/active_record_test_case.rb +0 -36
- data/test/deprecation_disabler.rb +0 -15
- data/test/execution_point.rb +0 -34
- data/test/integration/mocha_test_result_integration_test.rb +0 -105
- data/test/integration/stubba_integration_test.rb +0 -89
- data/test/integration/stubba_test_result_integration_test.rb +0 -85
- data/test/method_definer.rb +0 -18
- data/test/test_helper.rb +0 -12
- data/test/test_runner.rb +0 -31
- data/test/unit/any_instance_method_test.rb +0 -126
- data/test/unit/array_inspect_test.rb +0 -16
- data/test/unit/auto_verify_test.rb +0 -129
- data/test/unit/central_test.rb +0 -124
- data/test/unit/class_method_test.rb +0 -200
- data/test/unit/date_time_inspect_test.rb +0 -21
- data/test/unit/expectation_error_test.rb +0 -24
- data/test/unit/expectation_list_test.rb +0 -75
- data/test/unit/expectation_raiser_test.rb +0 -28
- data/test/unit/expectation_test.rb +0 -483
- data/test/unit/hash_inspect_test.rb +0 -16
- data/test/unit/infinite_range_test.rb +0 -53
- data/test/unit/metaclass_test.rb +0 -22
- data/test/unit/method_matcher_test.rb +0 -23
- data/test/unit/missing_expectation_test.rb +0 -42
- data/test/unit/mock_test.rb +0 -323
- data/test/unit/multiple_yields_test.rb +0 -18
- data/test/unit/no_yield_test.rb +0 -18
- data/test/unit/object_inspect_test.rb +0 -37
- data/test/unit/object_test.rb +0 -165
- data/test/unit/parameter_matchers/all_of_test.rb +0 -26
- data/test/unit/parameter_matchers/any_of_test.rb +0 -26
- data/test/unit/parameter_matchers/anything_test.rb +0 -21
- data/test/unit/parameter_matchers/has_entries_test.rb +0 -30
- data/test/unit/parameter_matchers/has_entry_test.rb +0 -40
- data/test/unit/parameter_matchers/has_key_test.rb +0 -25
- data/test/unit/parameter_matchers/has_value_test.rb +0 -25
- data/test/unit/parameter_matchers/includes_test.rb +0 -25
- data/test/unit/parameter_matchers/instance_of_test.rb +0 -25
- data/test/unit/parameter_matchers/is_a_test.rb +0 -25
- data/test/unit/parameter_matchers/kind_of_test.rb +0 -25
- data/test/unit/parameter_matchers/not_test.rb +0 -26
- data/test/unit/parameter_matchers/regexp_matches_test.rb +0 -25
- data/test/unit/parameter_matchers/stub_matcher.rb +0 -23
- data/test/unit/parameters_matcher_test.rb +0 -121
- data/test/unit/return_values_test.rb +0 -63
- data/test/unit/sequence_test.rb +0 -104
- data/test/unit/setup_and_teardown_test.rb +0 -76
- data/test/unit/single_return_value_test.rb +0 -33
- data/test/unit/single_yield_test.rb +0 -18
- data/test/unit/string_inspect_test.rb +0 -11
- data/test/unit/stub_test.rb +0 -24
- data/test/unit/yield_parameters_test.rb +0 -93
data/Rakefile
CHANGED
|
@@ -1,149 +1,191 @@
|
|
|
1
|
-
require '
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
require 'rake/testtask'
|
|
5
|
-
require 'rake/contrib/sshpublisher'
|
|
6
|
-
|
|
7
|
-
module Mocha
|
|
8
|
-
VERSION = "0.5.6"
|
|
1
|
+
require 'bundler'
|
|
2
|
+
namespace 'rubygems' do
|
|
3
|
+
Bundler::GemHelper.install_tasks
|
|
9
4
|
end
|
|
5
|
+
require 'bundler/setup'
|
|
10
6
|
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
require 'rake/testtask'
|
|
8
|
+
begin
|
|
9
|
+
# Only available with `gemfiles/Gemfile.rubocop`
|
|
10
|
+
require 'rubocop/rake_task'
|
|
11
|
+
rescue LoadError
|
|
12
|
+
warn "Unable to load 'rubocop/rake_task', but continuing anyway" if $DEBUG
|
|
13
|
+
end
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
desc 'Run all linters and tests'
|
|
16
|
+
task 'default' => ['lint', 'test', 'test:performance']
|
|
15
17
|
|
|
16
|
-
desc
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
desc 'Run tests'
|
|
19
|
+
task 'test' do
|
|
20
|
+
if (test_library = ENV['MOCHA_RUN_INTEGRATION_TESTS'])
|
|
21
|
+
Rake::Task["test:integration:#{test_library}"].invoke
|
|
22
|
+
else
|
|
23
|
+
Rake::Task['test:units'].invoke
|
|
24
|
+
Rake::Task['test:acceptance'].invoke
|
|
25
|
+
end
|
|
22
26
|
end
|
|
23
27
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
namespace 'test' do
|
|
29
|
+
desc 'Run unit tests'
|
|
30
|
+
Rake::TestTask.new('units') do |t|
|
|
31
|
+
t.libs << 'test'
|
|
32
|
+
t.test_files = FileList['test/unit/**/*_test.rb']
|
|
33
|
+
t.verbose = true
|
|
34
|
+
t.warning = true
|
|
35
|
+
end
|
|
31
36
|
|
|
32
|
-
desc
|
|
33
|
-
Rake::TestTask.new(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
end
|
|
37
|
+
desc 'Run acceptance tests'
|
|
38
|
+
Rake::TestTask.new('acceptance') do |t|
|
|
39
|
+
t.libs << 'test'
|
|
40
|
+
t.test_files = FileList['test/acceptance/*_test.rb']
|
|
41
|
+
t.verbose = true
|
|
42
|
+
t.warning = true
|
|
43
|
+
end
|
|
39
44
|
|
|
40
|
-
desc '
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
task.rdoc_dir = 'doc'
|
|
45
|
-
task.template = File.expand_path(File.join(File.dirname(__FILE__), "templates", "html_with_google_analytics"))
|
|
46
|
-
task.rdoc_files.include('README', 'RELEASE', 'COPYING', 'MIT-LICENSE', 'agiledox.txt', 'lib/mocha/auto_verify.rb', 'lib/mocha/mock.rb', 'lib/mocha/expectation.rb', 'lib/mocha/object.rb', 'lib/mocha/parameter_matchers.rb', 'lib/mocha/parameter_matchers')
|
|
47
|
-
end
|
|
48
|
-
task :rdoc => :examples
|
|
45
|
+
desc 'Run each test in isolation'
|
|
46
|
+
task 'isolated' do
|
|
47
|
+
test_files = FileList['test/unit/**/*_test.rb', 'test/acceptance/*_test.rb']
|
|
48
|
+
failed_tests = []
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
end
|
|
50
|
+
test_files.each do |test_file|
|
|
51
|
+
puts "\n=== Running #{test_file} in isolation ==="
|
|
52
|
+
system("ruby -Itest -w #{test_file}") || (failed_tests << test_file)
|
|
53
|
+
end
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
output << m[1]+" should:\n"
|
|
62
|
-
test_definitions = File::readlines(file).select {|line| line =~ /.*def test.*/}
|
|
63
|
-
test_definitions.sort.each do |definition|
|
|
64
|
-
m = %r"test_(should_)?(.*)".match(definition)
|
|
65
|
-
output << " - "+m[2].gsub(/_/," ") << "\n"
|
|
66
|
-
end
|
|
55
|
+
if failed_tests.any?
|
|
56
|
+
puts "\n❌ #{failed_tests.size} test file(s) failed:"
|
|
57
|
+
failed_tests.each { |f| puts " - #{f}" }
|
|
58
|
+
exit 1
|
|
59
|
+
else
|
|
60
|
+
puts "\n✅ All #{test_files.size} test files passed in isolation!"
|
|
67
61
|
end
|
|
68
62
|
end
|
|
69
|
-
end
|
|
70
63
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
64
|
+
namespace 'integration' do
|
|
65
|
+
desc 'Run Minitest integration tests (intended to be run in its own process)'
|
|
66
|
+
Rake::TestTask.new('minitest') do |t|
|
|
67
|
+
t.libs << 'test'
|
|
68
|
+
t.test_files = FileList['test/integration/minitest_test.rb']
|
|
69
|
+
t.verbose = true
|
|
70
|
+
t.warning = true
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
desc 'Run Test::Unit integration tests (intended to be run in its own process)'
|
|
74
|
+
Rake::TestTask.new('test-unit') do |t|
|
|
75
|
+
t.libs << 'test'
|
|
76
|
+
t.test_files = FileList['test/integration/test_unit_test.rb']
|
|
77
|
+
t.verbose = true
|
|
78
|
+
t.warning = true
|
|
79
|
+
end
|
|
78
80
|
end
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
81
|
+
|
|
82
|
+
# require 'rcov/rcovtask'
|
|
83
|
+
# Rcov::RcovTask.new('coverage') do |t|
|
|
84
|
+
# t.libs << 'test'
|
|
85
|
+
# t.test_files = unit_tests + acceptance_tests
|
|
86
|
+
# t.verbose = true
|
|
87
|
+
# t.warning = true
|
|
88
|
+
# t.rcov_opts << '--sort coverage'
|
|
89
|
+
# t.rcov_opts << '--xref'
|
|
90
|
+
# end
|
|
91
|
+
|
|
92
|
+
desc 'Run performance tests'
|
|
93
|
+
task 'performance' do
|
|
94
|
+
require File.join(File.dirname(__FILE__), 'test', 'acceptance', 'stubba_example_test')
|
|
95
|
+
require File.join(File.dirname(__FILE__), 'test', 'acceptance', 'mocha_example_test')
|
|
96
|
+
iterations = 1000
|
|
97
|
+
puts "\nBenchmarking with #{iterations} iterations..."
|
|
98
|
+
[MochaExampleTest, StubbaExampleTest].each do |test_case|
|
|
99
|
+
puts "#{test_case}: #{benchmark_test_case(test_case, iterations)} seconds."
|
|
89
100
|
end
|
|
90
101
|
end
|
|
91
102
|
end
|
|
92
103
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
s.description = <<-EOF
|
|
102
|
-
Mocking and stubbing library with JMock/SchMock syntax, which allows mocking and stubbing of methods on real (non-mock) classes.
|
|
103
|
-
EOF
|
|
104
|
-
s.email = 'mocha-developer@rubyforge.org'
|
|
105
|
-
s.homepage = 'http://mocha.rubyforge.org'
|
|
106
|
-
s.rubyforge_project = 'mocha'
|
|
107
|
-
|
|
108
|
-
s.has_rdoc = true
|
|
109
|
-
s.extra_rdoc_files = ['README', 'COPYING']
|
|
110
|
-
s.rdoc_options << '--title' << 'Mocha' << '--main' << 'README' << '--line-numbers'
|
|
111
|
-
|
|
112
|
-
s.autorequire = 'mocha'
|
|
113
|
-
s.add_dependency('rake')
|
|
114
|
-
s.files = FileList['{lib,test,examples}/**/*.rb', '[A-Z]*'].exclude('TODO').to_a
|
|
104
|
+
desc 'Run linters'
|
|
105
|
+
task 'lint' do
|
|
106
|
+
if defined?(RuboCop::RakeTask)
|
|
107
|
+
RuboCop::RakeTask.new
|
|
108
|
+
Rake::Task['rubocop'].invoke
|
|
109
|
+
else
|
|
110
|
+
puts 'RuboCop not available - skipping linting'
|
|
111
|
+
end
|
|
115
112
|
end
|
|
116
113
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
114
|
+
def benchmark_test_case(klass, iterations) # rubocop:disable Metrics/AbcSize
|
|
115
|
+
require 'benchmark'
|
|
116
|
+
require 'mocha/detection/minitest'
|
|
117
|
+
|
|
118
|
+
if defined?(Minitest)
|
|
119
|
+
minitest_version = Gem::Version.new(Mocha::Detection::Minitest.version)
|
|
120
|
+
if Gem::Requirement.new('>= 5.0.0').satisfied_by?(minitest_version)
|
|
121
|
+
run_method = Gem::Requirement.new('>= 6.0.0').satisfied_by?(minitest_version) ? :run_suite : :run
|
|
122
|
+
Minitest.seed = 1
|
|
123
|
+
result = Benchmark.realtime { iterations.times { |_i| klass.public_send(run_method, Minitest::CompositeReporter.new) } }
|
|
124
|
+
Minitest::Runnable.runnables.delete(klass)
|
|
125
|
+
result
|
|
126
|
+
else
|
|
127
|
+
Minitest::Unit.output = StringIO.new
|
|
128
|
+
Benchmark.realtime { iterations.times { |_i| Minitest::Unit.new.run([klass]) } }
|
|
129
|
+
end
|
|
130
|
+
else
|
|
131
|
+
load 'test/unit/ui/console/testrunner.rb' unless defined?(Test::Unit::UI::Console::TestRunner)
|
|
132
|
+
unless @silent_option
|
|
133
|
+
begin
|
|
134
|
+
load 'test/unit/ui/console/outputlevel.rb' unless defined?(Test::Unit::UI::Console::OutputLevel::SILENT)
|
|
135
|
+
@silent_option = { output_level: Test::Unit::UI::Console::OutputLevel::SILENT }
|
|
136
|
+
rescue LoadError
|
|
137
|
+
@silent_option = Test::Unit::UI::SILENT
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
Benchmark.realtime { iterations.times { Test::Unit::UI::Console::TestRunner.run(klass, @silent_option) } }
|
|
141
|
+
end
|
|
120
142
|
end
|
|
143
|
+
if ENV['MOCHA_GENERATE_DOCS']
|
|
144
|
+
require 'yard'
|
|
121
145
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
146
|
+
namespace :docs do
|
|
147
|
+
desc 'Remove generated documentation'
|
|
148
|
+
task :clobber do
|
|
149
|
+
`rm -rf ./docs`
|
|
150
|
+
end
|
|
125
151
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
152
|
+
desc 'Generate documentation'
|
|
153
|
+
YARD::Rake::YardocTask.new(:generate) do |task|
|
|
154
|
+
task.options = ['--title', "Mocha #{Mocha::VERSION}", '--fail-on-warning']
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
desc 'Ensure custom domain remains in place for docs on GitHub Pages'
|
|
158
|
+
task :ensure_cname do
|
|
159
|
+
`git checkout docs/CNAME`
|
|
160
|
+
end
|
|
129
161
|
|
|
130
|
-
desc
|
|
131
|
-
task :
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
162
|
+
desc 'Ensure custom JavaScript files remain in place for docs on GitHub Pages'
|
|
163
|
+
task :ensure_js do
|
|
164
|
+
`git checkout docs/js/app.js`
|
|
165
|
+
`git checkout docs/js/jquery.js`
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
desc 'Check documentation coverage'
|
|
169
|
+
task :coverage do
|
|
170
|
+
stats_output = `yard stats --list-undoc`
|
|
171
|
+
puts stats_output
|
|
172
|
+
|
|
173
|
+
match = stats_output.match(/(?<coverage_percentage>\d+\.\d+)% documented/);
|
|
174
|
+
abort 'Error: Could not determine documentation coverage.' unless match
|
|
175
|
+
|
|
176
|
+
coverage_percentage = match[:coverage_percentage].to_f
|
|
177
|
+
minimum_percentage = 100.0
|
|
178
|
+
|
|
179
|
+
if coverage_percentage < minimum_percentage
|
|
180
|
+
abort "Documentation coverage is #{coverage_percentage}%, which is below the required #{minimum_percentage}%."
|
|
181
|
+
else
|
|
182
|
+
puts "Documentation coverage is #{coverage_percentage}%, which is at or above the required #{minimum_percentage}%."
|
|
183
|
+
end
|
|
184
|
+
end
|
|
148
185
|
end
|
|
186
|
+
|
|
187
|
+
desc 'Prepare documentation for publication on GitHub Pages'
|
|
188
|
+
task 'docs' => %w[docs:clobber docs:generate docs:ensure_cname docs:ensure_js]
|
|
149
189
|
end
|
|
190
|
+
|
|
191
|
+
task 'release' => ['default', 'rubygems:release']
|
|
@@ -1,35 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
require 'mocha/stubbed_method'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
remove_new_method
|
|
9
|
-
restore_original_method
|
|
10
|
-
stubbee.any_instance.reset_mocha
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def mock
|
|
14
|
-
stubbee.any_instance.mocha
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def hide_original_method
|
|
18
|
-
stubbee.class_eval "alias_method :#{hidden_method}, :#{method}" if stubbee.method_defined?(method)
|
|
19
|
-
end
|
|
5
|
+
module Mocha
|
|
6
|
+
class AnyInstanceMethod < StubbedMethod
|
|
7
|
+
private
|
|
20
8
|
|
|
21
|
-
def
|
|
22
|
-
|
|
9
|
+
def stubbee
|
|
10
|
+
stubba_object.any_instance
|
|
23
11
|
end
|
|
24
12
|
|
|
25
|
-
def
|
|
26
|
-
|
|
13
|
+
def stubbee_method(method_name)
|
|
14
|
+
stubba_object.instance_method(method_name)
|
|
27
15
|
end
|
|
28
16
|
|
|
29
|
-
def
|
|
30
|
-
|
|
17
|
+
def original_method_owner
|
|
18
|
+
stubba_object
|
|
31
19
|
end
|
|
32
|
-
|
|
33
20
|
end
|
|
34
|
-
|
|
35
|
-
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mocha
|
|
4
|
+
class AnyInstanceReceiver
|
|
5
|
+
def initialize(klass)
|
|
6
|
+
@klass = klass
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def mocks
|
|
10
|
+
klass = @klass
|
|
11
|
+
mocks = []
|
|
12
|
+
while klass
|
|
13
|
+
mocha = klass.any_instance.mocha(instantiate: false)
|
|
14
|
+
mocks << mocha if mocha
|
|
15
|
+
klass = klass.superclass
|
|
16
|
+
end
|
|
17
|
+
mocks
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
data/lib/mocha/api.rb
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'mocha/ruby_version'
|
|
4
|
+
require 'mocha/parameter_matchers'
|
|
5
|
+
require 'mocha/hooks'
|
|
6
|
+
require 'mocha/mockery'
|
|
7
|
+
require 'mocha/sequence'
|
|
8
|
+
require 'mocha/object_methods'
|
|
9
|
+
require 'mocha/class_methods'
|
|
10
|
+
|
|
11
|
+
module Mocha
|
|
12
|
+
# Methods added to +Test::Unit::TestCase+, +Minitest::Unit::TestCase+ or equivalent.
|
|
13
|
+
# The mock creation methods are {#mock}, {#stub} and {#stub_everything}, all of which return a #{Mock}
|
|
14
|
+
# which can be further modified by {Mock#responds_like} and {Mock#responds_like_instance_of} methods,
|
|
15
|
+
# both of which return a {Mock}, too, and can therefore, be chained to the original creation methods.
|
|
16
|
+
#
|
|
17
|
+
# {Mock#responds_like} and {Mock#responds_like_instance_of} force the mock to indicate what it is
|
|
18
|
+
# supposed to be mocking, thus making it a safer verifying mock. They check that the underlying +responder+
|
|
19
|
+
# will actually respond to the methods being stubbed, throwing a +NoMethodError+ upon invocation otherwise.
|
|
20
|
+
#
|
|
21
|
+
# @example Verifying mock using {Mock#responds_like_instance_of}
|
|
22
|
+
# class Sheep
|
|
23
|
+
# def initialize
|
|
24
|
+
# raise "some awkward code we don't want to call"
|
|
25
|
+
# end
|
|
26
|
+
# def chew(grass); end
|
|
27
|
+
# end
|
|
28
|
+
#
|
|
29
|
+
# sheep = mock('sheep').responds_like_instance_of(Sheep)
|
|
30
|
+
# sheep.expects(:chew)
|
|
31
|
+
# sheep.expects(:foo)
|
|
32
|
+
# sheep.respond_to?(:chew) # => true
|
|
33
|
+
# sheep.respond_to?(:foo) # => false
|
|
34
|
+
# sheep.chew
|
|
35
|
+
# sheep.foo # => raises NoMethodError exception
|
|
36
|
+
module API
|
|
37
|
+
include ParameterMatchers::Methods
|
|
38
|
+
include Hooks
|
|
39
|
+
|
|
40
|
+
# @private
|
|
41
|
+
def self.included(_mod)
|
|
42
|
+
Object.include Mocha::ObjectMethods
|
|
43
|
+
Class.include Mocha::ClassMethods
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @private
|
|
47
|
+
def self.extended(mod)
|
|
48
|
+
included(mod)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Builds a new mock object
|
|
52
|
+
#
|
|
53
|
+
# @return [Mock] a new mock object
|
|
54
|
+
#
|
|
55
|
+
# @overload def mock(name)
|
|
56
|
+
# @param [String, Symbol] name identifies mock object in error messages.
|
|
57
|
+
# @overload def mock(expected_methods_vs_return_values = {})
|
|
58
|
+
# @param [Hash] expected_methods_vs_return_values expected method name symbols as keys and corresponding return values as values - these expectations are setup as if {Mock#expects} were called multiple times.
|
|
59
|
+
# @overload def mock(name, expected_methods_vs_return_values = {})
|
|
60
|
+
# @param [String, Symbol] name identifies mock object in error messages.
|
|
61
|
+
# @param [Hash] expected_methods_vs_return_values expected method name symbols as keys and corresponding return values as values - these expectations are setup as if {Mock#expects} were called multiple times.
|
|
62
|
+
#
|
|
63
|
+
# @example Using expected_methods_vs_return_values Hash to setup expectations.
|
|
64
|
+
# def test_motor_starts_and_stops
|
|
65
|
+
# motor = mock('motor', start: true, stop: true)
|
|
66
|
+
# assert motor.start
|
|
67
|
+
# assert motor.stop
|
|
68
|
+
# # an error will be raised unless both Motor#start and Motor#stop have been called
|
|
69
|
+
# end
|
|
70
|
+
#
|
|
71
|
+
def mock(*arguments)
|
|
72
|
+
name = arguments.shift.to_s if arguments.first.is_a?(String) || arguments.first.is_a?(Symbol)
|
|
73
|
+
expectations = arguments.shift || {}
|
|
74
|
+
mock = name ? Mockery.instance.named_mock(name) : Mockery.instance.unnamed_mock
|
|
75
|
+
mock.expects(expectations)
|
|
76
|
+
mock
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Builds a new mock object
|
|
80
|
+
#
|
|
81
|
+
# @return [Mock] a new mock object
|
|
82
|
+
#
|
|
83
|
+
# @overload def stub(name)
|
|
84
|
+
# @param [String, Symbol] name identifies mock object in error messages.
|
|
85
|
+
# @overload def stub(stubbed_methods_vs_return_values = {})
|
|
86
|
+
# @param [Hash] stubbed_methods_vs_return_values stubbed method name symbols as keys and corresponding return values as values - these stubbed methods are setup as if {Mock#stubs} were called multiple times.
|
|
87
|
+
# @overload def stub(name, stubbed_methods_vs_return_values = {})
|
|
88
|
+
# @param [String, Symbol] name identifies mock object in error messages.
|
|
89
|
+
# @param [Hash] stubbed_methods_vs_return_values stubbed method name symbols as keys and corresponding return values as values - these stubbed methods are setup as if {Mock#stubs} were called multiple times.
|
|
90
|
+
#
|
|
91
|
+
# @example Using stubbed_methods_vs_return_values Hash to setup stubbed methods.
|
|
92
|
+
# def test_motor_starts_and_stops
|
|
93
|
+
# motor = stub('motor', start: true, stop: true)
|
|
94
|
+
# assert motor.start
|
|
95
|
+
# assert motor.stop
|
|
96
|
+
# # an error will not be raised even if either Motor#start or Motor#stop has not been called
|
|
97
|
+
# end
|
|
98
|
+
def stub(*arguments)
|
|
99
|
+
name = arguments.shift.to_s if arguments.first.is_a?(String) || arguments.first.is_a?(Symbol)
|
|
100
|
+
expectations = arguments.shift || {}
|
|
101
|
+
stub = name ? Mockery.instance.named_mock(name) : Mockery.instance.unnamed_mock
|
|
102
|
+
stub.stubs(expectations)
|
|
103
|
+
stub
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Builds a mock object that accepts calls to any method. By default it will return +nil+ for any method call.
|
|
107
|
+
#
|
|
108
|
+
# @return [Mock] a new mock object
|
|
109
|
+
#
|
|
110
|
+
# @overload def stub_everything(name)
|
|
111
|
+
# @param [String, Symbol] name identifies mock object in error messages.
|
|
112
|
+
# @overload def stub_everything(stubbed_methods_vs_return_values = {})
|
|
113
|
+
# @param [Hash] stubbed_methods_vs_return_values stubbed method name symbols as keys and corresponding return values as values - these stubbed methods are setup as if {Mock#stubs} were called multiple times.
|
|
114
|
+
# @overload def stub_everything(name, stubbed_methods_vs_return_values = {})
|
|
115
|
+
# @param [String, Symbol] name identifies mock object in error messages.
|
|
116
|
+
# @param [Hash] stubbed_methods_vs_return_values stubbed method name symbols as keys and corresponding return values as values - these stubbed methods are setup as if {Mock#stubs} were called multiple times.
|
|
117
|
+
#
|
|
118
|
+
# @example Ignore invocations of irrelevant methods.
|
|
119
|
+
# def test_motor_stops
|
|
120
|
+
# motor = stub_everything('motor', stop: true)
|
|
121
|
+
# assert_nil motor.irrelevant_method_1 # => no error raised
|
|
122
|
+
# assert_nil motor.irrelevant_method_2 # => no error raised
|
|
123
|
+
# assert motor.stop
|
|
124
|
+
# end
|
|
125
|
+
def stub_everything(*arguments)
|
|
126
|
+
name = arguments.shift if arguments.first.is_a?(String) || arguments.first.is_a?(Symbol)
|
|
127
|
+
expectations = arguments.shift || {}
|
|
128
|
+
stub = name ? Mockery.instance.named_mock(name) : Mockery.instance.unnamed_mock
|
|
129
|
+
stub.stub_everything
|
|
130
|
+
stub.stubs(expectations)
|
|
131
|
+
stub
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Builds a new sequence which can be used to constrain the order in which expectations can occur.
|
|
135
|
+
#
|
|
136
|
+
# Specify that an expected invocation must occur within a named {Sequence} by calling {Expectation#in_sequence}
|
|
137
|
+
# on each expectation or by passing a block within which all expectations should be constrained by the {Sequence}.
|
|
138
|
+
#
|
|
139
|
+
# @param [String] name name of sequence
|
|
140
|
+
# @yield optional block within which expectations should be constrained by the sequence
|
|
141
|
+
# @return [Sequence] a new sequence
|
|
142
|
+
#
|
|
143
|
+
# @see Expectation#in_sequence
|
|
144
|
+
#
|
|
145
|
+
# @example Ensure methods on egg are invoked in correct order.
|
|
146
|
+
# breakfast = sequence('breakfast')
|
|
147
|
+
#
|
|
148
|
+
# egg = mock('egg')
|
|
149
|
+
# egg.expects(:crack).in_sequence(breakfast)
|
|
150
|
+
# egg.expects(:fry).in_sequence(breakfast)
|
|
151
|
+
# egg.expects(:eat).in_sequence(breakfast)
|
|
152
|
+
#
|
|
153
|
+
# @example Ensure methods across multiple objects are invoked in correct order.
|
|
154
|
+
# sequence = sequence(:task_order)
|
|
155
|
+
#
|
|
156
|
+
# task_one = mock("task_one")
|
|
157
|
+
# task_two = mock("task_two")
|
|
158
|
+
#
|
|
159
|
+
# task_one.expects(:execute).in_sequence(sequence)
|
|
160
|
+
# task_two.expects(:execute).in_sequence(sequence)
|
|
161
|
+
#
|
|
162
|
+
# task_one.execute
|
|
163
|
+
# task_two.execute
|
|
164
|
+
#
|
|
165
|
+
# @example Ensure methods on egg are invoked in the correct order using a block.
|
|
166
|
+
# egg = mock('egg')
|
|
167
|
+
# sequence('breakfast') do
|
|
168
|
+
# egg.expects(:crack)
|
|
169
|
+
# egg.expects(:fry)
|
|
170
|
+
# egg.expects(:eat)
|
|
171
|
+
# end
|
|
172
|
+
def sequence(name)
|
|
173
|
+
Sequence.new(name).tap do |seq|
|
|
174
|
+
Mockery.instance.sequences.push(seq)
|
|
175
|
+
begin
|
|
176
|
+
yield if block_given?
|
|
177
|
+
ensure
|
|
178
|
+
Mockery.instance.sequences.pop
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Builds a new state machine which can be used to constrain the order in which expectations can occur.
|
|
184
|
+
#
|
|
185
|
+
# Specify the initial state of the state machine by using {StateMachine#starts_as}.
|
|
186
|
+
#
|
|
187
|
+
# Specify that an expected invocation should change the state of the state machine by using {Expectation#then}.
|
|
188
|
+
#
|
|
189
|
+
# Specify that an expected invocation should be constrained to occur within a particular +state+ by using {Expectation#when}.
|
|
190
|
+
#
|
|
191
|
+
# A test can contain multiple state machines.
|
|
192
|
+
#
|
|
193
|
+
# @param [String] name name of state machine
|
|
194
|
+
# @return [StateMachine] a new state machine
|
|
195
|
+
#
|
|
196
|
+
# @see Expectation#then
|
|
197
|
+
# @see Expectation#when
|
|
198
|
+
# @see StateMachine
|
|
199
|
+
# @example Constrain expected invocations to occur in particular states.
|
|
200
|
+
# power = states('power').starts_as('off')
|
|
201
|
+
#
|
|
202
|
+
# radio = mock('radio')
|
|
203
|
+
# radio.expects(:switch_on).then(power.is('on'))
|
|
204
|
+
# radio.expects(:select_channel).with('BBC Radio 4').when(power.is('on'))
|
|
205
|
+
# radio.expects(:adjust_volume).with(+5).when(power.is('on'))
|
|
206
|
+
# radio.expects(:select_channel).with('BBC World Service').when(power.is('on'))
|
|
207
|
+
# radio.expects(:adjust_volume).with(-5).when(power.is('on'))
|
|
208
|
+
# radio.expects(:switch_off).then(power.is('off'))
|
|
209
|
+
def states(name)
|
|
210
|
+
Mockery.instance.new_state_machine(name)
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mocha
|
|
4
|
+
class ArgumentIterator
|
|
5
|
+
def initialize(argument)
|
|
6
|
+
@argument = argument
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def each(&block)
|
|
10
|
+
if @argument.is_a?(Hash)
|
|
11
|
+
@argument.each(&block)
|
|
12
|
+
else
|
|
13
|
+
block.call(@argument)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mocha
|
|
4
|
+
class BacktraceFilter
|
|
5
|
+
LIB_DIRECTORY = File.expand_path(File.join(File.dirname(__FILE__), '..')) + File::SEPARATOR
|
|
6
|
+
|
|
7
|
+
def initialize(lib_directory = LIB_DIRECTORY)
|
|
8
|
+
@lib_directory = lib_directory
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def filtered(backtrace)
|
|
12
|
+
backtrace.reject { |location| File.expand_path(location).start_with?(@lib_directory) }
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|