mocha 0.9.12 → 0.10.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.
- data/Gemfile +3 -0
- data/Gemfile.minitest.1.3.0 +7 -0
- data/Gemfile.minitest.1.4.0 +7 -0
- data/Gemfile.minitest.1.4.1 +7 -0
- data/Gemfile.minitest.1.4.2 +7 -0
- data/Gemfile.minitest.2.0.0 +7 -0
- data/Gemfile.minitest.2.0.1 +7 -0
- data/Gemfile.minitest.2.3.0 +7 -0
- data/Gemfile.minitest.latest +7 -0
- data/Gemfile.test-unit.2.0.0 +8 -0
- data/Gemfile.test-unit.2.0.1 +7 -0
- data/Gemfile.test-unit.2.0.3 +7 -0
- data/Gemfile.test-unit.latest +7 -0
- data/README.rdoc +4 -0
- data/RELEASE.rdoc +22 -3
- data/Rakefile +17 -90
- data/init.rb +3 -0
- data/lib/mocha.rb +1 -1
- data/lib/mocha/central.rb +4 -4
- data/lib/mocha/class_method.rb +20 -20
- data/lib/mocha/expectation.rb +33 -6
- data/lib/mocha/instance_method.rb +17 -1
- data/lib/mocha/integration/mini_test.rb +17 -13
- data/lib/mocha/integration/mini_test/{version_201_to_202.rb → version_201_to_222.rb} +9 -9
- data/lib/mocha/integration/mini_test/version_230_to_251.rb +59 -0
- data/lib/mocha/integration/test_unit.rb +17 -13
- data/lib/mocha/integration/test_unit/{gem_version_203_to_209.rb → gem_version_203_to_220.rb} +8 -8
- data/lib/mocha/integration/test_unit/gem_version_230_to_233.rb +58 -0
- data/lib/mocha/mock.rb +14 -14
- data/lib/mocha/object.rb +1 -1
- data/lib/mocha/thrower.rb +15 -0
- data/lib/mocha/version.rb +3 -0
- data/mocha.gemspec +43 -0
- data/test/acceptance/acceptance_test_helper.rb +3 -0
- data/test/acceptance/expectations_on_multiple_methods_test.rb +55 -0
- data/test/acceptance/minitest_test.rb +12 -7
- data/test/acceptance/raise_exception_test.rb +39 -0
- data/test/acceptance/{stub_class_method_test.rb → stub_class_method_defined_on_active_record_association_proxy_test.rb} +3 -103
- data/test/acceptance/stub_class_method_defined_on_class_test.rb +72 -0
- data/test/acceptance/stub_class_method_defined_on_module_test.rb +75 -0
- data/test/acceptance/stub_class_method_defined_on_superclass_test.rb +75 -0
- data/test/acceptance/stub_instance_method_defined_on_active_record_association_proxy_test.rb +93 -0
- data/test/acceptance/stub_instance_method_defined_on_class_and_aliased_test.rb +69 -0
- data/test/acceptance/stub_instance_method_defined_on_class_test.rb +66 -0
- data/test/acceptance/stub_instance_method_defined_on_kernel_module_test.rb +75 -0
- data/test/acceptance/stub_instance_method_defined_on_module_test.rb +75 -0
- data/test/acceptance/stub_instance_method_defined_on_object_class_test.rb +75 -0
- data/test/acceptance/stub_instance_method_defined_on_singleton_class_test.rb +70 -0
- data/test/acceptance/stub_instance_method_defined_on_superclass_test.rb +72 -0
- data/test/acceptance/throw_test.rb +45 -0
- data/test/method_definer.rb +3 -3
- data/test/test_helper.rb +0 -6
- data/test/unit/central_test.rb +7 -3
- data/test/unit/class_method_test.rb +10 -10
- data/test/unit/mockery_test.rb +1 -0
- data/test/unit/thrower_test.rb +20 -0
- metadata +110 -33
- data/lib/mocha/metaclass.rb +0 -13
- data/test/acceptance/stub_instance_method_test.rb +0 -206
- data/test/unit/metaclass_test.rb +0 -22
@@ -4,6 +4,14 @@ module Mocha
|
|
4
4
|
|
5
5
|
class InstanceMethod < ClassMethod
|
6
6
|
|
7
|
+
def hide_original_method
|
8
|
+
super if singleton_method?(method)
|
9
|
+
end
|
10
|
+
|
11
|
+
def restore_original_method
|
12
|
+
super if singleton_method?(hidden_method)
|
13
|
+
end
|
14
|
+
|
7
15
|
def method_exists?(method)
|
8
16
|
return true if stubbee.public_methods(false).include?(method)
|
9
17
|
return true if stubbee.protected_methods(false).include?(method)
|
@@ -11,6 +19,14 @@ module Mocha
|
|
11
19
|
return false
|
12
20
|
end
|
13
21
|
|
22
|
+
def singleton_method?(method)
|
23
|
+
__metaclass__ = stubbee.__metaclass__
|
24
|
+
return true if __metaclass__.public_instance_methods(false).include?(method)
|
25
|
+
return true if __metaclass__.protected_instance_methods(false).include?(method)
|
26
|
+
return true if __metaclass__.private_instance_methods(false).include?(method)
|
27
|
+
return false
|
28
|
+
end
|
29
|
+
|
14
30
|
end
|
15
|
-
|
31
|
+
|
16
32
|
end
|
@@ -1,32 +1,34 @@
|
|
1
1
|
require 'mocha/api'
|
2
|
+
require 'mocha/options'
|
2
3
|
|
3
4
|
if !MiniTest::Unit::TestCase.ancestors.include?(Mocha::API)
|
4
|
-
|
5
|
+
|
5
6
|
require 'mocha/integration/mini_test/exception_translation'
|
6
7
|
require 'mocha/integration/mini_test/version_13'
|
7
8
|
require 'mocha/integration/mini_test/version_140'
|
8
9
|
require 'mocha/integration/mini_test/version_141'
|
9
10
|
require 'mocha/integration/mini_test/version_142_to_172'
|
10
11
|
require 'mocha/integration/mini_test/version_200'
|
11
|
-
require 'mocha/integration/mini_test/
|
12
|
-
|
12
|
+
require 'mocha/integration/mini_test/version_201_to_222'
|
13
|
+
require 'mocha/integration/mini_test/version_230_to_251'
|
14
|
+
|
13
15
|
module MiniTest
|
14
16
|
class Unit
|
15
17
|
class TestCase
|
16
|
-
|
18
|
+
|
17
19
|
include Mocha::API
|
18
|
-
|
20
|
+
|
19
21
|
alias_method :run_before_mocha, :run
|
20
22
|
remove_method :run
|
21
|
-
|
23
|
+
|
22
24
|
mini_test_version = begin
|
23
25
|
MiniTest::Unit::VERSION
|
24
26
|
rescue LoadError
|
25
27
|
'unknown'
|
26
28
|
end
|
27
|
-
|
29
|
+
|
28
30
|
$stderr.puts "Detected MiniTest version: #{mini_test_version}" if $options['debug']
|
29
|
-
|
31
|
+
|
30
32
|
if (mini_test_version >= '1.3.0') && (mini_test_version <= '1.3.1')
|
31
33
|
include Mocha::Integration::MiniTest::Version13
|
32
34
|
elsif (mini_test_version == '1.4.0')
|
@@ -37,15 +39,17 @@ if !MiniTest::Unit::TestCase.ancestors.include?(Mocha::API)
|
|
37
39
|
include Mocha::Integration::MiniTest::Version142To172
|
38
40
|
elsif (mini_test_version == '2.0.0')
|
39
41
|
include Mocha::Integration::MiniTest::Version200
|
40
|
-
elsif (mini_test_version >= '2.0.1') && (mini_test_version <= '2.
|
41
|
-
include Mocha::Integration::MiniTest::
|
42
|
-
elsif (mini_test_version
|
42
|
+
elsif (mini_test_version >= '2.0.1') && (mini_test_version <= '2.2.2')
|
43
|
+
include Mocha::Integration::MiniTest::Version201To222
|
44
|
+
elsif (mini_test_version >= '2.3.0') && (mini_test_version <= '2.5.1')
|
45
|
+
include Mocha::Integration::MiniTest::Version230To251
|
46
|
+
elsif (mini_test_version > '2.5.1')
|
43
47
|
$stderr.puts "*** MiniTest integration has not been verified but patching anyway ***" if $options['debug']
|
44
|
-
include Mocha::Integration::MiniTest::
|
48
|
+
include Mocha::Integration::MiniTest::Version230To251
|
45
49
|
else
|
46
50
|
$stderr.puts "*** No Mocha integration for MiniTest version ***" if $options['debug']
|
47
51
|
end
|
48
|
-
|
52
|
+
|
49
53
|
end
|
50
54
|
end
|
51
55
|
end
|
@@ -2,14 +2,14 @@ require 'mocha/integration/mini_test/assertion_counter'
|
|
2
2
|
require 'mocha/expectation_error'
|
3
3
|
|
4
4
|
module Mocha
|
5
|
-
|
5
|
+
|
6
6
|
module Integration
|
7
|
-
|
7
|
+
|
8
8
|
module MiniTest
|
9
|
-
|
10
|
-
module
|
9
|
+
|
10
|
+
module Version201To222
|
11
11
|
def self.included(mod)
|
12
|
-
$stderr.puts "Monkey patching MiniTest >= v2.0.1 <= v2.
|
12
|
+
$stderr.puts "Monkey patching MiniTest >= v2.0.1 <= v2.2.2" if $options['debug']
|
13
13
|
end
|
14
14
|
def run runner
|
15
15
|
trap 'INFO' do
|
@@ -17,7 +17,7 @@ module Mocha
|
|
17
17
|
warn "%s#%s %.2fs" % [self.class, self.__name__, time]
|
18
18
|
runner.status $stderr
|
19
19
|
end if ::MiniTest::Unit::TestCase::SUPPORTS_INFO_SIGNAL
|
20
|
-
|
20
|
+
|
21
21
|
assertion_counter = AssertionCounter.new(self)
|
22
22
|
result = ""
|
23
23
|
begin
|
@@ -49,9 +49,9 @@ module Mocha
|
|
49
49
|
result
|
50
50
|
end
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
end
|
54
|
-
|
54
|
+
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'mocha/integration/mini_test/assertion_counter'
|
2
|
+
require 'mocha/expectation_error'
|
3
|
+
|
4
|
+
module Mocha
|
5
|
+
|
6
|
+
module Integration
|
7
|
+
|
8
|
+
module MiniTest
|
9
|
+
|
10
|
+
module Version230To251
|
11
|
+
def self.included(mod)
|
12
|
+
$stderr.puts "Monkey patching MiniTest >= v2.3.0 <= v2.5.1" if $options['debug']
|
13
|
+
end
|
14
|
+
def run runner
|
15
|
+
trap 'INFO' do
|
16
|
+
time = runner.start_time ? Time.now - runner.start_time : 0
|
17
|
+
warn "%s#%s %.2fs" % [self.class, self.__name__, time]
|
18
|
+
runner.status $stderr
|
19
|
+
end if ::MiniTest::Unit::TestCase::SUPPORTS_INFO_SIGNAL
|
20
|
+
|
21
|
+
assertion_counter = AssertionCounter.new(self)
|
22
|
+
result = ""
|
23
|
+
begin
|
24
|
+
begin
|
25
|
+
@passed = nil
|
26
|
+
self.setup
|
27
|
+
self.run_setup_hooks
|
28
|
+
self.__send__ self.__name__
|
29
|
+
mocha_verify(assertion_counter)
|
30
|
+
result = "." unless io?
|
31
|
+
@passed = true
|
32
|
+
rescue *::MiniTest::Unit::TestCase::PASSTHROUGH_EXCEPTIONS
|
33
|
+
raise
|
34
|
+
rescue Exception => e
|
35
|
+
@passed = false
|
36
|
+
result = runner.puke self.class, self.__name__, Mocha::Integration::MiniTest.translate(e)
|
37
|
+
ensure
|
38
|
+
begin
|
39
|
+
self.run_teardown_hooks
|
40
|
+
self.teardown
|
41
|
+
rescue *::MiniTest::Unit::TestCase::PASSTHROUGH_EXCEPTIONS
|
42
|
+
raise
|
43
|
+
rescue Exception => e
|
44
|
+
result = runner.puke self.class, self.__name__, Mocha::Integration::MiniTest.translate(e)
|
45
|
+
end
|
46
|
+
trap 'INFO', 'DEFAULT' if ::MiniTest::Unit::TestCase::SUPPORTS_INFO_SIGNAL
|
47
|
+
end
|
48
|
+
ensure
|
49
|
+
mocha_teardown
|
50
|
+
end
|
51
|
+
result
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -1,22 +1,24 @@
|
|
1
1
|
require 'mocha/api'
|
2
|
+
require 'mocha/options'
|
2
3
|
|
3
4
|
if !Test::Unit::TestCase.ancestors.include?(Mocha::API)
|
4
|
-
|
5
|
+
|
5
6
|
require 'mocha/integration/test_unit/gem_version_200'
|
6
7
|
require 'mocha/integration/test_unit/gem_version_201_to_202'
|
7
|
-
require 'mocha/integration/test_unit/
|
8
|
+
require 'mocha/integration/test_unit/gem_version_203_to_220'
|
9
|
+
require 'mocha/integration/test_unit/gem_version_230_to_233'
|
8
10
|
require 'mocha/integration/test_unit/ruby_version_185_and_below'
|
9
11
|
require 'mocha/integration/test_unit/ruby_version_186_and_above'
|
10
|
-
|
12
|
+
|
11
13
|
module Test
|
12
14
|
module Unit
|
13
15
|
class TestCase
|
14
|
-
|
16
|
+
|
15
17
|
include Mocha::API
|
16
|
-
|
18
|
+
|
17
19
|
alias_method :run_before_mocha, :run
|
18
20
|
remove_method :run
|
19
|
-
|
21
|
+
|
20
22
|
test_unit_version = begin
|
21
23
|
load 'test/unit/version.rb'
|
22
24
|
Test::Unit::VERSION
|
@@ -39,17 +41,19 @@ if !Test::Unit::TestCase.ancestors.include?(Mocha::API)
|
|
39
41
|
include Mocha::Integration::TestUnit::GemVersion200
|
40
42
|
elsif (test_unit_version >= '2.0.1') && (test_unit_version <= '2.0.2')
|
41
43
|
include Mocha::Integration::TestUnit::GemVersion201To202
|
42
|
-
elsif (test_unit_version >= '2.0.3') && (test_unit_version <= '2.0
|
43
|
-
include Mocha::Integration::TestUnit::
|
44
|
-
elsif (test_unit_version
|
44
|
+
elsif (test_unit_version >= '2.0.3') && (test_unit_version <= '2.2.0')
|
45
|
+
include Mocha::Integration::TestUnit::GemVersion203To220
|
46
|
+
elsif (test_unit_version >= '2.3.0') && (test_unit_version <= '2.3.3')
|
47
|
+
include Mocha::Integration::TestUnit::GemVersion230To233
|
48
|
+
elsif (test_unit_version > '2.3.3')
|
45
49
|
$stderr.puts "*** Test::Unit integration has not been verified but patching anyway ***" if $options['debug']
|
46
|
-
include Mocha::Integration::TestUnit::
|
50
|
+
include Mocha::Integration::TestUnit::GemVersion230To233
|
47
51
|
else
|
48
52
|
$stderr.puts "*** No Mocha integration for Test::Unit version ***" if $options['debug']
|
49
53
|
end
|
50
|
-
|
54
|
+
|
51
55
|
end
|
52
56
|
end
|
53
57
|
end
|
54
|
-
|
55
|
-
end
|
58
|
+
|
59
|
+
end
|
data/lib/mocha/integration/test_unit/{gem_version_203_to_209.rb → gem_version_203_to_220.rb}
RENAMED
@@ -3,14 +3,14 @@ require 'mocha/integration/test_unit/assertion_counter'
|
|
3
3
|
require 'mocha/expectation_error'
|
4
4
|
|
5
5
|
module Mocha
|
6
|
-
|
6
|
+
|
7
7
|
module Integration
|
8
|
-
|
8
|
+
|
9
9
|
module TestUnit
|
10
|
-
|
11
|
-
module
|
10
|
+
|
11
|
+
module GemVersion203To220
|
12
12
|
def self.included(mod)
|
13
|
-
$stderr.puts "Monkey patching Test::Unit gem >= v2.0.3 and <= v2.0
|
13
|
+
$stderr.puts "Monkey patching Test::Unit gem >= v2.0.3 and <= v2.2.0" if $options['debug']
|
14
14
|
end
|
15
15
|
def run(result)
|
16
16
|
assertion_counter = AssertionCounter.new(result)
|
@@ -44,9 +44,9 @@ module Mocha
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
end
|
49
|
-
|
49
|
+
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'test/unit/testcase'
|
2
|
+
require 'mocha/integration/test_unit/assertion_counter'
|
3
|
+
require 'mocha/expectation_error'
|
4
|
+
|
5
|
+
module Mocha
|
6
|
+
|
7
|
+
module Integration
|
8
|
+
|
9
|
+
module TestUnit
|
10
|
+
|
11
|
+
module GemVersion230To233
|
12
|
+
def self.included(mod)
|
13
|
+
$stderr.puts "Monkey patching Test::Unit gem >= v2.3.0 and <= v2.3.3" if $options['debug']
|
14
|
+
end
|
15
|
+
def run(result)
|
16
|
+
assertion_counter = AssertionCounter.new(result)
|
17
|
+
begin
|
18
|
+
@internal_data.test_started
|
19
|
+
@_result = result
|
20
|
+
yield(Test::Unit::TestCase::STARTED, name)
|
21
|
+
yield(Test::Unit::TestCase::STARTED_OBJECT, name)
|
22
|
+
begin
|
23
|
+
begin
|
24
|
+
run_setup
|
25
|
+
run_test
|
26
|
+
run_cleanup
|
27
|
+
mocha_verify(assertion_counter)
|
28
|
+
add_pass
|
29
|
+
rescue Mocha::ExpectationError => e
|
30
|
+
add_failure(e.message, e.backtrace)
|
31
|
+
rescue Exception
|
32
|
+
@internal_data.interrupted
|
33
|
+
raise unless handle_exception($!)
|
34
|
+
ensure
|
35
|
+
begin
|
36
|
+
run_teardown
|
37
|
+
rescue Exception
|
38
|
+
raise unless handle_exception($!)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
ensure
|
42
|
+
mocha_teardown
|
43
|
+
end
|
44
|
+
@internal_data.test_finished
|
45
|
+
result.add_run
|
46
|
+
yield(Test::Unit::TestCase::FINISHED, name)
|
47
|
+
yield(Test::Unit::TestCase::FINISHED_OBJECT, name)
|
48
|
+
ensure
|
49
|
+
# @_result = nil # For test-spec's after_all :<
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
data/lib/mocha/mock.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
+
require 'metaclass'
|
1
2
|
require 'mocha/expectation'
|
2
3
|
require 'mocha/expectation_list'
|
3
|
-
require 'mocha/metaclass'
|
4
4
|
require 'mocha/names'
|
5
5
|
require 'mocha/method_matcher'
|
6
6
|
require 'mocha/parameters_matcher'
|
@@ -8,12 +8,12 @@ require 'mocha/unexpected_invocation'
|
|
8
8
|
require 'mocha/argument_iterator'
|
9
9
|
|
10
10
|
module Mocha # :nodoc:
|
11
|
-
|
11
|
+
|
12
12
|
# Traditional mock object.
|
13
13
|
#
|
14
14
|
# Methods return an Expectation which can be further modified by methods on Expectation.
|
15
15
|
class Mock
|
16
|
-
|
16
|
+
|
17
17
|
# :call-seq: expects(method_name) -> expectation
|
18
18
|
# expects(method_names_vs_return_values) -> last expectation
|
19
19
|
#
|
@@ -48,7 +48,7 @@ module Mocha # :nodoc:
|
|
48
48
|
@expectations.add(expectation)
|
49
49
|
}
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
# :call-seq: stubs(method_name) -> expectation
|
53
53
|
# stubs(method_names_vs_return_values) -> last expectation
|
54
54
|
#
|
@@ -81,7 +81,7 @@ module Mocha # :nodoc:
|
|
81
81
|
@expectations.add(expectation)
|
82
82
|
}
|
83
83
|
end
|
84
|
-
|
84
|
+
|
85
85
|
# :call-seq: responds_like(responder) -> mock
|
86
86
|
#
|
87
87
|
# Constrains the +mock+ so that it can only expect or stub methods to which +responder+ responds. The constraint is only applied at method invocation time.
|
@@ -126,9 +126,9 @@ module Mocha # :nodoc:
|
|
126
126
|
@responder = object
|
127
127
|
self
|
128
128
|
end
|
129
|
-
|
129
|
+
|
130
130
|
# :stopdoc:
|
131
|
-
|
131
|
+
|
132
132
|
def initialize(name = nil, &block)
|
133
133
|
@name = name || DefaultName.new(self)
|
134
134
|
@expectations = ExpectationList.new
|
@@ -142,13 +142,13 @@ module Mocha # :nodoc:
|
|
142
142
|
alias_method :__expects__, :expects
|
143
143
|
|
144
144
|
alias_method :__stubs__, :stubs
|
145
|
-
|
145
|
+
|
146
146
|
alias_method :quacks_like, :responds_like
|
147
147
|
|
148
148
|
def stub_everything
|
149
149
|
@everything_stubbed = true
|
150
150
|
end
|
151
|
-
|
151
|
+
|
152
152
|
def method_missing(symbol, *arguments, &block)
|
153
153
|
if @responder and not @responder.respond_to?(symbol)
|
154
154
|
raise NoMethodError, "undefined method `#{symbol}' for #{self.mocha_inspect} which responds like #{@responder.mocha_inspect}"
|
@@ -165,7 +165,7 @@ module Mocha # :nodoc:
|
|
165
165
|
end
|
166
166
|
end
|
167
167
|
end
|
168
|
-
|
168
|
+
|
169
169
|
def respond_to?(symbol, include_private = false)
|
170
170
|
if @responder then
|
171
171
|
if @responder.method(:respond_to?).arity > 1
|
@@ -177,19 +177,19 @@ module Mocha # :nodoc:
|
|
177
177
|
@everything_stubbed || @expectations.matches_method?(symbol)
|
178
178
|
end
|
179
179
|
end
|
180
|
-
|
180
|
+
|
181
181
|
def __verified__?(assertion_counter = nil)
|
182
182
|
@expectations.verified?(assertion_counter)
|
183
183
|
end
|
184
|
-
|
184
|
+
|
185
185
|
def mocha_inspect
|
186
186
|
@name.mocha_inspect
|
187
187
|
end
|
188
|
-
|
188
|
+
|
189
189
|
def inspect
|
190
190
|
mocha_inspect
|
191
191
|
end
|
192
|
-
|
192
|
+
|
193
193
|
def ensure_method_not_already_defined(method_name)
|
194
194
|
self.__metaclass__.send(:undef_method, method_name) if self.__metaclass__.method_defined?(method_name)
|
195
195
|
end
|
data/lib/mocha/object.rb
CHANGED
@@ -110,7 +110,7 @@ module Mocha
|
|
110
110
|
# multiplier.double(2) # => 4
|
111
111
|
# multiplier.stubs(:double).raises
|
112
112
|
# multiplier.double(2) # => raises exception
|
113
|
-
# multiplier.
|
113
|
+
# multiplier.unstub(:double)
|
114
114
|
# multiplier.double(2) # => 4
|
115
115
|
#
|
116
116
|
# The original implementation of <tt>Multiplier#double</tt> is replaced temporarily.
|