minitest 5.5.1 → 5.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/{History.txt → History.rdoc} +25 -3
- data/Manifest.txt +2 -2
- data/{README.txt → README.rdoc} +49 -18
- data/Rakefile +10 -9
- data/lib/minitest.rb +15 -10
- data/lib/minitest/assertions.rb +22 -23
- data/lib/minitest/benchmark.rb +14 -15
- data/lib/minitest/expectations.rb +31 -4
- data/lib/minitest/mock.rb +24 -20
- data/lib/minitest/parallel.rb +14 -4
- data/lib/minitest/pride_plugin.rb +2 -2
- data/lib/minitest/spec.rb +25 -20
- data/lib/minitest/test.rb +8 -10
- data/test/minitest/metametameta.rb +10 -10
- data/test/minitest/test_minitest_benchmark.rb +3 -3
- data/test/minitest/test_minitest_mock.rb +11 -13
- data/test/minitest/test_minitest_spec.rb +48 -26
- data/test/minitest/test_minitest_unit.rb +59 -59
- metadata +9 -14
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8a1532fd0d9c25161ae3d4cae3357c707315d4d2
|
4
|
+
data.tar.gz: 827d205c0a4e09b33a5ec0db933ed7d0a024e718
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1fbb8e6fef5e909de09ed424a977ee7a1d4cb9510213b1dbdce103ce28ef6b213024379e8ffedf42fd423f90464d07f6eeb50bc8c978e3131dc34b02a26a3f42
|
7
|
+
data.tar.gz: 7e1c4342ce4313b98020f7f715d344bc222b8ee40b65d0ee3e9213e89f7b76c39ba268022579a34656da2b2a4dffe1fcfc2ef5e765d02fc521cb7b7a10305948
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
@@ -1,10 +1,32 @@
|
|
1
|
+
=== 5.6.0 / 2015-04-13
|
2
|
+
|
3
|
+
* 4 major enhancements:
|
4
|
+
|
5
|
+
* Added Minitest::Expectation value monad.
|
6
|
+
* Added Minitest::Expectations#_ that returns an Expectation. Aliased to value.
|
7
|
+
* All expectations are added to Minitest::Expectation.
|
8
|
+
* At some point, the methods on Object will be deprecated and then removed.
|
9
|
+
|
10
|
+
* 4 minor enhancements:
|
11
|
+
|
12
|
+
* Added a note about bundle exec pitfall in ruby 2.2+. (searls)
|
13
|
+
* Lazily start the parallel executor. (tenderlove)
|
14
|
+
* Make mocks more debugger-friendly (edward)
|
15
|
+
* Print out the current test run on interrupt. (riffraff)
|
16
|
+
|
17
|
+
* 3 bug fixes:
|
18
|
+
|
19
|
+
* Fix failing test under Windows. (kimhmadsen)
|
20
|
+
* Record mocked calls before they happen so mocks can raise exceptions easier (tho I'm not a fan). (corecode)
|
21
|
+
* Tried to clarify mocks vs stubs terminology better. (kkirsche)
|
22
|
+
|
1
23
|
=== 5.5.1 / 2015-01-09
|
2
24
|
|
3
25
|
* 1 bug fix:
|
4
26
|
|
5
27
|
* Fixed doco problems. (zzak)
|
6
28
|
|
7
|
-
=== 5.5.0 / 2014-12-12
|
29
|
+
=== 5.5.0 / 2014-12-12 // mri 2.2.0 (as a real gem)
|
8
30
|
|
9
31
|
* 1 minor enhancement:
|
10
32
|
|
@@ -149,7 +171,7 @@
|
|
149
171
|
|
150
172
|
* Fixed missing require in minitest/test. (erikh)
|
151
173
|
|
152
|
-
=== 4.7.5 / 2013-06-21
|
174
|
+
=== 4.7.5 / 2013-06-21 // mri 2.1.1
|
153
175
|
|
154
176
|
* 2 bug fixes:
|
155
177
|
|
@@ -388,7 +410,7 @@ back.
|
|
388
410
|
|
389
411
|
* Updated information about stubbing. (daviddavis)
|
390
412
|
|
391
|
-
=== 4.3.2 / 2012-11-27
|
413
|
+
=== 4.3.2 / 2012-11-27 // mri 2.0.0
|
392
414
|
|
393
415
|
* 1 minor enhancement:
|
394
416
|
|
data/Manifest.txt
CHANGED
data/{README.txt → README.rdoc}
RENAMED
@@ -139,6 +139,8 @@ Define your tests as methods beginning with `test_`.
|
|
139
139
|
For matchers support check out:
|
140
140
|
|
141
141
|
https://github.com/wojtekmach/minitest-matchers
|
142
|
+
https://github.com/rmm5t/minitest-matchers_vaccine
|
143
|
+
|
142
144
|
=== Benchmarks
|
143
145
|
|
144
146
|
Add benchmarks to your tests.
|
@@ -182,38 +184,51 @@ Output is tab-delimited to make it easy to paste into a spreadsheet.
|
|
182
184
|
|
183
185
|
=== Mocks
|
184
186
|
|
187
|
+
Mocks and stubs defined using terminology by Fowler & Meszaros at
|
188
|
+
http://www.martinfowler.com/bliki/TestDouble.html:
|
189
|
+
|
190
|
+
"Mocks are pre-programmed with expectations which form a specification
|
191
|
+
of the calls they are expected to receive. They can throw an exception
|
192
|
+
if they receive a call they don't expect and are checked during
|
193
|
+
verification to ensure they got all the calls they were expecting."
|
194
|
+
|
185
195
|
class MemeAsker
|
186
196
|
def initialize(meme)
|
187
197
|
@meme = meme
|
188
198
|
end
|
189
199
|
|
190
200
|
def ask(question)
|
191
|
-
method = question.tr(" ","_") + "?"
|
201
|
+
method = question.tr(" ", "_") + "?"
|
192
202
|
@meme.__send__(method)
|
193
203
|
end
|
194
204
|
end
|
195
205
|
|
196
206
|
require "minitest/autorun"
|
197
207
|
|
198
|
-
describe MemeAsker do
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
208
|
+
describe MemeAsker, :ask do
|
209
|
+
describe "when passed an unpunctuated question" do
|
210
|
+
it "should invoke the appropriate predicate method on the meme" do
|
211
|
+
@meme = Minitest::Mock.new
|
212
|
+
@meme_asker = MemeAsker.new @meme
|
213
|
+
@meme.expect :will_it_blend?, :return_value
|
203
214
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
@meme.expect :will_it_blend?, :return_value
|
208
|
-
@meme_asker.ask "will it blend"
|
209
|
-
@meme.verify
|
210
|
-
end
|
215
|
+
@meme_asker.ask "will it blend"
|
216
|
+
|
217
|
+
@meme.verify
|
211
218
|
end
|
212
219
|
end
|
213
220
|
end
|
214
221
|
|
215
222
|
=== Stubs
|
216
223
|
|
224
|
+
Mocks and stubs are defined using terminology by Fowler & Meszaros at
|
225
|
+
http://www.martinfowler.com/bliki/TestDouble.html:
|
226
|
+
|
227
|
+
"Stubs provide canned answers to calls made during the test".
|
228
|
+
|
229
|
+
Minitest's stub method overrides a single method for the duration of
|
230
|
+
the block.
|
231
|
+
|
217
232
|
def test_stale_eh
|
218
233
|
obj_under_test = Something.new
|
219
234
|
|
@@ -266,7 +281,8 @@ provided via plugins. To see them, simply run with `--help`:
|
|
266
281
|
== Writing Extensions
|
267
282
|
|
268
283
|
To define a plugin, add a file named minitest/XXX_plugin.rb to your
|
269
|
-
project/gem.
|
284
|
+
project/gem. That file must be discoverable via ruby's LOAD_PATH (via
|
285
|
+
rubygems or otherwise). Minitest will find and require that file using
|
270
286
|
Gem.find_files. It will then try to call plugin_XXX_init during
|
271
287
|
startup. The option processor will also try to call plugin_XXX_options
|
272
288
|
passing the OptionParser instance and the current options hash. This
|
@@ -326,6 +342,8 @@ Using our example above, here is how we might implement MyCI:
|
|
326
342
|
CI.connect(addr, port).send_results self.results
|
327
343
|
end
|
328
344
|
end
|
345
|
+
|
346
|
+
# code from above...
|
329
347
|
end
|
330
348
|
|
331
349
|
== FAQ
|
@@ -400,6 +418,13 @@ you want to extend your test using setup/teardown via a module, just
|
|
400
418
|
make sure you ALWAYS call super. before/after automatically call super
|
401
419
|
for you, so make sure you don't do it twice.
|
402
420
|
|
421
|
+
=== Why am I seeing `uninitialized constant MiniTest::Test (NameError)`?
|
422
|
+
|
423
|
+
Are you running the test with Bundler (e.g. via `bundle exec`)? If so,
|
424
|
+
in order to require minitest, you must first add the `gem 'minitest'`
|
425
|
+
to your Gemfile and run `bundle`. Once it's installed, you should be
|
426
|
+
able to require minitest and run your tests.
|
427
|
+
|
403
428
|
== Prominent Projects using Minitest:
|
404
429
|
|
405
430
|
* arel
|
@@ -416,8 +441,11 @@ for you, so make sure you don't do it twice.
|
|
416
441
|
capybara_minitest_spec :: Bridge between Capybara RSpec matchers and
|
417
442
|
Minitest::Spec expectations (e.g.
|
418
443
|
page.must_have_content("Title")).
|
419
|
-
|
420
|
-
|
444
|
+
color_pound_spec_reporter :: Test names print Ruby Object types in color with
|
445
|
+
your Minitest Spec style tests.
|
446
|
+
minispec-metadata :: Metadata for describe/it blocks & CLI tag filter.
|
447
|
+
E.g. `it "requires JS driver", js: true do` &
|
448
|
+
`ruby test.rb --tag js` runs tests tagged :js.
|
421
449
|
minitest-ansi :: Colorize minitest output with ANSI colors.
|
422
450
|
minitest-around :: Around block for minitest. An alternative to
|
423
451
|
setup/teardown dance.
|
@@ -453,6 +481,7 @@ minitest-firemock :: Makes your Minitest mocks more resilient.
|
|
453
481
|
minitest-great_expectations :: Generally useful additions to minitest's
|
454
482
|
assertions and expectations.
|
455
483
|
minitest-growl :: Test notifier for minitest via growl.
|
484
|
+
minitest-happy :: GLOBALLY ACTIVATE MINITEST PRIDE! RAWR!
|
456
485
|
minitest-implicit-subject :: Implicit declaration of the test subject.
|
457
486
|
minitest-instrument :: Instrument ActiveSupport::Notifications when
|
458
487
|
test method is executed.
|
@@ -464,6 +493,8 @@ minitest-macruby :: Provides extensions to minitest for macruby UI
|
|
464
493
|
testing.
|
465
494
|
minitest-matchers :: Adds support for RSpec-style matchers to
|
466
495
|
minitest.
|
496
|
+
minitest-matchers_vaccine :: Adds assertions that adhere to the matcher spec,
|
497
|
+
but without any expectation infections.
|
467
498
|
minitest-metadata :: Annotate tests with metadata (key-value).
|
468
499
|
minitest-mongoid :: Mongoid assertion matchers for Minitest.
|
469
500
|
minitest-must_not :: Provides must_not as an alias for wont in
|
@@ -472,6 +503,7 @@ minitest-osx :: Reporter for the Mac OS X notification center.
|
|
472
503
|
minitest-parallel-db :: Run tests in parallel with a single database.
|
473
504
|
minitest-power_assert :: PowerAssert for Minitest.
|
474
505
|
minitest-predicates :: Adds support for .predicate? methods.
|
506
|
+
minitest-profile :: List the 10 slowest tests in your suite.
|
475
507
|
minitest-rails :: Minitest integration for Rails 3.x.
|
476
508
|
minitest-rails-capybara :: Capybara integration for Minitest::Rails.
|
477
509
|
minitest-reporters :: Create customizable Minitest output formats.
|
@@ -481,6 +513,7 @@ minitest-should_syntax :: RSpec-style +x.should == y+ assertions for
|
|
481
513
|
Minitest.
|
482
514
|
minitest-shouldify :: Adding all manner of shoulds to Minitest (bad
|
483
515
|
idea)
|
516
|
+
minitest-snail :: Print a list of tests that take too long
|
484
517
|
minitest-spec-context :: Provides rspec-ish context method to
|
485
518
|
Minitest::Spec.
|
486
519
|
minitest-spec-expect :: Expect syntax for Minitest::Spec (e.g.
|
@@ -525,8 +558,6 @@ Authors... Please send me a pull request with a description of your minitest ext
|
|
525
558
|
* minitest-spec
|
526
559
|
* minitest-spec-should
|
527
560
|
* minitest-sugar
|
528
|
-
* minitest_should
|
529
|
-
* mongoid-minitest
|
530
561
|
* spork-minitest
|
531
562
|
|
532
563
|
== REQUIREMENTS:
|
data/Rakefile
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
# -*- ruby -*-
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "rubygems"
|
4
|
+
require "hoe"
|
5
5
|
|
6
6
|
Hoe.plugin :seattlerb
|
7
|
+
Hoe.plugin :rdoc
|
7
8
|
|
8
|
-
Hoe.spec
|
9
|
-
developer
|
9
|
+
Hoe.spec "minitest" do
|
10
|
+
developer "Ryan Davis", "ryand-ruby@zenspider.com"
|
10
11
|
|
11
12
|
license "MIT"
|
12
13
|
|
@@ -25,12 +26,12 @@ task :specs do
|
|
25
26
|
|
26
27
|
map = {
|
27
28
|
/(must_throw)s/ => '\1',
|
28
|
-
/(?!not)_same/ =>
|
29
|
-
/_in_/ =>
|
30
|
-
/_operator/ =>
|
31
|
-
/_includes/ =>
|
29
|
+
/(?!not)_same/ => "_be_same_as",
|
30
|
+
/_in_/ => "_be_within_",
|
31
|
+
/_operator/ => "_be",
|
32
|
+
/_includes/ => "_include",
|
32
33
|
/(must|wont)_(.*_of|nil|silent|empty)/ => '\1_be_\2',
|
33
|
-
/must_raises/ =>
|
34
|
+
/must_raises/ => "must_raise",
|
34
35
|
}
|
35
36
|
|
36
37
|
expectations = Minitest::Expectations.public_instance_methods.map(&:to_s)
|
data/lib/minitest.rb
CHANGED
@@ -4,10 +4,10 @@ require "mutex_m"
|
|
4
4
|
require "minitest/parallel"
|
5
5
|
|
6
6
|
##
|
7
|
-
# :include: README.
|
7
|
+
# :include: README.rdoc
|
8
8
|
|
9
9
|
module Minitest
|
10
|
-
VERSION = "5.
|
10
|
+
VERSION = "5.6.0" # :nodoc:
|
11
11
|
ENCS = "".respond_to? :encoding # :nodoc:
|
12
12
|
|
13
13
|
@@installed_at_exit ||= false
|
@@ -20,7 +20,7 @@ module Minitest
|
|
20
20
|
# Parallel test executor
|
21
21
|
|
22
22
|
mc.send :attr_accessor, :parallel_executor
|
23
|
-
self.parallel_executor = Parallel::Executor.new((ENV[
|
23
|
+
self.parallel_executor = Parallel::Executor.new((ENV["N"] || 2).to_i)
|
24
24
|
|
25
25
|
##
|
26
26
|
# Filter object for backtraces.
|
@@ -107,7 +107,7 @@ module Minitest
|
|
107
107
|
# runnable.run(reporter, options)
|
108
108
|
# self.runnable_methods.each
|
109
109
|
# self.run_one_method(self, runnable_method, reporter)
|
110
|
-
# Minitest.run_one_method(klass, runnable_method
|
110
|
+
# Minitest.run_one_method(klass, runnable_method)
|
111
111
|
# klass.new(runnable_method).run
|
112
112
|
|
113
113
|
def self.run args = []
|
@@ -123,8 +123,13 @@ module Minitest
|
|
123
123
|
self.init_plugins options
|
124
124
|
self.reporter = nil # runnables shouldn't depend on the reporter, ever
|
125
125
|
|
126
|
+
self.parallel_executor.start if parallel_executor.respond_to?(:start)
|
126
127
|
reporter.start
|
127
|
-
|
128
|
+
begin
|
129
|
+
__run reporter, options
|
130
|
+
rescue Interrupt
|
131
|
+
warn "Interrupted. Exiting..."
|
132
|
+
end
|
128
133
|
self.parallel_executor.shutdown
|
129
134
|
reporter.report
|
130
135
|
|
@@ -175,13 +180,13 @@ module Minitest
|
|
175
180
|
options[:verbose] = true
|
176
181
|
end
|
177
182
|
|
178
|
-
opts.on "-n", "--name PATTERN","Filter run on /
|
183
|
+
opts.on "-n", "--name PATTERN", "Filter run on /regexp/ or string." do |a|
|
179
184
|
options[:filter] = a
|
180
185
|
end
|
181
186
|
|
182
187
|
unless extensions.empty?
|
183
188
|
opts.separator ""
|
184
|
-
opts.separator "Known extensions: #{extensions.join(
|
189
|
+
opts.separator "Known extensions: #{extensions.join(", ")}"
|
185
190
|
|
186
191
|
extensions.each do |meth|
|
187
192
|
msg = "plugin_#{meth}_options"
|
@@ -277,8 +282,8 @@ module Minitest
|
|
277
282
|
# reporter to record.
|
278
283
|
|
279
284
|
def self.run reporter, options = {}
|
280
|
-
filter = options[:filter] ||
|
281
|
-
filter = Regexp.new $1 if filter =~
|
285
|
+
filter = options[:filter] || "/./"
|
286
|
+
filter = Regexp.new $1 if filter =~ %r%/(.*)/%
|
282
287
|
|
283
288
|
filtered_methods = self.runnable_methods.find_all { |m|
|
284
289
|
filter === m || filter === "#{self}##{m}"
|
@@ -692,7 +697,7 @@ module Minitest
|
|
692
697
|
end
|
693
698
|
|
694
699
|
def message # :nodoc:
|
695
|
-
bt = Minitest
|
700
|
+
bt = Minitest.filter_backtrace(self.backtrace).join "\n "
|
696
701
|
"#{self.exception.class}: #{self.exception.message}\n #{bt}"
|
697
702
|
end
|
698
703
|
|
data/lib/minitest/assertions.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require "rbconfig"
|
2
2
|
require "tempfile"
|
3
|
-
require
|
3
|
+
require "stringio"
|
4
4
|
|
5
5
|
module Minitest
|
6
6
|
##
|
@@ -25,7 +25,7 @@ module Minitest
|
|
25
25
|
# figure out what diff to use.
|
26
26
|
|
27
27
|
def self.diff
|
28
|
-
@diff = if (RbConfig::CONFIG[
|
28
|
+
@diff = if (RbConfig::CONFIG["host_os"] =~ /mswin|mingw/ &&
|
29
29
|
system("diff.exe", __FILE__, __FILE__)) then
|
30
30
|
"diff.exe -u"
|
31
31
|
elsif Minitest::Test.maglev? then
|
@@ -67,7 +67,6 @@ module Minitest
|
|
67
67
|
expect == butwas) &&
|
68
68
|
Minitest::Assertions.diff
|
69
69
|
|
70
|
-
|
71
70
|
return "Expected: #{mu_pp exp}\n Actual: #{mu_pp act}" unless
|
72
71
|
need_to_diff
|
73
72
|
|
@@ -116,7 +115,7 @@ module Minitest
|
|
116
115
|
# uses mu_pp to do the first pass and then cleans it up.
|
117
116
|
|
118
117
|
def mu_pp_for_diff obj
|
119
|
-
mu_pp(obj).gsub(/\\n/, "\n").gsub(/:0x[a-fA-F0-9]{4,}/m,
|
118
|
+
mu_pp(obj).gsub(/\\n/, "\n").gsub(/:0x[a-fA-F0-9]{4,}/m, ":0xXXXXXX")
|
120
119
|
end
|
121
120
|
|
122
121
|
##
|
@@ -435,25 +434,25 @@ module Minitest
|
|
435
434
|
def capture_subprocess_io
|
436
435
|
_synchronize do
|
437
436
|
begin
|
438
|
-
|
437
|
+
require "tempfile"
|
439
438
|
|
440
|
-
|
439
|
+
captured_stdout, captured_stderr = Tempfile.new("out"), Tempfile.new("err")
|
441
440
|
|
442
|
-
|
443
|
-
|
444
|
-
|
441
|
+
orig_stdout, orig_stderr = $stdout.dup, $stderr.dup
|
442
|
+
$stdout.reopen captured_stdout
|
443
|
+
$stderr.reopen captured_stderr
|
445
444
|
|
446
|
-
|
445
|
+
yield
|
447
446
|
|
448
|
-
|
449
|
-
|
447
|
+
$stdout.rewind
|
448
|
+
$stderr.rewind
|
450
449
|
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
450
|
+
return captured_stdout.read, captured_stderr.read
|
451
|
+
ensure
|
452
|
+
captured_stdout.unlink
|
453
|
+
captured_stderr.unlink
|
454
|
+
$stdout.reopen orig_stdout
|
455
|
+
$stderr.reopen orig_stderr
|
457
456
|
end
|
458
457
|
end
|
459
458
|
end
|
@@ -467,7 +466,7 @@ module Minitest
|
|
467
466
|
"Class: <#{e.class}>",
|
468
467
|
"Message: <#{e.message.inspect}>",
|
469
468
|
"---Backtrace---",
|
470
|
-
"#{Minitest
|
469
|
+
"#{Minitest.filter_backtrace(e.backtrace).join("\n")}",
|
471
470
|
"---------------",
|
472
471
|
].join "\n"
|
473
472
|
end
|
@@ -494,7 +493,7 @@ module Minitest
|
|
494
493
|
##
|
495
494
|
# used for counting assertions
|
496
495
|
|
497
|
-
def pass
|
496
|
+
def pass _msg = nil
|
498
497
|
assert true
|
499
498
|
end
|
500
499
|
|
@@ -503,7 +502,7 @@ module Minitest
|
|
503
502
|
|
504
503
|
def refute test, msg = nil
|
505
504
|
msg ||= "Failed refutation, no message given"
|
506
|
-
not assert
|
505
|
+
not assert !test, msg
|
507
506
|
end
|
508
507
|
|
509
508
|
##
|
@@ -581,7 +580,7 @@ module Minitest
|
|
581
580
|
# Fails if +matcher+ <tt>=~</tt> +obj+.
|
582
581
|
|
583
582
|
def refute_match matcher, obj, msg = nil
|
584
|
-
msg = message(msg) {"Expected #{mu_pp matcher} to not match #{mu_pp obj}"}
|
583
|
+
msg = message(msg) { "Expected #{mu_pp matcher} to not match #{mu_pp obj}" }
|
585
584
|
assert_respond_to matcher, :"=~"
|
586
585
|
matcher = Regexp.new Regexp.escape matcher if String === matcher
|
587
586
|
refute matcher =~ obj, msg
|
@@ -603,7 +602,7 @@ module Minitest
|
|
603
602
|
|
604
603
|
def refute_operator o1, op, o2 = UNDEFINED, msg = nil
|
605
604
|
return refute_predicate o1, op, msg if UNDEFINED == o2
|
606
|
-
msg = message(msg) { "Expected #{mu_pp(o1)} to not be #{op} #{mu_pp(o2)}"}
|
605
|
+
msg = message(msg) { "Expected #{mu_pp(o1)} to not be #{op} #{mu_pp(o2)}" }
|
607
606
|
refute o1.__send__(op, o2), msg
|
608
607
|
end
|
609
608
|
|