├── .gitignore
├── .travis.yml
├── README.md
├── example
└── sample.rb
├── mrbgem.rake
├── mrblib
└── mtest_unit.rb
├── run_test.rb
└── test
└── mtest_unit_test.rb
/.gitignore:
--------------------------------------------------------------------------------
1 | # mrbgems
2 | *.tmp
3 | *.ctmp
4 | *.rbtmp
5 | *.o
6 | *.a
7 | gem_mixlib.c
8 | gem_mrblib.c
9 | gem_srclib.c
10 | .*.swp
11 | /tmp
12 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | script:
2 | - "ruby run_test.rb all test"
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Minimum Test Framework for mruby
2 | =========
3 |
4 | [](https://travis-ci.org/iij/mruby-mtest)
5 |
6 | ## example
7 |
8 | ```ruby
9 | class Test4MTest < MTest::Unit::TestCase
10 | def test_assert
11 | assert(true)
12 | assert(true, 'true sample test')
13 | end
14 | end
15 |
16 | MTest::Unit.new.run
17 | ```
18 |
19 | This example outputs results in a format similar to minitest.
20 |
21 | You can also use `MTest::Unit.new.run` to get mruby-test style output. It is
22 | OK to use minitest style output with mrbtest. mruby-test will be notified of
23 | test runs with either method.
24 |
25 | ### How to use mrbgem's mrbtest
26 |
27 | ```ruby
28 | if Object.const_defined?(:MTest)
29 | class Test4MTest < MTest::Unit::TestCase
30 | def test_assert_nil
31 | assert_nil(nil, 'nil sample test')
32 | end
33 | end
34 |
35 | if $ok_test
36 | MTest::Unit.new.mrbtest
37 | else
38 | MTest::Unit.new.run
39 | end
40 | else
41 | $asserts << "test skip of Test4MTest." if $asserts
42 | end
43 | ```
44 |
45 | ## TODO
46 |
47 | - MiniTest::Unit.autorun is not implemented (because mruby hasn't ``at_exit`` method.)
48 |
49 |
50 | ## License
51 |
52 | Copyright (c) 2013 Internet Initiative Japan Inc.
53 |
54 | Permission is hereby granted, free of charge, to any person obtaining a
55 | copy of this software and associated documentation files (the "Software"),
56 | to deal in the Software without restriction, including without limitation
57 | the rights to use, copy, modify, merge, publish, distribute, sublicense,
58 | and/or sell copies of the Software, and to permit persons to whom the
59 | Software is furnished to do so, subject to the following conditions:
60 |
61 | The above copyright notice and this permission notice shall be included in
62 | all copies or substantial portions of the Software.
63 |
64 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
65 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
66 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
67 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
68 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
69 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
70 | DEALINGS IN THE SOFTWARE.
71 |
72 |
--------------------------------------------------------------------------------
/example/sample.rb:
--------------------------------------------------------------------------------
1 | class Test4MTest < MTest::Unit::TestCase
2 | def test_assert
3 | assert(true)
4 | assert(true, 'true sample test')
5 | end
6 |
7 | def test_assert_block
8 | assert_block('msg') do
9 | 'something-block'
10 | end
11 | end
12 |
13 | def test_assert_empty
14 | assert_empty('', 'string empty')
15 | assert_empty([], 'array empty')
16 | assert_empty({}, 'hash empty')
17 | end
18 |
19 | def test_assert_equal
20 | assert_equal('', nil.to_s)
21 | end
22 |
23 | def test_assert_in_delta
24 | assert_in_delta(0, 0.1, 0.5)
25 | end
26 |
27 | def test_assert_includes
28 | assert_include([1,2,3], 1)
29 | end
30 |
31 | def test_assert_instance_of
32 | assert_instance_of Array, []
33 | assert_instance_of Class, Array
34 | end
35 |
36 | def test_assert_kind_of
37 | assert_kind_of Array, []
38 | assert_kind_of Class, Array
39 | end
40 |
41 | def test_assert_match
42 | assert_match 'abc', 'abc'
43 | end
44 |
45 | def test_skip
46 | skip 'explain why we skip the test'
47 | end
48 |
49 | def test_failure
50 | assert(1 == 0, 'assertion to fail')
51 | end
52 |
53 | def test_error
54 | 1 + "a"
55 | end
56 | end
57 |
58 | MTest::Unit.new.run
59 |
--------------------------------------------------------------------------------
/mrbgem.rake:
--------------------------------------------------------------------------------
1 | MRuby::Gem::Specification.new('mruby-mtest') do |spec|
2 | spec.license = 'MIT'
3 | spec.authors = 'Internet Initiative Japan Inc.'
4 |
5 | spec.add_dependency 'mruby-sprintf', core: 'mruby-sprintf'
6 | spec.add_dependency 'mruby-time', core: 'mruby-time'
7 | if Dir.exist?(File.join(MRUBY_ROOT, "mrbgems", "mruby-io"))
8 | spec.add_dependency 'mruby-io', core: 'mruby-io'
9 | else
10 | spec.add_dependency 'mruby-io', mgem: 'mruby-io'
11 | end
12 | if Dir.exist?(File.join(MRUBY_ROOT, "mrbgems", "mruby-metaprog"))
13 | spec.add_dependency 'mruby-metaprog', :core => 'mruby-metaprog'
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/mrblib/mtest_unit.rb:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | ##
4 | # Minimal Test framework for mruby
5 | #
6 | module MTest
7 |
8 |
9 | ##
10 | # Assertion base class
11 |
12 | class Assertion < Exception; end
13 |
14 | ##
15 | # Assertion raised when skipping a test
16 |
17 | class Skip < Assertion; end
18 |
19 | module Assertions
20 | def mu_pp obj
21 | obj.inspect
22 | end
23 |
24 | def diff exp, act
25 | return "Expected: #{mu_pp exp}\n Actual: #{mu_pp act}"
26 | end
27 |
28 | def _assertions= n
29 | @_assertions = n
30 | end
31 |
32 | def _assertions
33 | @_assertions = 0 unless @_assertions
34 | @_assertions
35 | end
36 |
37 | ##
38 | # Fails unless test is truthy.
39 |
40 | def assert test, msg = nil
41 | msg ||= "Failed assertion, no message given."
42 | self._assertions += 1
43 | unless test
44 | msg = msg.call if Proc === msg
45 | raise MTest::Assertion, msg
46 | end
47 | true
48 | end
49 |
50 | alias assert_true assert
51 |
52 | ##
53 | # Fails if test is truthy.
54 | def assert_false test, msg = nil
55 | msg = message(msg) { "Expected #{mu_pp(test)} to be false" }
56 | assert !test, msg
57 | end
58 |
59 | ##
60 | # Fails unless the block returns a true value.
61 |
62 | def assert_block msg = nil
63 | msg = message(msg) { "Expected block to return true value" }
64 | assert yield, msg
65 | end
66 |
67 | ##
68 | # Fails unless +obj+ is empty.
69 |
70 | def assert_empty obj, msg = nil
71 | msg = message(msg) { "Expected #{mu_pp(obj)} to be empty" }
72 | assert_respond_to obj, :empty?
73 | assert obj.empty?, msg
74 | end
75 |
76 | ##
77 | # Fails +obj+ is not empty.
78 |
79 | def assert_not_empty obj, msg = nil
80 | msg = message(msg) { "Expected #{mu_pp(obj)} to be not empty" }
81 | assert_respond_to obj, :empty?
82 | assert !obj.empty?, msg
83 | end
84 |
85 | ##
86 | # Fails unless exp == act printing the difference between
87 | # the two, if possible.
88 | #
89 | # If there is no visible difference but the assertion fails, you
90 | # should suspect that your #== is buggy, or your inspect output is
91 | # missing crucial details.
92 | #
93 | # For floats use assert_in_delta.
94 | #
95 | # See also: MiniTest::Assertions.diff
96 |
97 | def assert_equal exp, act, msg = nil
98 | msg = message(msg, "") { diff exp, act }
99 | assert(exp == act, msg)
100 | end
101 |
102 | ##
103 | # Fails exp == act
104 | def assert_not_equal exp, act, msg = nil
105 | msg = message(msg) {
106 | "Expected #{mu_pp(exp)} to be not equal #{mu_pp(act)}"
107 | }
108 | assert(exp != act, msg)
109 | end
110 |
111 | ##
112 | # For comparing Floats. Fails unless +exp+ and +act+ are within +delta+
113 | # of each other.
114 | #
115 | # assert_in_delta Math::PI, (22.0 / 7.0), 0.01
116 |
117 | def assert_in_delta exp, act, delta = 0.001, msg = nil
118 | n = (exp - act).abs
119 | msg = message(msg) { "Expected #{exp} - #{act} (#{n}) to be < #{delta}" }
120 | assert delta >= n, msg
121 | end
122 |
123 | ##
124 | # For comparing Floats. Fails unless +exp+ and +act+ have a relative
125 | # error less than +epsilon+.
126 |
127 | def assert_in_epsilon a, b, epsilon = 0.001, msg = nil
128 | assert_in_delta a, b, [a, b].min * epsilon, msg
129 | end
130 |
131 | ##
132 | # Fails unless +collection+ includes +obj+.
133 |
134 | def assert_include collection, obj, msg = nil
135 | msg = message(msg) {
136 | "Expected #{mu_pp(collection)} to include #{mu_pp(obj)}"
137 | }
138 | assert_respond_to collection, :include?
139 | assert collection.include?(obj), msg
140 | end
141 |
142 | ##
143 | # Fails +collection+ includes +obj+
144 | def assert_not_include collection, obj, msg = nil
145 | msg = message(msg) {
146 | "Expected #{mu_pp(collection)} to not include #{mu_pp(obj)}"
147 | }
148 | assert_respond_to collection, :include?
149 | assert !collection.include?(obj), msg
150 | end
151 |
152 | ##
153 | # Fails unless +obj+ is an instance of +cls+.
154 |
155 | def assert_instance_of cls, obj, msg = nil
156 | msg = message(msg) {
157 | "Expected #{mu_pp(obj)} to be an instance of #{cls}, not #{obj.class}"
158 | }
159 |
160 | assert obj.instance_of?(cls), msg
161 | end
162 |
163 | ##
164 | # Fails unless +obj+ is a kind of +cls+.
165 |
166 | def assert_kind_of cls, obj, msg = nil # TODO: merge with instance_of
167 | msg = message(msg) {
168 | "Expected #{mu_pp(obj)} to be a kind of #{cls}, not #{obj.class}" }
169 |
170 | assert obj.kind_of?(cls), msg
171 | end
172 |
173 | ##
174 | # Fails unless +exp+ is =~ +act+.
175 |
176 | def assert_match exp, act, msg = nil
177 | if Object.const_defined?(:Regexp)
178 | msg = message(msg) { "Expected #{mu_pp(exp)} to match #{mu_pp(act)}" }
179 | assert_respond_to act, :"=~"
180 | exp = Regexp.new Regexp.escape exp if String === exp and String === act
181 | assert exp =~ act, msg
182 | else
183 | raise MTest::Skip, "assert_match is not defined, because Regexp is not impl."
184 | end
185 | end
186 |
187 | ##
188 | # Fails unless +obj+ is nil
189 |
190 | def assert_nil obj, msg = nil
191 | msg = message(msg) { "Expected #{mu_pp(obj)} to be nil" }
192 | assert obj.nil?, msg
193 | end
194 |
195 | ##
196 | # For testing equality operators and so-forth.
197 | #
198 | # assert_operator 5, :<=, 4
199 |
200 | def assert_operator o1, op, o2, msg = nil
201 | msg = message(msg) { "Expected #{mu_pp(o1)} to be #{op} #{mu_pp(o2)}" }
202 | assert o1.__send__(op, o2), msg
203 | end
204 |
205 | ##
206 | # Fails if stdout or stderr do not output the expected results.
207 | # Pass in nil if you don't care about that streams output. Pass in
208 | # "" if you require it to be silent.
209 | #
210 | # See also: #assert_silent
211 |
212 | def assert_output stdout = nil, stderr = nil
213 | out, err = capture_io do
214 | yield
215 | end
216 |
217 | x = assert_equal stdout, out, "In stdout" if stdout
218 | y = assert_equal stderr, err, "In stderr" if stderr
219 |
220 | (!stdout || x) && (!stderr || y)
221 | end
222 |
223 | ##
224 | # Fails unless the block raises one of +exp+
225 |
226 | def assert_raise *exp
227 | msg = "#{exp.pop}\n" if String === exp.last
228 |
229 | begin
230 | yield
231 | rescue MTest::Skip => e
232 | return e if exp.include? MTest::Skip
233 | raise e
234 | rescue Exception => e
235 | excepted = exp.any? do |ex|
236 | if ex.instance_of?(Module)
237 | e.kind_of?(ex)
238 | else
239 | e.instance_of?(ex)
240 | end
241 | end
242 |
243 | assert excepted, exception_details(e, "#{msg}#{mu_pp(exp)} exception expected, not")
244 |
245 | return e
246 | end
247 | exp = exp.first if exp.size == 1
248 | flunk "#{msg}#{mu_pp(exp)} expected but nothing was raised."
249 | end
250 |
251 | ##
252 | # Fails unless +obj+ responds to +meth+.
253 |
254 | def assert_respond_to obj, meth, msg = nil
255 | msg = message(msg, '') {
256 | "Expected #{mu_pp(obj)} (#{obj.class}) to respond to ##{meth}"
257 | }
258 | assert obj.respond_to?(meth), msg
259 | end
260 |
261 | ##
262 | # Fails unless +exp+ and +act+ are #equal?
263 |
264 | def assert_same exp, act, msg = nil
265 | msg = message(msg) {
266 | data = [mu_pp(act), act.object_id, mu_pp(exp), exp.object_id]
267 | "Expected %s (oid=%d) to be the same as %s (oid=%d)" % data
268 | }
269 | assert exp.equal?(act), msg
270 | end
271 |
272 | ##
273 | # +send_ary+ is a receiver, message and arguments.
274 | #
275 | # Fails unless the call returns a true value
276 | # TODO: I should prolly remove this from specs
277 |
278 | def assert_send send_ary, m = nil
279 | recv, msg, *args = send_ary
280 | m = message(m) {
281 | "Expected #{mu_pp(recv)}.#{msg}(*#{mu_pp(args)}) to return true" }
282 | assert recv.__send__(msg, *args), m
283 | end
284 |
285 | ##
286 | # Fails if the block outputs anything to stderr or stdout.
287 | #
288 | # See also: #assert_output
289 |
290 | def assert_silent
291 | assert_output "", "" do
292 | yield
293 | end
294 | end
295 |
296 | ##
297 | # Fails unless the block throws +sym+
298 |
299 | def assert_throws sym, msg = nil
300 | default = "Expected #{mu_pp(sym)} to have been thrown"
301 | caught = true
302 | catch(sym) do
303 | begin
304 | yield
305 | rescue ArgumentError => e # 1.9 exception
306 | default += ", not #{e.message.split(' ').last}"
307 | rescue NameError => e # 1.8 exception
308 | default += ", not #{e.name.inspect}"
309 | end
310 | caught = false
311 | end
312 |
313 | assert caught, message(msg) { default }
314 | end
315 |
316 | ##
317 | # Returns a proc that will output +msg+ along with the default message.
318 |
319 | def message msg = nil, ending = ".", &default
320 | Proc.new{
321 | custom_message = "#{msg}.\n" unless msg.nil? or msg.to_s.empty?
322 | "#{custom_message}#{default.call}#{ending}"
323 | }
324 | end
325 |
326 | ##
327 | # used for counting assertions
328 |
329 | def pass msg = nil
330 | assert true
331 | end
332 |
333 | ##
334 | # Skips the current test. Gets listed at the end of the run but
335 | # doesn't cause a failure exit code.
336 |
337 | # disable backtrace for mruby
338 |
339 | def skip msg = nil
340 | msg ||= "Skipped, no message given"
341 | raise MTest::Skip, msg
342 | end
343 |
344 | ##
345 | # Returns details for exception +e+
346 |
347 | # disable backtrace for mruby
348 |
349 | def exception_details e, msg
350 | [
351 | "#{msg}",
352 | "Class: <#{e.class}>",
353 | "Message: <#{e.message.inspect}>",
354 | "---Backtrace---",
355 | "#{e.backtrace.join("\n")}",
356 | "---------------",
357 | ].join "\n"
358 | end
359 |
360 | ##
361 | # Fails with +msg+
362 |
363 | def flunk msg = nil
364 | msg ||= "Epic Fail!"
365 | assert false, msg
366 | end
367 |
368 | end
369 |
370 | class Unit
371 | attr_accessor :report, :failures, :errors, :skips
372 | attr_accessor :test_count, :assertion_count
373 | attr_accessor :start_time
374 | attr_accessor :help
375 | attr_accessor :verbose
376 | attr_writer :options
377 |
378 | def options
379 | @options ||= {}
380 | end
381 |
382 | @@out = $stdout
383 | @@runner = nil
384 |
385 | def self.output
386 | @@out
387 | end
388 |
389 | def self.output= stream
390 | @@out = stream
391 | end
392 |
393 | def self.runner= runner
394 | @@runner = runner
395 | end
396 |
397 | def self.runner
398 | @@runner = self.new unless @@runner
399 | @@runner
400 | end
401 |
402 | def output
403 | self.class.output
404 | end
405 |
406 | def puts *a
407 | output.puts(*a)
408 | end
409 |
410 | def print *a
411 | output.print(*a)
412 | end
413 |
414 | def puke klass, meth, e
415 | # dirty hack to find the actual filename and line number that the assertion failed at
416 | loc = e.backtrace.find {|l| l.include?(meth)}
417 | if loc
418 | idx = loc.rindex(':in ')
419 | loc = idx.nil? ? "#{loc}: #{e.message}" : "#{loc[0, idx]}: #{e.message} (#{e.class})"
420 | else
421 | loc = e.inspect
422 | end
423 |
424 | e = case e
425 | when MTest::Skip
426 | @skips += 1
427 | "Skipped:\n#{meth}(#{klass}) #{loc}\n"
428 | when MTest::Assertion
429 | @failures += 1
430 | "Failure:\n#{meth}(#{klass}) #{loc}\n"
431 | else
432 | @errors += 1
433 | bt = ""
434 | e.backtrace.each { |l|
435 | bt += "\t#{l}\n"
436 | break if l.include?(":in "+meth)
437 | }
438 | "Error:\n#{meth}(#{klass}): #{e.class}, #{e.message}\n#{bt}"
439 | end
440 | @report << e
441 | e[0, 1]
442 | end
443 |
444 | def initialize
445 | @report = []
446 | @errors = @failures = @skips = 0
447 | @verbose = false
448 | end
449 |
450 | ##
451 | # Runs tests and outputs minitest-style results
452 |
453 | def run args = []
454 | self.class.runner._run(args)
455 | end
456 |
457 | ##
458 | # Runs the tests and outputs mruby-test style results
459 |
460 | def mrbtest
461 | suites = TestCase.send "test_suites"
462 | return if suites.empty?
463 |
464 | results = _run_suites suites
465 |
466 | report.each_with_index do |msg, i|
467 | $asserts << "MTest #{i+1}) #{msg}"
468 | end
469 |
470 | TestCase.reset
471 | end
472 |
473 | def _run args = []
474 | $ok_test ||= 0
475 | $ko_test ||= 0
476 | $kill_test ||= 0
477 |
478 | _run_tests
479 |
480 | @test_count ||= 0
481 | @test_count > 0 ? failures + errors : nil
482 | end
483 |
484 | def _run_tests
485 | suites = TestCase.send "test_suites"
486 | return if suites.empty?
487 |
488 | start = Time.now
489 |
490 | puts
491 | puts "# Running tests:"
492 | puts
493 |
494 | results = _run_suites suites
495 |
496 | t = Time.now - start
497 |
498 | puts
499 | puts
500 | puts sprintf("Finished tests in %.6fs, %.4f tests/s, %.4f assertions/s.",
501 | t, test_count / t, assertion_count / t)
502 |
503 | report.each_with_index do |msg, i|
504 | puts sprintf("\n%3d) %s", i+1, msg)
505 | end
506 |
507 | puts
508 |
509 | status
510 | end
511 |
512 | def _run_suites suites
513 | @test_count, @assertion_count = 0, 0
514 |
515 | results = suites.map { |suite| _run_suite suite }
516 |
517 | @test_count = results.map{ |r| r[0] }.inject(0) { |sum, tc| sum + tc }
518 | @assertion_count = results.map{ |r| r[1] }.inject(0) { |sum, ac| sum + ac }
519 |
520 | $ok_test += (test_count.to_i - failures.to_i - errors.to_i - skips.to_i)
521 | $ko_test += failures.to_i
522 | $kill_test += errors.to_i
523 |
524 | return results
525 | end
526 |
527 | def _run_suite suite
528 | header = "test_suite_header"
529 | puts send(header, suite) if respond_to? header
530 |
531 | assertions = suite.send("test_methods").map do |method|
532 | inst = suite.new method
533 | inst._assertions = 0
534 |
535 | print "#{suite}##{method} = " if @verbose
536 |
537 | @start_time = Time.now
538 | result = inst.run self
539 | time = Time.now - @start_time
540 |
541 | print sprintf("%.2f s = ", time) if @verbose
542 | print result
543 | puts if @verbose
544 |
545 | inst._assertions
546 | end
547 |
548 | return assertions.size, assertions.inject(0) { |sum, n| sum + n }
549 | end
550 |
551 | def status io = self.output
552 | format = "%d tests, %d assertions, %d failures, %d errors, %d skips"
553 | io.puts sprintf(format, test_count, assertion_count, failures, errors, skips)
554 | end
555 |
556 | class TestCase
557 | attr_reader :__name__
558 |
559 | @@test_suites = {}
560 |
561 | def run runner
562 | result = ""
563 | begin
564 | @passed = nil
565 | self.setup
566 | self.run_setup_hooks
567 | self.__send__ self.__name__
568 | result = "." unless io?
569 | @passed = true
570 | rescue Exception => e
571 | @passed = false
572 | result = runner.puke self.class, self.__name__, e
573 | ensure
574 | begin
575 | self.run_teardown_hooks
576 | self.teardown
577 | rescue Exception => e
578 | result = runner.puke self.class, self.__name__, e
579 | end
580 | end
581 | result
582 | end
583 |
584 | def initialize name = self.to_s
585 | @__name__ = name
586 | @__io__ = nil
587 | @passed = nil
588 | end
589 |
590 | def io
591 | @__io__ = true
592 | MTest::Unit.output
593 | end
594 |
595 | def io?
596 | @__io__
597 | end
598 |
599 | def self.reset
600 | @@test_suites = {}
601 | end
602 |
603 | reset
604 |
605 | def self.inherited klass
606 | @@test_suites[klass] = true
607 | klass.reset_setup_teardown_hooks
608 | end
609 |
610 | def self.test_order
611 | :random
612 | end
613 |
614 | def self.test_suites
615 | hash = {}
616 | @@test_suites.keys.each{ |ts| hash[ts.to_s] = ts }
617 | hash.keys.sort.map{ |key| hash[key] }
618 | end
619 |
620 | def self.test_methods # :nodoc:
621 | methods = []
622 | self.new.methods(true).each do |m|
623 | methods << m.to_s if m.to_s.index('test') == 0
624 | end
625 |
626 | case self.test_order
627 | when :random then
628 | max = methods.size
629 | # TODO: methods.sort.sort_by { rand max }
630 | methods
631 | when :alpha, :sorted then
632 | methods.sort
633 | else
634 | raise "Unknown test_order: #{self.test_order.inspect}"
635 | end
636 | end
637 |
638 |
639 | def passed?
640 | @passed
641 | end
642 |
643 | def setup; end
644 | def teardown; end
645 | def self.reset_setup_teardown_hooks
646 | @setup_hooks = []
647 | @teardown_hooks = []
648 | end
649 | reset_setup_teardown_hooks
650 |
651 | def self.add_setup_hook arg=nil, &block
652 | hook = arg || block
653 | @setup_hooks << hook
654 | end
655 |
656 | def self.setup_hooks # :nodoc:
657 | if superclass.respond_to? :setup_hooks then
658 | superclass.setup_hooks
659 | else
660 | []
661 | end + @setup_hooks
662 | end
663 |
664 | def run_setup_hooks # :nodoc:
665 | self.class.setup_hooks.each do |hook|
666 | if hook.respond_to?(:arity) && hook.arity == 1
667 | hook.call(self)
668 | else
669 | hook.call
670 | end
671 | end
672 | end
673 |
674 | def self.add_teardown_hook arg=nil, &block
675 | hook = arg || block
676 | @teardown_hooks << hook
677 | end
678 |
679 | def self.teardown_hooks # :nodoc:
680 | if superclass.respond_to? :teardown_hooks then
681 | superclass.teardown_hooks
682 | else
683 | []
684 | end + @teardown_hooks
685 | end
686 |
687 | def run_teardown_hooks # :nodoc:
688 | self.class.teardown_hooks.reverse.each do |hook|
689 | if hook.respond_to?(:arity) && hook.arity == 1
690 | hook.call(self)
691 | else
692 | hook.call
693 | end
694 | end
695 | end
696 |
697 |
698 | include MTest::Assertions
699 | end
700 | end
701 | end
702 |
703 | if __FILE__ == $0
704 | class Test4MTest < MTest::Unit::TestCase
705 | def setup
706 | puts '*setup'
707 | end
708 |
709 | def teardown
710 | puts '*teardown'
711 | end
712 |
713 | def test_sample
714 | puts '*test_sample'
715 | assert(true, 'true sample test')
716 | assert(true)
717 | end
718 |
719 | def test_skip
720 | skip
721 | end
722 |
723 | def test_failure
724 | assert(false, 'assertion to fail')
725 | end
726 |
727 | def test_error
728 | 1 + "a"
729 | end
730 | end
731 |
732 | MTest::Unit.new.run
733 | end
734 |
--------------------------------------------------------------------------------
/run_test.rb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # mrbgems test runner
4 | #
5 |
6 | if __FILE__ == $0
7 | repository, dir = 'https://github.com/mruby/mruby.git', 'tmp/mruby'
8 | build_args = ARGV
9 | build_args = ['all', 'test'] if build_args.nil? or build_args.empty?
10 |
11 | Dir.mkdir 'tmp' unless File.exist?('tmp')
12 | unless File.exist?(dir)
13 | system "git clone #{repository} #{dir}"
14 | end
15 |
16 | exit system(%Q[cd #{dir}; MRUBY_CONFIG=#{File.expand_path __FILE__} ruby minirake #{build_args.join(' ')}])
17 | end
18 |
19 | MRuby::Build.new do |conf|
20 | toolchain :gcc
21 | conf.gembox 'default'
22 |
23 | conf.gem File.expand_path(File.dirname(__FILE__))
24 | conf.gem :core => 'mruby-time'
25 | conf.gem :github => 'iij/mruby-io'
26 | end
27 |
--------------------------------------------------------------------------------
/test/mtest_unit_test.rb:
--------------------------------------------------------------------------------
1 | ##
2 | # Test of Minimal Test framework for mruby.
3 | #
4 |
5 | if Object.const_defined?(:MTest)
6 | class Test4MTest < MTest::Unit::TestCase
7 | def test_assert
8 | assert(true)
9 | assert(true, 'true sample test')
10 | assert_true(true)
11 | assert_false(false)
12 | assert_nil(nil)
13 | end
14 |
15 | def test_assert_block
16 | assert_block('msg') do
17 | 'something-block'
18 | end
19 | end
20 |
21 | def test_assert_empty
22 | assert_empty('', 'string empty')
23 | assert_empty([], 'array empty')
24 | assert_empty({}, 'hash empty')
25 | end
26 |
27 | def test_assert_equal
28 | assert_equal('', nil.to_s)
29 | assert_not_equal('a', nil.to_s)
30 | end
31 |
32 | def test_assert_in_delta
33 | assert_in_delta(0, 0.1, 0.5)
34 | end
35 |
36 | def test_assert_include
37 | assert_include([1,2,3], 1)
38 | end
39 |
40 | def test_assert_instance_of
41 | assert_instance_of Array, []
42 | assert_instance_of Class, Array
43 | end
44 |
45 | def test_assert_kind_of
46 | assert_kind_of Array, []
47 | assert_kind_of Class, Array
48 | end
49 |
50 | def test_assert_match
51 | assert_match 'abc', 'abc'
52 | end
53 |
54 | def test_assert_raise
55 | assert_raise(RuntimeError) do
56 | raise
57 | end
58 | end
59 |
60 | def test_assert_false
61 | assert_false(false)
62 | assert_false(nil)
63 |
64 | assert_raise(MTest::Assertion) do
65 | assert_false(true)
66 | end
67 |
68 | assert_raise(MTest::Assertion) do
69 | assert_false(1)
70 | end
71 | end
72 |
73 | def test_assert_true
74 | assert_true(true)
75 | assert_true(1)
76 |
77 | assert_raise(MTest::Assertion) do
78 | assert_true(false)
79 | end
80 |
81 | assert_raise(MTest::Assertion) do
82 | assert_true(nil)
83 | end
84 | end
85 | end
86 |
87 | if $ok_test
88 | MTest::Unit.new.mrbtest
89 | else
90 | MTest::Unit.new.run
91 | end
92 | else
93 | $asserts << "test skip of mruby-mtest/test/mtest_unit_test.rb" if $asserts
94 | end
95 |
--------------------------------------------------------------------------------