rspec-mocks 3.0.0.beta1 → 3.0.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. data.tar.gz.sig +1 -1
  2. data/Changelog.md +95 -3
  3. data/README.md +27 -13
  4. data/features/README.md +15 -7
  5. data/features/argument_matchers/README.md +5 -5
  6. data/features/argument_matchers/explicit.feature +6 -6
  7. data/features/argument_matchers/general_matchers.feature +4 -4
  8. data/features/argument_matchers/type_matchers.feature +2 -2
  9. data/features/message_expectations/README.md +29 -27
  10. data/features/message_expectations/call_original.feature +0 -1
  11. data/features/message_expectations/message_chains_using_expect.feature +49 -0
  12. data/features/method_stubs/README.md +2 -1
  13. data/features/method_stubs/{any_instance.feature → allow_any_instance_of.feature} +12 -12
  14. data/features/method_stubs/{stub_chain.feature → receive_message_chain.feature} +3 -3
  15. data/features/method_stubs/to_ary.feature +1 -1
  16. data/features/mutating_constants/stub_defined_constant.feature +0 -1
  17. data/features/outside_rspec/standalone.feature +1 -1
  18. data/features/spies/spy_pure_mock_method.feature +1 -1
  19. data/features/test_frameworks/test_unit.feature +21 -10
  20. data/features/verifying_doubles/README.md +17 -0
  21. data/features/verifying_doubles/class_doubles.feature +1 -16
  22. data/features/verifying_doubles/dynamic_classes.feature +0 -1
  23. data/features/verifying_doubles/{introduction.feature → instance_doubles.feature} +41 -23
  24. data/features/verifying_doubles/partial_doubles.feature +2 -2
  25. data/lib/rspec/mocks.rb +69 -82
  26. data/lib/rspec/mocks/any_instance/expect_chain_chain.rb +35 -0
  27. data/lib/rspec/mocks/any_instance/expectation_chain.rb +1 -2
  28. data/lib/rspec/mocks/any_instance/recorder.rb +52 -18
  29. data/lib/rspec/mocks/any_instance/stub_chain.rb +1 -1
  30. data/lib/rspec/mocks/any_instance/stub_chain_chain.rb +4 -0
  31. data/lib/rspec/mocks/argument_list_matcher.rb +10 -44
  32. data/lib/rspec/mocks/argument_matchers.rb +132 -163
  33. data/lib/rspec/mocks/configuration.rb +28 -4
  34. data/lib/rspec/mocks/error_generator.rb +46 -13
  35. data/lib/rspec/mocks/example_methods.rb +13 -12
  36. data/lib/rspec/mocks/extensions/marshal.rb +1 -1
  37. data/lib/rspec/mocks/framework.rb +3 -4
  38. data/lib/rspec/mocks/instance_method_stasher.rb +2 -3
  39. data/lib/rspec/mocks/matchers/have_received.rb +8 -6
  40. data/lib/rspec/mocks/matchers/receive.rb +28 -20
  41. data/lib/rspec/mocks/matchers/receive_message_chain.rb +65 -0
  42. data/lib/rspec/mocks/matchers/receive_messages.rb +3 -2
  43. data/lib/rspec/mocks/message_chain.rb +91 -0
  44. data/lib/rspec/mocks/message_expectation.rb +86 -80
  45. data/lib/rspec/mocks/method_double.rb +2 -11
  46. data/lib/rspec/mocks/method_reference.rb +82 -23
  47. data/lib/rspec/mocks/method_signature_verifier.rb +207 -0
  48. data/lib/rspec/mocks/mutate_const.rb +34 -50
  49. data/lib/rspec/mocks/object_reference.rb +0 -1
  50. data/lib/rspec/mocks/proxy.rb +70 -13
  51. data/lib/rspec/mocks/ruby_features.rb +24 -0
  52. data/lib/rspec/mocks/space.rb +105 -31
  53. data/lib/rspec/mocks/standalone.rb +2 -2
  54. data/lib/rspec/mocks/syntax.rb +43 -8
  55. data/lib/rspec/mocks/targets.rb +16 -7
  56. data/lib/rspec/mocks/test_double.rb +41 -15
  57. data/lib/rspec/mocks/verifying_double.rb +51 -4
  58. data/lib/rspec/mocks/verifying_message_expecation.rb +12 -12
  59. data/lib/rspec/mocks/verifying_proxy.rb +32 -19
  60. data/lib/rspec/mocks/version.rb +1 -1
  61. data/spec/rspec/mocks/and_call_original_spec.rb +28 -7
  62. data/spec/rspec/mocks/and_return_spec.rb +23 -0
  63. data/spec/rspec/mocks/and_yield_spec.rb +1 -2
  64. data/spec/rspec/mocks/any_instance_spec.rb +33 -17
  65. data/spec/rspec/mocks/array_including_matcher_spec.rb +6 -6
  66. data/spec/rspec/mocks/before_all_spec.rb +132 -0
  67. data/spec/rspec/mocks/block_return_value_spec.rb +12 -1
  68. data/spec/rspec/mocks/combining_implementation_instructions_spec.rb +9 -11
  69. data/spec/rspec/mocks/configuration_spec.rb +14 -1
  70. data/spec/rspec/mocks/double_spec.rb +867 -24
  71. data/spec/rspec/mocks/example_methods_spec.rb +13 -0
  72. data/spec/rspec/mocks/extensions/marshal_spec.rb +17 -17
  73. data/spec/rspec/mocks/failing_argument_matchers_spec.rb +29 -1
  74. data/spec/rspec/mocks/hash_excluding_matcher_spec.rb +12 -12
  75. data/spec/rspec/mocks/hash_including_matcher_spec.rb +21 -17
  76. data/spec/rspec/mocks/instance_method_stasher_spec.rb +2 -3
  77. data/spec/rspec/mocks/matchers/have_received_spec.rb +7 -0
  78. data/spec/rspec/mocks/matchers/receive_message_chain_spec.rb +198 -0
  79. data/spec/rspec/mocks/matchers/receive_messages_spec.rb +2 -2
  80. data/spec/rspec/mocks/matchers/receive_spec.rb +19 -6
  81. data/spec/rspec/mocks/method_signature_verifier_spec.rb +272 -0
  82. data/spec/rspec/mocks/methods_spec.rb +0 -1
  83. data/spec/rspec/mocks/multiple_return_value_spec.rb +2 -2
  84. data/spec/rspec/mocks/mutate_const_spec.rb +24 -1
  85. data/spec/rspec/mocks/nil_expectation_warning_spec.rb +6 -22
  86. data/spec/rspec/mocks/null_object_mock_spec.rb +13 -7
  87. data/spec/rspec/mocks/options_hash_spec.rb +3 -3
  88. data/spec/rspec/mocks/{partial_mock_spec.rb → partial_double_spec.rb} +5 -2
  89. data/spec/rspec/mocks/{partial_mock_using_mocks_directly_spec.rb → partial_double_using_mocks_directly_spec.rb} +1 -1
  90. data/spec/rspec/mocks/passing_argument_matchers_spec.rb +18 -0
  91. data/spec/rspec/mocks/serialization_spec.rb +1 -0
  92. data/spec/rspec/mocks/space_spec.rb +218 -7
  93. data/spec/rspec/mocks/stub_chain_spec.rb +6 -0
  94. data/spec/rspec/mocks/stub_spec.rb +0 -6
  95. data/spec/rspec/mocks/syntax_spec.rb +19 -0
  96. data/spec/rspec/mocks/test_double_spec.rb +0 -1
  97. data/spec/rspec/mocks/verifying_double_spec.rb +281 -18
  98. data/spec/rspec/mocks/verifying_message_expecation_spec.rb +7 -6
  99. data/spec/rspec/mocks_spec.rb +168 -42
  100. data/spec/spec_helper.rb +34 -22
  101. metadata +94 -63
  102. metadata.gz.sig +0 -0
  103. checksums.yaml +0 -15
  104. checksums.yaml.gz.sig +0 -2
  105. data/features/outside_rspec/configuration.feature +0 -60
  106. data/lib/rspec/mocks/arity_calculator.rb +0 -66
  107. data/lib/rspec/mocks/errors.rb +0 -12
  108. data/lib/rspec/mocks/mock.rb +0 -7
  109. data/lib/rspec/mocks/proxy_for_nil.rb +0 -37
  110. data/lib/rspec/mocks/stub_chain.rb +0 -51
  111. data/spec/rspec/mocks/argument_expectation_spec.rb +0 -32
  112. data/spec/rspec/mocks/arity_calculator_spec.rb +0 -95
  113. data/spec/rspec/mocks/mock_space_spec.rb +0 -113
  114. data/spec/rspec/mocks/mock_spec.rb +0 -788
metadata.gz.sig CHANGED
Binary file
checksums.yaml DELETED
@@ -1,15 +0,0 @@
1
- ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- MWQyODY3ZjBkNmUxYWY1ZjFlZWNlM2Q0NjZlY2M1OTEwOTI3N2E1ZQ==
5
- data.tar.gz: !binary |-
6
- YzI0OGE3YzFmZDQ4MTc5ZmJlODExYjNjNDE5MzMyOGI4ZTE2ZDY2MQ==
7
- !binary "U0hBNTEy":
8
- metadata.gz: !binary |-
9
- OTA4ZmE4NjJhNDhjYTFmMWU4MmM3OTkzMTk3OTQ3M2YyYTNmMzljYzQzNDFm
10
- MjgwMzE0NDlmZDFmYzVkMzIwZWIzOGYxNjZlN2U1MDMwZDIwNGYxZDkzYWFj
11
- MDAzM2NmMWEyNDA1NTg5OTBmMzViMzdhYjRlMTUyODNmMDJkMjU=
12
- data.tar.gz: !binary |-
13
- YjExYjNmYzZhMTAyZjQyN2RjNWY1NmNhMjRiNmU5NDhjOTY0NWNiYzMxOWUy
14
- MGMzOGIzOTYzNDhmOWNlNzVkODQ5ZmYyN2RmN2MwZGM2ZThmMWIwY2U3NGIx
15
- M2Q3ZTFhNTVkZjFjZmJhNmQ4M2NkNTJhMGRiN2IzMmY3ZThkNGQ=
@@ -1,2 +0,0 @@
1
- }��{ �ͨ�k}���{Z�E ����@;P�?�t���.�+��D.�d�����p3x|�Vv��hhv�p@�i�R8���E(���¸D~�����~�3�jC1Of+Wm7*��k�
2
- �3�
@@ -1,60 +0,0 @@
1
- Feature: configure any test framework to use rspec-mocks
2
-
3
- Test frameworks that want to use rspec-mocks can use
4
- RSpec::Mocks::setup(self) to hook into rspec-mocks. Doing so adds the
5
- following:
6
-
7
- To the object passed to setup:
8
-
9
- double # creates a test double
10
- mock # creates a test double
11
- stub # creates a test double
12
-
13
- To every object in the system:
14
-
15
- should_receive
16
- should_not_receive
17
- stub
18
-
19
- NOTICE: the stub() method that is added to the object passed to setup is not
20
- the same stub() method that is added to every other object.
21
-
22
- Scenario: RSpec::Mocks::setup(object) adds double, mock, and stub methods to the submitted object
23
- Given a file named "foo.rb" with:
24
- """ruby
25
- require 'rspec/mocks'
26
-
27
- class CodeExample
28
- def init
29
- RSpec::Mocks::setup(self)
30
- end
31
- end
32
-
33
- example = CodeExample.new
34
- example.init
35
-
36
- puts example.respond_to?(:double)
37
- """
38
-
39
- When I run `ruby foo.rb`
40
- Then the output should contain "true"
41
- But the output should not contain "false"
42
-
43
- Scenario: RSpec::Mocks::setup(anything) adds methods to Object
44
- Given a file named "foo.rb" with:
45
- """ruby
46
- require 'rspec/mocks'
47
-
48
- RSpec::Mocks::setup(Object.new)
49
-
50
- obj = Object.new
51
-
52
- puts obj.respond_to?(:should_receive)
53
- puts obj.respond_to?(:should_not_receive)
54
- puts obj.respond_to?(:stub)
55
- """
56
-
57
- When I run `ruby foo.rb`
58
- Then the output should contain "true"
59
- But the output should not contain "false"
60
-
@@ -1,66 +0,0 @@
1
- module RSpec
2
- module Mocks
3
-
4
- # Figures out the valid arity range for a method. Surprisingly non-trivial.
5
- class ArityCalculator
6
-
7
- def initialize(method)
8
- @method = method
9
- end
10
-
11
- # @api private
12
- def within_range?(actual)
13
- min_arity <= actual && actual <= max_arity
14
- end
15
-
16
- # @api private
17
- def range_description
18
- return min_arity.to_s if min_arity == max_arity
19
- return "#{min_arity} or more" if max_arity == INFINITY
20
- "#{min_arity} to #{max_arity}"
21
- end
22
-
23
- private
24
-
25
- def method
26
- @method
27
- end
28
-
29
- # @api private
30
- def self.supports_optional_and_splat_args?
31
- Method.method_defined?(:parameters)
32
- end
33
-
34
- def min_arity
35
- return method.arity if method.arity >= 0
36
- # `~` inverts the one's complement and gives us the number of
37
- # required arguments.
38
- ~method.arity
39
- end
40
-
41
- if supports_optional_and_splat_args?
42
- def max_arity
43
- params = method.parameters
44
- if params.any? {|(type, _)| type == :rest }
45
- # Method takes a splat argument
46
- return INFINITY
47
- else
48
- params.count {|(type, _)| type != :block }
49
- end
50
- end
51
- else
52
- def max_arity
53
- # On 1.8, Method#parameters does not exist. There is no way to
54
- # distinguish between default and splat args, so there is no way to
55
- # have it work correctly for both default and splat args, as far as I
56
- # can tell. The best we can do is consider it INFINITY (to be
57
- # tolerant of splat args).
58
- method.arity < 0 ? INFINITY : method.arity
59
- end
60
- end
61
-
62
- INFINITY = 1/0.0
63
- end
64
- end
65
- end
66
-
@@ -1,12 +0,0 @@
1
- module RSpec
2
- module Mocks
3
- # @private
4
- class MockExpectationError < Exception
5
- end
6
-
7
- # @private
8
- class AmbiguousReturnError < StandardError
9
- end
10
- end
11
- end
12
-
@@ -1,7 +0,0 @@
1
- module RSpec
2
- module Mocks
3
- class Mock
4
- include TestDouble
5
- end
6
- end
7
- end
@@ -1,37 +0,0 @@
1
- module RSpec
2
- module Mocks
3
- # @private
4
- class ProxyForNil < Proxy
5
-
6
- def initialize(order_group)
7
- @warn_about_expectations = true
8
- super nil, order_group
9
- end
10
- attr_accessor :warn_about_expectations
11
- alias warn_about_expectations? warn_about_expectations
12
-
13
- def add_message_expectation(location, method_name, opts={}, &block)
14
- warn(method_name) if warn_about_expectations?
15
- super
16
- end
17
-
18
- def add_negative_message_expectation(location, method_name, &implementation)
19
- warn(method_name) if warn_about_expectations?
20
- super
21
- end
22
-
23
- def add_stub(location, method_name, opts={}, &implementation)
24
- warn(method_name) if warn_about_expectations?
25
- super
26
- end
27
-
28
- private
29
-
30
- def warn method_name
31
- source = CallerFilter.first_non_rspec_line
32
- Kernel.warn("An expectation of :#{method_name} was set on nil. Called from #{source}. Use allow_message_expectations_on_nil to disable warnings.")
33
- end
34
-
35
- end
36
- end
37
- end
@@ -1,51 +0,0 @@
1
- module RSpec
2
- module Mocks
3
- # @private
4
- class StubChain
5
- def self.stub_chain_on(object, *chain, &blk)
6
- new(object, *chain, &blk).stub_chain
7
- end
8
-
9
- attr_reader :object, :chain, :block
10
-
11
- def initialize(object, *chain, &blk)
12
- @object = object
13
- @chain, @block = format_chain(*chain, &blk)
14
- end
15
-
16
- def stub_chain
17
- if chain.length > 1
18
- if matching_stub = find_matching_stub
19
- chain.shift
20
- matching_stub.invoke(nil).stub_chain(*chain, &block)
21
- else
22
- next_in_chain = Mock.new
23
- object.stub(chain.shift) { next_in_chain }
24
- StubChain.stub_chain_on(next_in_chain, *chain, &block)
25
- end
26
- else
27
- object.stub(chain.shift, &block)
28
- end
29
- end
30
-
31
- private
32
-
33
- def format_chain(*chain, &blk)
34
- if Hash === chain.last
35
- hash = chain.pop
36
- hash.each do |k,v|
37
- chain << k
38
- blk = lambda { v }
39
- end
40
- end
41
- return chain.join('.').split('.'), blk
42
- end
43
-
44
- def find_matching_stub
45
- ::RSpec::Mocks.proxy_for(object).
46
- __send__(:find_matching_method_stub, chain.first.to_sym)
47
- end
48
- end
49
- end
50
- end
51
-
@@ -1,32 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module RSpec
4
- module Mocks
5
- describe ArgumentListMatcher do
6
- let(:argument_expectation) { RSpec::Mocks::ArgumentListMatcher.new }
7
- let(:obj) { double("matcher") }
8
-
9
- it "considers an object that responds to #matches? and #failure_message_for_should to be a matcher" do
10
- obj.stub(:matches?)
11
- obj.stub(:failure_message_for_should)
12
- expect(argument_expectation.send(:is_matcher?, obj)).to be_truthy
13
- end
14
-
15
- it "considers an object that responds to #matches? and #failure_message to be a matcher for backward compatibility" do
16
- obj.stub(:matches?)
17
- obj.stub(:failure_message)
18
- expect(argument_expectation.send(:is_matcher?, obj)).to be_truthy
19
- end
20
-
21
- it "does NOT consider an object that only responds to #matches? to be a matcher" do
22
- obj.stub(:matches?)
23
- expect(argument_expectation.send(:is_matcher?, obj)).to be_falsey
24
- end
25
-
26
- it "does not consider a null object to be a matcher" do
27
- obj.as_null_object
28
- expect(argument_expectation.send(:is_matcher?, obj)).to be_falsey
29
- end
30
- end
31
- end
32
- end
@@ -1,95 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module RSpec
4
- module Mocks
5
- describe ArityCalculator do
6
- describe '#verify!' do
7
- subject { described_class.new(test_method) }
8
-
9
- def within_range?(arity)
10
- subject.within_range?(arity)
11
- end
12
-
13
- def description
14
- subject.range_description
15
- end
16
-
17
- describe 'with a method with arguments' do
18
- def arity_two(x, y); end
19
-
20
- let(:test_method) { method(:arity_two) }
21
-
22
- it 'covers only the exact arity' do
23
- expect(within_range?(1)).to eq(false)
24
- expect(within_range?(2)).to eq(true)
25
- expect(within_range?(3)).to eq(false)
26
- end
27
-
28
- it 'is described precisely' do
29
- expect(description).to eq("2")
30
- end
31
- end
32
-
33
- describe 'a method with splat arguments' do
34
- def arity_splat(_, *); end
35
-
36
- let(:test_method) { method(:arity_splat) }
37
-
38
- it 'covers a range from the lower bound upwards' do
39
- expect(within_range?(0)).to eq(false)
40
- expect(within_range?(1)).to eq(true)
41
- expect(within_range?(2)).to eq(true)
42
- expect(within_range?(3)).to eq(true)
43
- end
44
-
45
- it 'is described with no upper bound' do
46
- expect(description).to eq("1 or more")
47
- end
48
- end
49
-
50
- describe 'a method with optional arguments' do
51
- def arity_optional(x, y, z = 1); end
52
-
53
- let(:test_method) { method(:arity_optional) }
54
-
55
- it 'covers a range from min to max possible arguments' do
56
- expect(within_range?(1)).to eq(false)
57
- expect(within_range?(2)).to eq(true)
58
- expect(within_range?(3)).to eq(true)
59
-
60
- if ArityCalculator.supports_optional_and_splat_args?
61
- expect(within_range?(4)).to eq(false)
62
- else
63
- expect(within_range?(4)).to eq(true)
64
- end
65
- end
66
-
67
- if ArityCalculator.supports_optional_and_splat_args?
68
- it 'is described as a range' do
69
- expect(description).to eq("2 to 3")
70
- end
71
- else
72
- it 'is described with no upper bound' do
73
- expect(description).to eq("2 or more")
74
- end
75
- end
76
- end
77
-
78
- describe 'a method with a block' do
79
- def arity_block(_, &block); end
80
-
81
- let(:test_method) { method(:arity_block) }
82
-
83
- it 'does not count the block as a parameter' do
84
- expect(within_range?(1)).to eq(true)
85
- expect(within_range?(2)).to eq(false)
86
- end
87
-
88
- it 'is described precisely' do
89
- expect(description).to eq("1")
90
- end
91
- end
92
- end
93
- end
94
- end
95
- end
@@ -1,113 +0,0 @@
1
- require 'spec_helper'
2
- require 'rspec/mocks'
3
-
4
- module RSpec
5
- module Mocks
6
- describe Space do
7
- let(:space) { RSpec::Mocks::Space.new }
8
- let(:dbl_1) { Object.new }
9
- let(:dbl_2) { Object.new }
10
-
11
- before do
12
- space.ensure_registered(dbl_1)
13
- space.ensure_registered(dbl_2)
14
- end
15
-
16
- it "verifies all mocks within" do
17
- verifies = []
18
-
19
- space.proxy_for(dbl_1).stub(:verify) { verifies << :dbl_1 }
20
- space.proxy_for(dbl_2).stub(:verify) { verifies << :dbl_2 }
21
-
22
- space.verify_all
23
-
24
- expect(verifies).to match_array([:dbl_1, :dbl_2])
25
- end
26
-
27
- def define_singleton_method_on_recorder_for(klass, name, &block)
28
- recorder = space.any_instance_recorder_for(klass)
29
- (class << recorder; self; end).send(:define_method, name, &block)
30
- end
31
-
32
- it 'verifies all any_instance recorders within' do
33
- klass_1, klass_2 = Class.new, Class.new
34
-
35
- verifies = []
36
-
37
- # We can't `stub` a method on the recorder because it defines its own `stub`...
38
- define_singleton_method_on_recorder_for(klass_1, :verify) { verifies << :klass_1 }
39
- define_singleton_method_on_recorder_for(klass_2, :verify) { verifies << :klass_2 }
40
-
41
- space.verify_all
42
-
43
- expect(verifies).to match_array([:klass_1, :klass_2])
44
- end
45
-
46
- it "resets all mocks within" do
47
- resets = []
48
-
49
- space.proxy_for(dbl_1).stub(:reset) { resets << :dbl_1 }
50
- space.proxy_for(dbl_2).stub(:reset) { resets << :dbl_2 }
51
-
52
- space.reset_all
53
-
54
- expect(resets).to match_array([:dbl_1, :dbl_2])
55
- end
56
-
57
- it "does not leak mock proxies between examples" do
58
- expect {
59
- space.reset_all
60
- }.to change { space.proxies.size }.to(0)
61
- end
62
-
63
- it 'does not leak any instance recorders between examples' do
64
- space.any_instance_recorder_for(Class.new)
65
- expect {
66
- space.reset_all
67
- }.to change { space.any_instance_recorders.size }.to(0)
68
- end
69
-
70
- it "resets the ordering" do
71
- space.expectation_ordering.register :some_expectation
72
-
73
- expect {
74
- space.reset_all
75
- }.to change { space.expectation_ordering.empty? }.from(false).to(true)
76
- end
77
-
78
- it "only adds an instance once" do
79
- m1 = double("mock1")
80
-
81
- expect {
82
- space.ensure_registered(m1)
83
- }.to change { space.proxies }
84
-
85
- expect {
86
- space.ensure_registered(m1)
87
- }.not_to change { space.proxies }
88
- end
89
-
90
- it 'returns a consistent any_instance_recorder for a given class' do
91
- klass_1, klass_2 = Class.new, Class.new
92
-
93
- r1 = space.any_instance_recorder_for(klass_1)
94
- r2 = space.any_instance_recorder_for(klass_1)
95
- r3 = space.any_instance_recorder_for(klass_2)
96
-
97
- expect(r1).to be(r2)
98
- expect(r1).not_to be(r3)
99
- end
100
-
101
- it 'removes an any_instance_recorder when requested' do
102
- klass = Class.new
103
-
104
- space.any_instance_recorder_for(klass)
105
-
106
- expect {
107
- space.remove_any_instance_recorder_for(klass)
108
- }.to change { space.any_instance_recorders.size }.by(-1)
109
- end
110
- end
111
- end
112
- end
113
-