├── var ├── name ├── title ├── version ├── organization ├── summary ├── authors ├── copyrights ├── repositories ├── description ├── requirements └── resources ├── demo ├── applique │ ├── ae.rb │ └── cli.rb ├── fixtures │ └── tapy.yml ├── minitest.md └── minispec.md ├── work ├── minitest4 │ ├── applique │ │ ├── ae.rb │ │ └── cli.rb │ ├── Gemfile │ ├── fixtures │ │ └── tapy.yml │ └── minitest.md └── test_example.rb ├── Gemfile ├── .yardopts ├── .gitignore ├── lib ├── minitap │ ├── autorun.rb │ ├── ignore_callers.rb │ └── minitest5.rb ├── minitap.rb └── minitest │ └── minitap_plugin.rb ├── .travis.yml ├── MANIFEST ├── Assembly ├── LICENSE.txt ├── .index ├── NOTICE.md ├── HISTORY.md ├── README.md └── .gemspec /var/name: -------------------------------------------------------------------------------- 1 | minitap -------------------------------------------------------------------------------- /var/title: -------------------------------------------------------------------------------- 1 | MiniTap -------------------------------------------------------------------------------- /var/version: -------------------------------------------------------------------------------- 1 | 0.5.3 2 | -------------------------------------------------------------------------------- /var/organization: -------------------------------------------------------------------------------- 1 | rubyworks 2 | -------------------------------------------------------------------------------- /demo/applique/ae.rb: -------------------------------------------------------------------------------- 1 | require 'ae' 2 | -------------------------------------------------------------------------------- /var/summary: -------------------------------------------------------------------------------- 1 | TAP-Y/J reporters for MiniTest -------------------------------------------------------------------------------- /work/minitest4/applique/ae.rb: -------------------------------------------------------------------------------- 1 | require 'ae' 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | gemspec 3 | -------------------------------------------------------------------------------- /var/authors: -------------------------------------------------------------------------------- 1 | --- 2 | - trans 3 | -------------------------------------------------------------------------------- /var/copyrights: -------------------------------------------------------------------------------- 1 | --- 2 | - 2011 Rubyworks (BSD-2-Clause) 3 | -------------------------------------------------------------------------------- /var/repositories: -------------------------------------------------------------------------------- 1 | --- 2 | upstream: git://github.com/rubyworks/minitap.git 3 | -------------------------------------------------------------------------------- /var/description: -------------------------------------------------------------------------------- 1 | MiniTap provides a MiniTest TAP-Y/J report format suitable for use with TAPOUT. 2 | -------------------------------------------------------------------------------- /.yardopts: -------------------------------------------------------------------------------- 1 | --title "MiniTAP" 2 | --readme README.md 3 | --protected 4 | --private 5 | lib 6 | - 7 | *.md 8 | *.txt 9 | 10 | -------------------------------------------------------------------------------- /var/requirements: -------------------------------------------------------------------------------- 1 | --- 2 | - tapout 0.3.0+ 3 | - minitest 5.0~ 4 | - minitest-reporter-api 0.0.2+ 5 | - qed (test) 6 | - ae (test) 7 | - ergo (build) 8 | 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.lock 3 | DEMO.md 4 | .ergo/digest 5 | .yardoc 6 | doc/ 7 | log/ 8 | man/**/*.1 9 | man/**/*.html 10 | pkg/ 11 | tmp/ 12 | web/ 13 | work/sandbox 14 | -------------------------------------------------------------------------------- /lib/minitap/autorun.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | require 'minitap' 3 | 4 | # Default it TapY. 5 | #Minitest.reporter = Minitest::TapJ 6 | Minitest.reporter = Minitest::TapY 7 | 8 | 9 | -------------------------------------------------------------------------------- /work/minitest4/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "minitest", "~> 4.0" 4 | 5 | group "test" do 6 | gem "tapout", ">= 0.3.0" 7 | gem "qed" 8 | gem "ae" 9 | end 10 | 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: ruby 3 | script: "bundle exec qed demo" 4 | rvm: 5 | - 1.8.7 6 | - 1.9.3 7 | - 2.0.0 8 | - rbx 9 | - rbx-19mode 10 | - jruby 11 | - jruby-19mode 12 | 13 | -------------------------------------------------------------------------------- /lib/minitap/ignore_callers.rb: -------------------------------------------------------------------------------- 1 | ignore = /(lib|bin)#{Regexp.escape(File::SEPARATOR)}minitap/ 2 | 3 | $RUBY_IGNORE_CALLERS = [] unless defined?($RUBY_IGNORE_CALLERS) 4 | $RUBY_IGNORE_CALLERS << ignore 5 | 6 | -------------------------------------------------------------------------------- /lib/minitap.rb: -------------------------------------------------------------------------------- 1 | #gem "minitest", "~> 5.0" 2 | 3 | require 'minitest' 4 | require 'minitest/reporter_api' 5 | require 'minitap/minitest5' 6 | 7 | module Minitap 8 | TapY = Minitest::TapY 9 | TapJ = Minitest::TapJ 10 | end 11 | 12 | -------------------------------------------------------------------------------- /var/resources: -------------------------------------------------------------------------------- 1 | --- 2 | home: http://rubyworks.github.com/minitap 3 | docs: http://rubydoc.info/gems/minitap 4 | code: http://github.com/rubyworks/minitap 5 | bugs: http://github.com/rubyworks/minitap/issues 6 | mail: http://groups.google.com/group/rubyworks-mailinglist 7 | 8 | -------------------------------------------------------------------------------- /MANIFEST: -------------------------------------------------------------------------------- 1 | #!mast .index .ruby .yardopts bin lib man spec test *.md *.txt 2 | .index 3 | .yardopts 4 | lib/minitap/autorun.rb 5 | lib/minitap/ignore_callers.rb 6 | lib/minitap/minitest5.rb 7 | lib/minitap.rb 8 | lib/minitest/minitap_plugin.rb 9 | NOTICE.md 10 | README.md 11 | HISTORY.md 12 | DEMO.md 13 | LICENSE.txt 14 | -------------------------------------------------------------------------------- /Assembly: -------------------------------------------------------------------------------- 1 | --- 2 | gem: 3 | active : true 4 | 5 | github: 6 | gh_pages: web 7 | 8 | qed: 9 | files: demo 10 | 11 | qedoc: 12 | files: demo 13 | title: MiniTAP Demonstrandum 14 | output: QED.md 15 | 16 | dnote: 17 | title: Developer's Notes 18 | labels: ~ 19 | output: log/notes.html 20 | active: true 21 | 22 | vclog: 23 | output: 24 | - log/changes.html 25 | - log/history.html 26 | 27 | email: 28 | mailto: 29 | - ruby-talk@ruby-lang.org 30 | - rubyworks-mailinglist@googlegroups.com 31 | 32 | -------------------------------------------------------------------------------- /work/test_example.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | 3 | #require 'minitap' 4 | #MiniTest::Unit.runner = MiniTest::TapJ.new 5 | 6 | #require "minitest/reporters" 7 | #MiniTest::Reporters.use! MiniTest::Reporters::SpecReporter.new 8 | 9 | #require 'active_support/core_ext' # why do i have to require this? 10 | 11 | class TestThis < Minitest::Test 12 | 13 | def method1 14 | puts "this will break tapout because of malformed output" 15 | true 16 | end 17 | 18 | def method2 19 | puts "this will also break tapout because of malformed output" 20 | true 21 | end 22 | 23 | def test_broken1 24 | assert method1 25 | end 26 | 27 | def test_broken2 28 | assert method2 29 | end 30 | 31 | def test_fine 32 | assert true 33 | end 34 | 35 | def test_not_fine 36 | assert false 37 | end 38 | 39 | end 40 | -------------------------------------------------------------------------------- /work/minitest4/applique/cli.rb: -------------------------------------------------------------------------------- 1 | require 'tapout' 2 | 3 | When 'Given a MiniTest testcase' do |text| 4 | @test = text 5 | end 6 | 7 | When 'Running it with the (((.*?))) format' do |type| 8 | File.open('test.rb', 'w'){ |f| 9 | f << test_helper(type) + "\n\n" + @test 10 | } 11 | 12 | @out = `ruby -I../../lib test.rb` 13 | 14 | #@stream = YAML.load_documents(@out) # b/c of bug in Ruby 1.8 15 | @stream = ( 16 | s = [] 17 | YAML.load_documents(@out){ |d| s << d } 18 | s 19 | ) 20 | end 21 | 22 | #When '(((\w+))) reporter should run without error' do |format| 23 | # $stdin = StringIO.new(@tapy) 24 | # $stdout = StringIO.new(out = '') 25 | # 26 | # TapOut.cli(format) 27 | #end 28 | 29 | def test_helper(type) 30 | if type == 'TAP-Y' then 31 | %Q{ 32 | require 'minitap' 33 | MiniTest::Unit.runner = MiniTest::TapY.new 34 | require 'minitest/autorun' 35 | } 36 | else 37 | %Q{ 38 | require 'minitap' 39 | MiniTest::Unit.runner = MiniTest::TapJ.new 40 | require 'minitest/autorun' 41 | } 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /lib/minitest/minitap_plugin.rb: -------------------------------------------------------------------------------- 1 | module Minitest 2 | 3 | # 4 | def self.plugin_minitap_options(opts, options) 5 | opts.on "--tapy", "Use TapY reporter." do 6 | options[:minitap] = 'tapy' 7 | end 8 | 9 | opts.on "--tapj", "Use TapJ reporter." do 10 | options[:minitap] = 'tapj' 11 | end 12 | 13 | # DEPRECATED Thanks to minitest-reporter-api gem. 14 | #unless options[:minitap] 15 | # if defined?(Minitest::TapY) && self.reporter == Minitest::TapY 16 | # options[:minitap] = 'tapy' 17 | # elsif defined?(Minitest::TapJ) && self.reporter == Minitest::TapJ 18 | # options[:minitap] = 'tapj' 19 | # end 20 | #end 21 | end 22 | 23 | # 24 | def self.plugin_minitap_init(options) 25 | if options[:minitap] 26 | require 'minitap/minitest5' 27 | 28 | self.reporter.reporters.clear 29 | 30 | case options[:minitap] || ENV['rpt'] 31 | when 'tapj' 32 | self.reporter << TapJ.new(options) 33 | when 'tapy' 34 | self.reporter << TapY.new(options) 35 | end 36 | end 37 | end 38 | 39 | end 40 | 41 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | BSD-2-Clause License 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 14 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 15 | AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 16 | COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 17 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 20 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 22 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | -------------------------------------------------------------------------------- /.index: -------------------------------------------------------------------------------- 1 | --- 2 | revision: 2013 3 | type: ruby 4 | sources: 5 | - var 6 | authors: 7 | - name: trans 8 | email: transfire@gmail.com 9 | organizations: [] 10 | requirements: 11 | - version: 0.3.0+ 12 | name: tapout 13 | - version: 5.0~ 14 | name: minitest 15 | - version: 0.0.2+ 16 | name: minitest-reporter-api 17 | - groups: 18 | - test 19 | development: true 20 | name: qed 21 | - groups: 22 | - test 23 | development: true 24 | name: ae 25 | - groups: 26 | - build 27 | development: true 28 | name: ergo 29 | conflicts: [] 30 | alternatives: [] 31 | resources: 32 | - type: home 33 | uri: http://rubyworks.github.com/minitap 34 | label: Homepage 35 | - type: docs 36 | uri: http://rubydoc.info/gems/minitap 37 | label: Documentation 38 | - type: code 39 | uri: http://github.com/rubyworks/minitap 40 | label: Source Code 41 | - type: bugs 42 | uri: http://github.com/rubyworks/minitap/issues 43 | label: Issue Tracker 44 | - type: mail 45 | uri: http://groups.google.com/group/rubyworks-mailinglist 46 | label: Mailing List 47 | repositories: 48 | - name: upstream 49 | scm: git 50 | uri: git://github.com/rubyworks/minitap.git 51 | categories: [] 52 | copyrights: 53 | - holder: Rubyworks 54 | year: '2011' 55 | license: BSD-2-Clause 56 | customs: [] 57 | paths: 58 | lib: 59 | - lib 60 | name: minitap 61 | title: MiniTap 62 | summary: TAP-Y/J reporters for MiniTest 63 | description: MiniTap provides a MiniTest TAP-Y/J report format suitable for use with 64 | TAPOUT. 65 | version: 0.5.3 66 | date: '2013-11-20' 67 | -------------------------------------------------------------------------------- /demo/applique/cli.rb: -------------------------------------------------------------------------------- 1 | require 'tapout' 2 | 3 | When 'Given a Minitest (((Test|Spec)))' do |type, text| 4 | @test = text 5 | end 6 | 7 | When 'Running it with the (((.*?))) format' do |type| 8 | File.open('test.rb', 'w') { |f| 9 | f << "\n" + test_helper(type) + "\n\n" + @test 10 | } 11 | 12 | @out = test_command(type) 13 | 14 | #@stream = YAML.load_documents(@out) # b/c of bug in Ruby 1.8 15 | @stream = ( 16 | s = [] 17 | YAML.load_documents(@out){ |d| s << d } 18 | s 19 | ) 20 | end 21 | 22 | #When '(((\w+))) reporter should run without error' do |format| 23 | # $stdin = StringIO.new(@tapy) 24 | # $stdout = StringIO.new(out = '') 25 | # 26 | # TapOut.cli(format) 27 | #end 28 | 29 | def test_command(type) 30 | #return test_command_4 if ENV['minitest'] == "4" 31 | 32 | if type == 'TAP-Y' 33 | `ruby -I../../lib test.rb - --tapy` 34 | else 35 | `ruby -I../../lib test.rb - --tapj` 36 | end 37 | end 38 | 39 | # TODO: Is there a way to offer option to select the format via code? 40 | def test_helper(type) 41 | #return test_helper_4(type) if ENV['minitest'] == "4" 42 | 43 | "require 'minitest/autorun'" 44 | end 45 | 46 | =begin 47 | def test_command_4 48 | `ruby -I../../lib test.rb` 49 | end 50 | 51 | # For Minitest v4. 52 | def test_helper_4(type) 53 | if type == 'TAP-Y' then 54 | %Q{ 55 | require 'minitap' 56 | MiniTest::Unit.runner = MiniTest::TapY.new 57 | require 'minitest/autorun' 58 | } 59 | else 60 | %Q{ 61 | require 'minitap' 62 | MiniTest::Unit.runner = MiniTest::TapJ.new 63 | require 'minitest/autorun' 64 | } 65 | end 66 | end 67 | =end 68 | -------------------------------------------------------------------------------- /demo/fixtures/tapy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | type: suite 3 | start: '2011-10-06 18:48:08' 4 | count: 3 5 | seed: 36440 6 | rev: 2 7 | --- 8 | type: case 9 | subtype: '' 10 | label: ExampleTestCase 11 | level: 0 12 | --- 13 | type: test 14 | subtype: '' 15 | status: error 16 | label: test_error 17 | exception: 18 | message: ! 'RuntimeError:' 19 | file: example.rb 20 | line: 10 21 | snippet: 22 | - 8: '' 23 | - 9: ! ' def test_error' 24 | - 10: ! ' raise' 25 | - 11: ! ' end' 26 | - 12: '' 27 | backtrace: 28 | - example.rb:10 29 | time: 0.001054606 30 | --- 31 | type: test 32 | subtype: '' 33 | status: fail 34 | label: test_failing 35 | exception: 36 | message: ! "Expected: \"1\"\n Actual: \"2\"" 37 | file: example.rb 38 | line: 14 39 | snippet: 40 | - 12: '' 41 | - 13: ! ' def test_failing' 42 | - 14: ! ' assert_equal(''1'', ''2'')' 43 | - 15: ! ' end' 44 | - 16: '' 45 | backtrace: 46 | - example.rb:14 47 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:456 48 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:103 49 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:88 50 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:88 51 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:88 52 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:73 53 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:73 54 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:73 55 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:146 56 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:72 57 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:48 58 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:47 59 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:47 60 | time: 0.046170916 61 | --- 62 | type: test 63 | subtype: '' 64 | status: pass 65 | label: test_passing 66 | time: 1.04997403 67 | --- 68 | type: tally 69 | time: 1.000800203 70 | counts: 71 | total: 3 72 | pass: 1 73 | fail: 1 74 | error: 1 75 | omit: 0 76 | todo: 0 77 | ... 78 | 79 | -------------------------------------------------------------------------------- /work/minitest4/fixtures/tapy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | type: suite 3 | start: '2011-10-06 18:48:08' 4 | count: 3 5 | seed: 36440 6 | rev: 2 7 | --- 8 | type: case 9 | subtype: '' 10 | label: ExampleTestCase 11 | level: 0 12 | --- 13 | type: test 14 | subtype: '' 15 | status: error 16 | label: test_error 17 | exception: 18 | message: ! 'RuntimeError:' 19 | file: example.rb 20 | line: 10 21 | snippet: 22 | - 8: '' 23 | - 9: ! ' def test_error' 24 | - 10: ! ' raise' 25 | - 11: ! ' end' 26 | - 12: '' 27 | backtrace: 28 | - example.rb:10 29 | time: 0.001054606 30 | --- 31 | type: test 32 | subtype: '' 33 | status: fail 34 | label: test_failing 35 | exception: 36 | message: ! "Expected: \"1\"\n Actual: \"2\"" 37 | file: example.rb 38 | line: 14 39 | snippet: 40 | - 12: '' 41 | - 13: ! ' def test_failing' 42 | - 14: ! ' assert_equal(''1'', ''2'')' 43 | - 15: ! ' end' 44 | - 16: '' 45 | backtrace: 46 | - example.rb:14 47 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:456 48 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:103 49 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:88 50 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:88 51 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:88 52 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:73 53 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:73 54 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:73 55 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:146 56 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:72 57 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:48 58 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:47 59 | - /home/trans/com/programs/rubyworks/minitap/lib/minitap.rb:47 60 | time: 0.046170916 61 | --- 62 | type: test 63 | subtype: '' 64 | status: pass 65 | label: test_passing 66 | time: 1.04997403 67 | --- 68 | type: tally 69 | time: 1.000800203 70 | counts: 71 | total: 3 72 | pass: 1 73 | fail: 1 74 | error: 1 75 | omit: 0 76 | todo: 0 77 | ... 78 | 79 | -------------------------------------------------------------------------------- /NOTICE.md: -------------------------------------------------------------------------------- 1 | # COPYRIGHT NOTICES 2 | 3 | MiniTap (http://rubyworks.github.com/tapout) 4 | 5 | Copyright (c) 2011 Rubyworks 6 | 7 | BSD-2-Clause License 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | 12 | 1. Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 15 | 2. Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 20 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 21 | AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 22 | COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 26 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 28 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | -------------------------------------------------------------------------------- 31 | 32 | Minitest Reporters (https://github.com/CapnKernul/minitest-reporters) 33 | 34 | Copyright (c) 2011 Alexander Kern 35 | 36 | MIT License 37 | 38 | Permission is hereby granted, free of charge, to any person obtaining 39 | a copy of this software and associated documentation files (the 40 | "Software"), to deal in the Software without restriction, including 41 | without limitation the rights to use, copy, modify, merge, publish, 42 | distribute, sublicense, and/or sell copies of the Software, and to 43 | permit persons to whom the Software is furnished to do so, subject to 44 | the following conditions: 45 | 46 | The above copyright notice and this permission notice shall be 47 | included in all copies or substantial portions of the Software. 48 | 49 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 50 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 51 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 52 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 53 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 54 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 55 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 56 | 57 | -------------------------------------------------------------------------------- /demo/minitest.md: -------------------------------------------------------------------------------- 1 | # Minitap 2 | 3 | Given a Minitest Test: 4 | 5 | class ExampleTestCase < Minitest::Test 6 | def test_error 7 | raise 8 | end 9 | 10 | def test_failing 11 | assert_equal('1', '2') 12 | end 13 | 14 | def test_passing 15 | sleep 1 16 | assert_equal('1', '1') 17 | end 18 | end 19 | 20 | Running it with the TAP-Y format should work without error. 21 | 22 | The resulting document stream should exhibit the following 23 | characteristics. 24 | 25 | There should be six sections. 26 | 27 | @stream.size #=> 6 28 | 29 | The first should be a `suite` with a count of `3`. 30 | 31 | @stream.first['type'] #=> 'suite' 32 | @stream.first['count'] #=> 3 33 | 34 | The second should be `case` entry. 35 | 36 | @stream[1]['type'] #=> 'case' 37 | @stream[1]['label'] #=> 'ExampleTestCase' 38 | @stream[1]['level'] #=> 0 39 | 40 | The next three documents are the unit tests, which can occur in any order. 41 | There's one that should have a status of `pass`, another of `fail` and the 42 | third of `error`. 43 | 44 | passing_test = @stream.find{ |d| d['type'] == 'test' && d['status'] == 'pass' } 45 | failing_test = @stream.find{ |d| d['type'] == 'test' && d['status'] == 'fail' } 46 | erring_test = @stream.find{ |d| d['type'] == 'test' && d['status'] == 'error' } 47 | 48 | The passing test should have the following charactersitics. 49 | 50 | passing_test['label'] #=> 'test_passing' 51 | 52 | The failing test should 53 | 54 | failing_test['label'] #=> "test_failing" 55 | failing_test['exception']['class'] #=> "Minitest::Assertion" 56 | failing_test['exception']['file'] #=> "test.rb" 57 | failing_test['exception']['line'] #=> 10 58 | failing_test['exception']['source'] #=> "assert_equal('1', '2')" 59 | 60 | The failing test should also not have any mention of minitap in the 61 | backtrace. 62 | 63 | failing_test['exception']['backtrace'].each do |e| 64 | /minitap/.refute.match(e) 65 | end 66 | 67 | The erring test should 68 | 69 | erring_test['label'] #=> 'test_error' 70 | erring_test['exception']['class'] #=> 'RuntimeError' 71 | erring_test['exception']['file'] #=> 'test.rb' 72 | erring_test['exception']['line'] #=> 6 73 | erring_test['exception']['source'] #=> 'raise' 74 | 75 | The erring test should also not have any mention of minitap in the 76 | backtrace. 77 | 78 | erring_test['exception']['backtrace'].each do |e| 79 | /minitap/.refute.match(e) 80 | end 81 | 82 | The last should a `final` document. 83 | 84 | @stream.last['type'] #=> 'final' 85 | 86 | And it should have the following counts. 87 | 88 | @stream.last['counts']['total'] #=> 3 89 | @stream.last['counts']['error'] #=> 1 90 | @stream.last['counts']['fail'] #=> 1 91 | @stream.last['counts']['pass'] #=> 1 92 | @stream.last['counts']['omit'] #=> 0 93 | @stream.last['counts']['todo'] #=> 0 94 | 95 | -------------------------------------------------------------------------------- /work/minitest4/minitest.md: -------------------------------------------------------------------------------- 1 | # Minitap 2 | 3 | Given a Minitest testcase: 4 | 5 | class ExampleTestCase < MiniTest::Unit::TestCase 6 | def test_error 7 | raise 8 | end 9 | 10 | def test_failing 11 | assert_equal('1', '2') 12 | end 13 | 14 | def test_passing 15 | sleep 1 16 | assert_equal('1', '1') 17 | end 18 | end 19 | 20 | Running it with the TAP-Y format should work without error. 21 | 22 | The resulting document stream should exhibit the following 23 | characteristics. 24 | 25 | There should be six sections. 26 | 27 | @stream.size #=> 6 28 | 29 | The first should be a `suite` with a count of `3`. 30 | 31 | @stream.first['type'] #=> 'suite' 32 | @stream.first['count'] #=> 3 33 | 34 | The second should be `case` entry. 35 | 36 | @stream[1]['type'] #=> 'case' 37 | @stream[1]['label'] #=> 'ExampleTestCase' 38 | @stream[1]['level'] #=> 0 39 | 40 | The next three documents are the unit tests, which can occur in any order. 41 | There's one that should have a status of `pass`, another of `fail` and the 42 | third of `error`. 43 | 44 | passing_test = @stream.find{ |d| d['type'] == 'test' && d['status'] == 'pass' } 45 | failing_test = @stream.find{ |d| d['type'] == 'test' && d['status'] == 'fail' } 46 | erring_test = @stream.find{ |d| d['type'] == 'test' && d['status'] == 'error' } 47 | 48 | The passing test should have the following charactersitics. 49 | 50 | passing_test['label'] #=> 'test_passing' 51 | 52 | The failing test should 53 | 54 | failing_test['label'] #=> "test_failing" 55 | failing_test['exception']['class'] #=> "MiniTest::Assertion" 56 | failing_test['exception']['file'] #=> "test.rb" 57 | failing_test['exception']['line'] #=> 13 58 | failing_test['exception']['source'] #=> "assert_equal('1', '2')" 59 | 60 | The failing test should also not have any mention of minitap in the 61 | backtrace. 62 | 63 | failing_test['exception']['backtrace'].each do |e| 64 | /minitap/.refute.match(e) 65 | end 66 | 67 | The erring test should 68 | 69 | erring_test['label'] #=> 'test_error' 70 | erring_test['exception']['class'] #=> 'RuntimeError' 71 | erring_test['exception']['file'] #=> 'test.rb' 72 | erring_test['exception']['line'] #=> 9 73 | erring_test['exception']['source'] #=> 'raise' 74 | 75 | The erring test should also not have any mention of minitap in the 76 | backtrace. 77 | 78 | erring_test['exception']['backtrace'].each do |e| 79 | /minitap/.refute.match(e) 80 | end 81 | 82 | The last should a `final` document. 83 | 84 | @stream.last['type'] #=> 'final' 85 | 86 | And it should have the following counts. 87 | 88 | @stream.last['counts']['total'] #=> 3 89 | @stream.last['counts']['error'] #=> 1 90 | @stream.last['counts']['fail'] #=> 1 91 | @stream.last['counts']['pass'] #=> 1 92 | @stream.last['counts']['omit'] #=> 0 93 | @stream.last['counts']['todo'] #=> 0 94 | 95 | -------------------------------------------------------------------------------- /demo/minispec.md: -------------------------------------------------------------------------------- 1 | # Minitap 2 | 3 | Given a Minitest Spec: 4 | 5 | require 'minitest/spec' 6 | 7 | describe "Example Case" do 8 | it "should error" do 9 | raise 10 | end 11 | 12 | it "should fail" do 13 | assert_equal('1', '2') 14 | end 15 | 16 | it "should pass" do 17 | sleep 1 18 | assert_equal('1', '1') 19 | end 20 | end 21 | 22 | Running it with the TAP-Y format should work without error. 23 | 24 | The resulting document stream should exhibit the following 25 | characteristics. 26 | 27 | There should be six sections. 28 | 29 | @stream.size #=> 6 30 | 31 | The first should be a `suite` with a count of `3`. 32 | 33 | @stream.first['type'] #=> 'suite' 34 | @stream.first['count'] #=> 3 35 | 36 | The second should be `case` entry. 37 | 38 | @stream[1]['type'] #=> 'case' 39 | @stream[1]['label'] #=> 'Example Case' 40 | @stream[1]['level'] #=> 0 41 | 42 | The next three documents are the unit tests, which can occur in any order. 43 | There's one that should have a status of `pass`, another of `fail` and the 44 | third of `error`. 45 | 46 | passing_test = @stream.find{ |d| d['type'] == 'test' && d['status'] == 'pass' } 47 | failing_test = @stream.find{ |d| d['type'] == 'test' && d['status'] == 'fail' } 48 | erring_test = @stream.find{ |d| d['type'] == 'test' && d['status'] == 'error' } 49 | 50 | The passing test should have the following charactersitics. 51 | 52 | passing_test['label'] #=> 'should pass' 53 | 54 | The failing test should 55 | 56 | failing_test['label'] #=> "should fail" 57 | failing_test['exception']['class'] #=> "Minitest::Assertion" 58 | failing_test['exception']['file'] #=> "test.rb" 59 | failing_test['exception']['line'] #=> 12 60 | failing_test['exception']['source'] #=> "assert_equal('1', '2')" 61 | 62 | The failing test should also not have any mention of minitap in the 63 | backtrace. 64 | 65 | failing_test['exception']['backtrace'].each do |e| 66 | /minitap/.refute.match(e) 67 | end 68 | 69 | The erring test should 70 | 71 | erring_test['label'] #=> 'should error' 72 | erring_test['exception']['class'] #=> 'RuntimeError' 73 | erring_test['exception']['file'] #=> 'test.rb' 74 | erring_test['exception']['line'] #=> 8 75 | erring_test['exception']['source'] #=> 'raise' 76 | 77 | The erring test should also not have any mention of minitap in the 78 | backtrace. 79 | 80 | erring_test['exception']['backtrace'].each do |e| 81 | /minitap/.refute.match(e) 82 | end 83 | 84 | The last should a `final` document. 85 | 86 | @stream.last['type'] #=> 'final' 87 | 88 | And it should have the following counts. 89 | 90 | @stream.last['counts']['total'] #=> 3 91 | @stream.last['counts']['error'] #=> 1 92 | @stream.last['counts']['fail'] #=> 1 93 | @stream.last['counts']['pass'] #=> 1 94 | @stream.last['counts']['omit'] #=> 0 95 | @stream.last['counts']['todo'] #=> 0 96 | 97 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | # RELEASE HISTORY 2 | 3 | ## 0.5.3 | 2013-11-20 4 | 5 | Small change made to ensure that output i/o is un sync mode. 6 | This prevents test results fro being buffered over the pipe 7 | 8 | Changes: 9 | 10 | * Add `io.sync = true` *after* Minitest reporter class is initialized. 11 | * Add notes to README about use tapout's pause and resume feature. 12 | 13 | 14 | ## 0.5.2 | 2013-11-18 15 | 16 | This release makes it possible to specify reporters in code 17 | (again), and not just on the command line. This makes it easier 18 | to use with other test and build tools such as Rake. 19 | 20 | Changes: 21 | 22 | * Add support for in code configuration of reporter. 23 | * Use minitest-reporter-api gem to support in code reporter config. 24 | 25 | 26 | ## 0.5.1 | 2013-11-16 27 | 28 | This release simply removes all the remaing v4 code that 29 | is no longer needed to work with Minitest 5. This also 30 | fixes an issue Minitap has with working with Rails 4. 31 | 32 | Changes: 33 | 34 | * Remove all vestigial v4 code. 35 | 36 | 37 | ## 0.5.0 | 2013-11-15 38 | 39 | The release adds support for MiniTest 5. Minitest completely 40 | changes the way custom reporters are handled so this release 41 | includes extensive new code. Note that this version is also 42 | no longer intended for use with Minitest 4 or older. If you 43 | are using Minitest 4, please use Minitap 0.4.x as well. 44 | 45 | Changes: 46 | 47 | * Add support for Minitest 5. 48 | * Deprecate support for Minitest 4. 49 | 50 | 51 | ## 0.4.1 | 2013-03-18 52 | 53 | Minor release improves upon backtrace filtering and makes 54 | the hook extensions more robust when non-minitap runners 55 | are used even though minitap has been requried. 56 | 57 | Changes: 58 | 59 | * Use $RUBY_IGNORE_CALLERS for backtrace filtering. 60 | * Ensure hook methods exist before using them. 61 | 62 | 63 | ## 0.4.0 | 2013-03-17 64 | 65 | MiniTap v0.4.0 is a heavy refactorization of the code based on 66 | Alexander Kern's latest MiniTest-Reporters code. (Thank you 67 | Mr. Kern! You made dealing with sorry Minitest code at least 68 | tolerable.) This release also owes gratitiude to Kevin Swope 69 | who's bug report about running on MiniTap with Rails led to 70 | the whole shebang. 71 | 72 | Changes: 73 | 74 | * Refactored runner to "catch-up" with the ever changing 75 | crap that is MiniTest's code. 76 | 77 | 78 | ## 0.3.5 | 2013-01-17 79 | 80 | This release adds a #record method to the TestRunner to accomodate 81 | recent changes to MiniTest. 82 | 83 | Changes: 84 | 85 | * Add TestRunner#record method. 86 | 87 | 88 | ## 0.3.4 | 2012-05-01 89 | 90 | This release simply fixes a misspelling that caused an error 91 | when a test was skipped. 92 | 93 | Changes: 94 | 95 | * Fix misspelling of the word 'exception'. (#2 Corey O'Connor) 96 | 97 | 98 | ## 0.3.3 | 2012-02-01 99 | 100 | This release adds support for the new 'stdout' and 'stderr' fields. 101 | As tests are run $stdout and $stderr are captured and included in 102 | the TAP-Y/J stream. This prevents the structured streams from being 103 | corrupted and provide some nice report options too. 104 | 105 | Changes: 106 | 107 | * Add support for stdout and stderr capturing. 108 | 109 | 110 | ## 0.3.2 | 2011-11-08 111 | 112 | This release add support for the new TAP-Y/J 'class' field, and removes 113 | the class name from the message field. It also fixes a bug that 114 | arose with certain versions of Ruby's YAML.load_documents implementation. 115 | 116 | Changes: 117 | 118 | * Work around Ruby's YAML.load_documents issue. 119 | * Add dependency for MiniTest. 120 | * Support TAP-Y/J class field. 121 | * Remove class name from message field. 122 | 123 | 124 | ## 0.3.1 | 2011-10-18 125 | 126 | This release includes two basic improvements: better backtrace filtering, 127 | and file fields given relative to current working directory instead of 128 | absolute paths. In future maybe this can be configurable, if someone makes 129 | the case that absolute paths are needed. 130 | 131 | Changes: 132 | 133 | * Improve backtrace filtering. 134 | * Make file fields relative to working directory. 135 | 136 | 137 | ## 0.3.0 | 2011-10-09 138 | 139 | Support version 3 of TAP-Y/J spec. This simply entailed renaming 140 | the `tally` document to `final`. 141 | 142 | Changes: 143 | 144 | * Support revision 3 of TAP-Y/J. 145 | 146 | 147 | ## 0.2.0 | 2011-10-07 148 | 149 | This release adjusts how the customer reporter classes 150 | should be used. It's actually a very minor release under 151 | the hood. 152 | 153 | Changes: 154 | 155 | * Adjust usage documentation. 156 | 157 | 158 | ## 0.1.0 | 2011-10-06 159 | 160 | This is the first release of MiniTap, a TAP-Y/J reporter 161 | for the MiniTest test framework. 162 | 163 | Changes: 164 | 165 | * First Release Day! 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Minitap 2 | 3 | [Website](http://rubyworks.github.com/minitap) | 4 | [Documentation](http://rubydoc.info/gems/minitap/frames) | 5 | [Report Issue](http://github.com/rubyworks/minitap/issues) | 6 | [Source Code](http://github.com/rubyworks/minitap) 7 | 8 | [![Build Status](https://travis-ci.org/rubyworks/minitap.png)](https://travis-ci.org/rubyworks/minitap) 9 | [![Gem Version](https://badge.fury.io/rb/minitap.png)](http://badge.fury.io/rb/minitap)     10 | [![Flattr Me](http://api.flattr.com/button/flattr-badge-large.png)](http://flattr.com/thing/324911/Rubyworks-Ruby-Development-Fund) 11 | 12 | 13 | # About 14 | 15 | The MiniTap project provides a TAP-Y and TAP-J output reporters for 16 | the MiniTest test framework --the test framework that comes standard 17 | with Ruby 1.9+. 18 | 19 | See [TAPOUT](http://rubyworks.github.com/tapout) for more information about 20 | TAP-Y/J formats. 21 | 22 | 23 | # Usage 24 | 25 | ## Minitest 5 26 | 27 | Minitest 5 has a new report system and plug-in API. Minitap takes advantage 28 | of this new API to allow the TAP-Y or TAP-J formats to be selected via command-line 29 | options as an alternative to setting the format in test helper scripts. 30 | 31 | ### Via Command Line 32 | 33 | To use simply add `--tapy` or `--tapj` after an isolated `-` separator on the 34 | ruby test command invocation, e.g. 35 | 36 | $ ruby -Ilib test/runner.rb - --tapy 37 | 38 | In your test helper scripts be sure you have the standard Minitest line: 39 | 40 | require 'minitest/autorun' 41 | 42 | And remove any old `MiniTest::Unit.runner=` assignments if you are migrating 43 | from v4. 44 | 45 | Now to do something interesting with the TAP-Y/J output, you will probably want 46 | to install `tapout`: 47 | 48 | $ gem install tapout 49 | 50 | Then pipe the output to the `tapout` command, e.g. 51 | 52 | $ ruby test/some_test.rb - --tapy | tapout progressbar 53 | 54 | ### Via Helper Script 55 | 56 | To use via test helper script, require the `minitap` library after `minitest/autorun` 57 | and assign `Minitest.reporter` to the Minitap reporter to be used. 58 | 59 | require "minitest/autorun" 60 | require "minitap" 61 | 62 | Minitest.reporter = Minitap::TapY 63 | 64 | Then pipe the output to the `tapout` command, e.g. 65 | 66 | $ ruby -Ilib test/runner.rb | tapout progrssbar 67 | 68 | Or using Rake: 69 | 70 | $ rake test | tapout progressbar 71 | 72 | You may need the `-q` option for Rake to supress extraneous output. 73 | 74 | 75 | ## MiniTest 4 76 | 77 | If you are still using MiniTest 4.x you will need to use Minitap version 4.x 78 | as well. In your dependencies be sure to specify this version. For example in 79 | your Gemfile: 80 | 81 | gem "minitap", "~> 0.4.0" 82 | 83 | For Minitest 4 and and older, custom report formats are set by assigning 84 | the `MiniTest::Unit.runner` to an instance of a custom runner class. 85 | In our case we want to set it to an instance of `MiniTest::TapY` or `MiniTest::TapJ`. 86 | So in your project's test helper script add, e.g. 87 | 88 | require 'minitap' 89 | MiniTest::Unit.runner = MiniTest::TapY.new 90 | 91 | Now you may want to set this up so it is selectable. In which case use an 92 | environment variable. 93 | 94 | MiniTest::Unit.runner = \ 95 | case ENV['rpt'] 96 | when 'tapy' 97 | MiniTest::TapY.new 98 | when 'tapj' 99 | MiniTest::TapJ.new 100 | end 101 | 102 | Then you can do, e.g. 103 | 104 | $ rpt=tapy ruby test/some_test.rb 105 | 106 | Now to do something interesting with the TAP-Y/J output, you will probably want 107 | to install `tapout`: 108 | 109 | $ gem install tapout 110 | 111 | Then pipe the output to the `tapout` command, e.g. 112 | 113 | $ rpt=tapy ruby test/some_test.rb | tapout progressbar 114 | 115 | 116 | # Using Pry & Other Tools 117 | 118 | Becuase Tapout communicates with Minitest via a shell pipe it is improtant 119 | to keep in mind that any non TAP-Y/J output that tapout receives might 120 | force it to halt. To ensure this doesn't occur a *pause code* (`16.chr`) can 121 | be sent over the pipe to instruct the tapout comamnd to stop processing test 122 | results and route `$stdin` directly to `$stdout` instead. A *resume code* 123 | (`23.chr`) can be sent to restart test result processing. 124 | 125 | A good example of this is when using `binding.pry` for debugging. To do so 126 | while using tapout: 127 | 128 | require 'tapout/utility' 129 | tapout.pause{ binding.pry } 130 | 131 | Or, even more convenient, specifically for use with pry: 132 | 133 | require 'tapout/utility' 134 | tapout.pry(binding) 135 | 136 | Which is a more covenient way of coding: 137 | 138 | STDOUT.puts 16.chr 139 | binding.pry 140 | STDOUT.puts 23.chr 141 | 142 | 143 | # Copying 144 | 145 | Copyright (c) 2011 Rubyworks 146 | 147 | Made available under the terms of the *BSD-2-Clause* license. 148 | 149 | Portions of this program were drawn from Alexander Kern's 150 | MiniTest Reporter (c) 2011 Alexander Kern. Thanks Alexander 151 | for making my endeavor a little bit easier. 152 | 153 | See COPYING.rdoc for copyright and licensing details. 154 | 155 | -------------------------------------------------------------------------------- /.gemspec: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'yaml' 4 | require 'pathname' 5 | 6 | module Indexer 7 | 8 | # Convert index data into a gemspec. 9 | # 10 | # Notes: 11 | # * Assumes all executables are in bin/. 12 | # * Does not yet handle default_executable setting. 13 | # * Does not yet handle platform setting. 14 | # * Does not yet handle required_ruby_version. 15 | # * Support for rdoc entries is weak. 16 | # 17 | class GemspecExporter 18 | 19 | # File globs to include in package --unless a manifest file exists. 20 | FILES = ".index .yardopts alt bin data demo ext features lib man spec test try* [A-Z]*.*" unless defined?(FILES) 21 | 22 | # File globs to omit from FILES. 23 | OMIT = "Config.rb" unless defined?(OMIT) 24 | 25 | # Standard file patterns. 26 | PATTERNS = { 27 | :root => '{.index,Gemfile}', 28 | :bin => 'bin/*', 29 | :lib => 'lib/{**/}*', #.rb', 30 | :ext => 'ext/{**/}extconf.rb', 31 | :doc => '*.{txt,rdoc,md,markdown,tt,textile}', 32 | :test => '{test,spec}/{**/}*.rb' 33 | } unless defined?(PATTERNS) 34 | 35 | # For which revision of indexer spec is this converter intended? 36 | REVISION = 2013 unless defined?(REVISION) 37 | 38 | # 39 | def self.gemspec 40 | new.to_gemspec 41 | end 42 | 43 | # 44 | attr :metadata 45 | 46 | # 47 | def initialize(metadata=nil) 48 | @root_check = false 49 | 50 | if metadata 51 | root_dir = metadata.delete(:root) 52 | if root_dir 53 | @root = root_dir 54 | @root_check = true 55 | end 56 | metadata = nil if metadata.empty? 57 | end 58 | 59 | @metadata = metadata || YAML.load_file(root + '.index') 60 | 61 | if @metadata['revision'].to_i != REVISION 62 | warn "This gemspec exporter was not designed for this revision of index metadata." 63 | end 64 | end 65 | 66 | # 67 | def has_root? 68 | root ? true : false 69 | end 70 | 71 | # 72 | def root 73 | return @root if @root || @root_check 74 | @root_check = true 75 | @root = find_root 76 | end 77 | 78 | # 79 | def manifest 80 | return nil unless root 81 | @manifest ||= Dir.glob(root + 'manifest{,.txt}', File::FNM_CASEFOLD).first 82 | end 83 | 84 | # 85 | def scm 86 | return nil unless root 87 | @scm ||= %w{git hg}.find{ |m| (root + ".#{m}").directory? }.to_sym 88 | end 89 | 90 | # 91 | def files 92 | return [] unless root 93 | @files ||= \ 94 | if manifest 95 | File.readlines(manifest). 96 | map{ |line| line.strip }. 97 | reject{ |line| line.empty? || line[0,1] == '#' } 98 | else 99 | list = [] 100 | Dir.chdir(root) do 101 | FILES.split(/\s+/).each do |pattern| 102 | list.concat(glob(pattern)) 103 | end 104 | OMIT.split(/\s+/).each do |pattern| 105 | list = list - glob(pattern) 106 | end 107 | end 108 | list 109 | end.select{ |path| File.file?(path) }.uniq 110 | end 111 | 112 | # 113 | def glob_files(pattern) 114 | return [] unless root 115 | Dir.chdir(root) do 116 | Dir.glob(pattern).select do |path| 117 | File.file?(path) && files.include?(path) 118 | end 119 | end 120 | end 121 | 122 | def patterns 123 | PATTERNS 124 | end 125 | 126 | def executables 127 | @executables ||= \ 128 | glob_files(patterns[:bin]).map do |path| 129 | File.basename(path) 130 | end 131 | end 132 | 133 | def extensions 134 | @extensions ||= \ 135 | glob_files(patterns[:ext]).map do |path| 136 | File.basename(path) 137 | end 138 | end 139 | 140 | def name 141 | metadata['name'] || metadata['title'].downcase.gsub(/\W+/,'_') 142 | end 143 | 144 | def homepage 145 | page = ( 146 | metadata['resources'].find{ |r| r['type'] =~ /^home/i } || 147 | metadata['resources'].find{ |r| r['name'] =~ /^home/i } || 148 | metadata['resources'].find{ |r| r['name'] =~ /^web/i } 149 | ) 150 | page ? page['uri'] : false 151 | end 152 | 153 | def licenses 154 | metadata['copyrights'].map{ |c| c['license'] }.compact 155 | end 156 | 157 | def require_paths 158 | paths = metadata['paths'] || {} 159 | paths['load'] || ['lib'] 160 | end 161 | 162 | # 163 | # Convert to gemnspec. 164 | # 165 | def to_gemspec 166 | if has_root? 167 | Gem::Specification.new do |gemspec| 168 | to_gemspec_data(gemspec) 169 | to_gemspec_paths(gemspec) 170 | end 171 | else 172 | Gem::Specification.new do |gemspec| 173 | to_gemspec_data(gemspec) 174 | to_gemspec_paths(gemspec) 175 | end 176 | end 177 | end 178 | 179 | # 180 | # Convert pure data settings. 181 | # 182 | def to_gemspec_data(gemspec) 183 | gemspec.name = name 184 | gemspec.version = metadata['version'] 185 | gemspec.summary = metadata['summary'] 186 | gemspec.description = metadata['description'] 187 | 188 | metadata['authors'].each do |author| 189 | gemspec.authors << author['name'] 190 | 191 | if author.has_key?('email') 192 | if gemspec.email 193 | gemspec.email << author['email'] 194 | else 195 | gemspec.email = [author['email']] 196 | end 197 | end 198 | end 199 | 200 | gemspec.licenses = licenses 201 | 202 | requirements = metadata['requirements'] || [] 203 | requirements.each do |req| 204 | next if req['optional'] 205 | next if req['external'] 206 | 207 | name = req['name'] 208 | groups = req['groups'] || [] 209 | 210 | version = gemify_version(req['version']) 211 | 212 | if groups.empty? or groups.include?('runtime') 213 | # populate runtime dependencies 214 | if gemspec.respond_to?(:add_runtime_dependency) 215 | gemspec.add_runtime_dependency(name,*version) 216 | else 217 | gemspec.add_dependency(name,*version) 218 | end 219 | else 220 | # populate development dependencies 221 | if gemspec.respond_to?(:add_development_dependency) 222 | gemspec.add_development_dependency(name,*version) 223 | else 224 | gemspec.add_dependency(name,*version) 225 | end 226 | end 227 | end 228 | 229 | # convert external dependencies into gemspec requirements 230 | requirements.each do |req| 231 | next unless req['external'] 232 | gemspec.requirements << ("%s-%s" % req.values_at('name', 'version')) 233 | end 234 | 235 | gemspec.homepage = homepage 236 | gemspec.require_paths = require_paths 237 | gemspec.post_install_message = metadata['install_message'] 238 | end 239 | 240 | # 241 | # Set gemspec settings that require a root directory path. 242 | # 243 | def to_gemspec_paths(gemspec) 244 | gemspec.files = files 245 | gemspec.extensions = extensions 246 | gemspec.executables = executables 247 | 248 | if Gem::VERSION < '1.7.' 249 | gemspec.default_executable = gemspec.executables.first 250 | end 251 | 252 | gemspec.test_files = glob_files(patterns[:test]) 253 | 254 | unless gemspec.files.include?('.document') 255 | gemspec.extra_rdoc_files = glob_files(patterns[:doc]) 256 | end 257 | end 258 | 259 | # 260 | # Return a copy of this file. This is used to generate a local 261 | # .gemspec file that can automatically read the index file. 262 | # 263 | def self.source_code 264 | File.read(__FILE__) 265 | end 266 | 267 | private 268 | 269 | def find_root 270 | root_files = patterns[:root] 271 | if Dir.glob(root_files).first 272 | Pathname.new(Dir.pwd) 273 | elsif Dir.glob("../#{root_files}").first 274 | Pathname.new(Dir.pwd).parent 275 | else 276 | #raise "Can't find root of project containing `#{root_files}'." 277 | warn "Can't find root of project containing `#{root_files}'." 278 | nil 279 | end 280 | end 281 | 282 | def glob(pattern) 283 | if File.directory?(pattern) 284 | Dir.glob(File.join(pattern, '**', '*')) 285 | else 286 | Dir.glob(pattern) 287 | end 288 | end 289 | 290 | def gemify_version(version) 291 | case version 292 | when /^(.*?)\+$/ 293 | ">= #{$1}" 294 | when /^(.*?)\-$/ 295 | "< #{$1}" 296 | when /^(.*?)\~$/ 297 | "~> #{$1}" 298 | else 299 | version 300 | end 301 | end 302 | 303 | end 304 | 305 | end 306 | 307 | Indexer::GemspecExporter.gemspec -------------------------------------------------------------------------------- /lib/minitap/minitest5.rb: -------------------------------------------------------------------------------- 1 | # MiniTest adaptor for tapout. 2 | 3 | # Have to make sure the latest version of minitest is used. 4 | begin; gem 'minitest'; rescue; end 5 | 6 | #require 'minitest/unit' 7 | require 'minitap/ignore_callers' 8 | require 'stringio' 9 | 10 | # Becuase of some wierdness in MiniTest 11 | #debug, $DEBUG = $DEBUG, false 12 | #require 'minitest/unit' 13 | #$DEBUG = debug 14 | 15 | module Minitest 16 | 17 | ## 18 | # Base class for TapY and TapJ runners. 19 | # 20 | class Minitap < StatisticsReporter #Reporter 21 | 22 | # TAP-Y/J Revision 23 | REVISION = 4 24 | 25 | # Backtrace patterns to be omitted. 26 | IGNORE_CALLERS = $RUBY_IGNORE_CALLERS 27 | 28 | # Test results. 29 | #attr_reader :test_results 30 | 31 | attr_reader :test_cases 32 | attr_reader :test_count 33 | 34 | attr_accessor :suite_start_time 35 | attr_accessor :case_start_time 36 | attr_accessor :test_start_time 37 | 38 | # Initialize new Minitap Minitest reporter. 39 | def initialize(options = {}) 40 | io = options.delete(:io) || $stdout 41 | 42 | super(io, options) 43 | 44 | # since tapout uses a unix pipe, we don't want any buffering 45 | io.sync = true 46 | 47 | #@_stdout = StringIO.new 48 | #@_stderr = StringIO.new 49 | 50 | #@test_results = {} 51 | #self.assertion_count = 0 52 | 53 | @_source_cache = {} 54 | end 55 | 56 | # 57 | # Minitest's initial hook ran just before testing begins. 58 | # 59 | def start 60 | super 61 | 62 | @test_cases = Runnable.runnables 63 | 64 | capture_io 65 | 66 | #@_stdout, @_stderr = capture_io do 67 | # super_result = super(suite, type) 68 | #end 69 | 70 | before_suite(@test_cases) 71 | end 72 | 73 | # 74 | # Process a test result. 75 | # 76 | def record(minitest_result) 77 | super(minitest_result) 78 | 79 | result = TestResult.new(minitest_result) 80 | 81 | #if exception #&& ENV['minitap_debug'] 82 | # STDERR.puts exception 83 | # STDERR.puts exception.backtrace.join("\n") 84 | #end 85 | 86 | #@test_results[suite] ||= {} 87 | #@test_results[suite][test.to_sym] = record 88 | 89 | case_change = false 90 | 91 | if @previous_case != result.test_case 92 | case_change = true 93 | before_case(result.test_case) 94 | end 95 | 96 | #before_test(result) 97 | case result.type 98 | when :skip 99 | test_skip(result) 100 | when :pass 101 | test_pass(result) 102 | when :fail 103 | test_fail(result) 104 | when :err 105 | test_err(result) 106 | end 107 | after_test(result) 108 | 109 | if case_change 110 | after_case(result.test_case) 111 | end 112 | 113 | @previous_case = result.test_case 114 | end 115 | 116 | # 117 | # Minitest's finalization hook. 118 | # 119 | def report 120 | super 121 | 122 | uncapture_io 123 | 124 | after_suite() 125 | end 126 | 127 | # 128 | # Intermediary Callbacks 129 | # 130 | 131 | # 132 | def before_suite(test_cases) 133 | @suite_start_time = Time.now 134 | count_tests!(test_cases) 135 | tapout_before_suite() 136 | end 137 | 138 | def after_suite() #(test_cases) 139 | tapout_after_suite() 140 | end 141 | 142 | def before_case(test_case) 143 | @case_start_time = Time.now 144 | tapout_before_case(test_case) 145 | end 146 | 147 | def after_case(test_case) 148 | tapout_after_case(test_case) 149 | end 150 | 151 | def before_test(result) 152 | @test_start_time = Time.now 153 | tapout_before_test(result) 154 | end 155 | 156 | def after_test(result) 157 | tapout_after_test(result) 158 | end 159 | 160 | def test_skip(result) 161 | tapout_test_skip(result) 162 | end 163 | 164 | def test_pass(result) 165 | tapout_test_pass(result) 166 | end 167 | 168 | def test_fail(result) 169 | tapout_test_failure(result) 170 | end 171 | 172 | def test_err(result) 173 | tapout_test_error(result) 174 | end 175 | 176 | =begin 177 | def _run_suites(suites, type) 178 | #output.puts "# Run options: #{@help}" 179 | 180 | @suites_start_time = Time.now 181 | count_tests!(suites, type) 182 | trigger_callback(:before_suites, suites, type) 183 | super(suites, type) 184 | ensure 185 | trigger_callback(:after_suites, suites, type) 186 | end 187 | 188 | def _run_suite(suite, type) 189 | # The only reason this is here is b/c MiniTest wil try to run 190 | # base classes like `MiniTest::Spec`. So to prevent that, 191 | # if there are no tests to run, we don't bother to process 192 | # the "suite" at all. 193 | @_suite_tests = suite.send("#{type}_methods") 194 | return [0,0] if @_suite_tests.empty? 195 | 196 | begin 197 | @suite_start_time = Time.now 198 | trigger_callback(:before_suite, suite) 199 | 200 | super_result = nil 201 | @_stdout, @_stderr = capture_io do 202 | super_result = super(suite, type) 203 | end 204 | super_result 205 | ensure 206 | trigger_callback(:after_suite, suite) 207 | end 208 | end 209 | 210 | def before_test(suite, test) 211 | @test_start_time = Time.now 212 | trigger_callback(:before_test, suite, test) 213 | end 214 | 215 | def after_test(suite, test) 216 | #runners = @test_recorder[suite, test.to_sym] 217 | #records = @test_results[suite][test.to_sym] 218 | record = @test_results[suite][test.to_sym] 219 | 220 | #records.each do |record| 221 | # trigger_callback(record.result, suite, test.to_sym, record) 222 | #end 223 | 224 | trigger_callback(record.result, suite, test.to_sym, record) 225 | 226 | #trigger_callback(:after_test, suite, test.to_sym) 227 | end 228 | =end 229 | 230 | # Stub out the three IO methods used by the built-in reporter. 231 | def p(*args) 232 | args.each{ |a| io.print(a.inspect); puts } 233 | end 234 | 235 | def puts(*args) 236 | io.puts(*args) 237 | end 238 | 239 | def print(*args) 240 | io.print(*args) 241 | end 242 | 243 | #def status(io = output); end 244 | 245 | private 246 | 247 | # 248 | def filtered_tests(test_case) #suite, type 249 | filter = options[:filter] || '/./' 250 | filter = Regexp.new($1) if filter =~ /\/(.*)\// 251 | test_case.runnable_methods.grep(filter) 252 | end 253 | 254 | =begin 255 | # 256 | def add_test_result(suite, test, test_runner) 257 | self.report[suite] ||= {} 258 | self.report[suite][test.to_sym] = test_runner 259 | 260 | self.assertion_count += test_runner.assertions 261 | 262 | case test_runner.result 263 | when :skip then self.skips += 1 264 | when :failure then self.failures += 1 265 | when :error then self.errors += 1 266 | end 267 | end 268 | =end 269 | 270 | def count_tests!(test_cases) 271 | filter = options[:filter] || '/./' 272 | filter = Regexp.new $1 if filter =~ /\/(.*)\// 273 | 274 | @test_count = test_cases.inject(0) do |acc, test_case| 275 | acc + test_case.runnable_methods.grep(filter).length 276 | end 277 | end 278 | 279 | # 280 | # Tapout Records 281 | # 282 | 283 | # 284 | def tapout_before_suite() 285 | doc = { 286 | 'type' => 'suite', 287 | 'start' => self.suite_start_time.strftime('%Y-%m-%d %H:%M:%S'), 288 | 'count' => self.test_count, 289 | 'seed' => self.options[:seed], 290 | 'rev' => REVISION 291 | } 292 | return doc 293 | end 294 | 295 | # 296 | def tapout_after_suite() 297 | doc = { 298 | 'type' => 'final', 299 | 'time' => Time.now - self.suite_start_time, 300 | 'counts' => { 301 | 'total' => self.test_count, 302 | 'pass' => self.test_count - self.failures - self.errors - self.skips, 303 | 'fail' => self.failures, 304 | 'error' => self.errors, 305 | 'omit' => self.skips, 306 | 'todo' => 0 # TODO: does minitest support pending tests? 307 | } 308 | } 309 | return doc 310 | end 311 | 312 | # 313 | def tapout_before_case(test_case) 314 | doc = { 315 | 'type' => 'case', 316 | 'subtype' => '', 317 | 'label' => "#{test_case}", 318 | 'level' => 0 319 | } 320 | 321 | record_stdcom(doc) 322 | 323 | return doc 324 | end 325 | 326 | # 327 | def tapout_after_case(test_case) 328 | end 329 | 330 | # 331 | def tapout_before_test(result) 332 | end 333 | 334 | # 335 | def tapout_after_test(result) 336 | end 337 | 338 | # TAP record for pass. 339 | # 340 | # Returns [Hash]. 341 | def tapout_test_pass(result) #suite, test, test_runner 342 | doc = { 343 | 'type' => 'test', 344 | 'subtype' => '', 345 | 'status' => 'pass', 346 | #'setup': foo instance 347 | 'label' => "#{result.label}", 348 | #'expected' => 2 349 | #'returned' => 2 350 | #'file' => 'test/test_foo.rb' 351 | #'line': 45 352 | #'source': ok 1, 2 353 | #'snippet': 354 | # - 44: ok 0,0 355 | # - 45: ok 1,2 356 | # - 46: ok 2,4 357 | #'coverage': 358 | # file: lib/foo.rb 359 | # line: 11..13 360 | # code: Foo#* 361 | 'time' => Time.now - self.suite_start_time 362 | } 363 | 364 | record_stdcom(doc) 365 | 366 | #stdout, stderr = @_stdout, @_stderr 367 | #doc['stdout'] = stdout unless stdout.empty? 368 | #doc['stderr'] = stderr unless stderr.empty? 369 | 370 | return doc 371 | end 372 | 373 | # TAP record for skip. 374 | # 375 | # Returns [Hash]. 376 | def tapout_test_skip(result) #suite, test, test_runner 377 | e = result.exception 378 | e_file, e_line = location(result.exception) 379 | r_file = e_file.sub(Dir.pwd+'/', '') 380 | 381 | doc = { 382 | 'type' => 'test', 383 | 'subtype' => '', 384 | 'status' => 'skip', 385 | 'label' => "#{result.label}", 386 | #'setup' => "foo instance", 387 | #'expected' => 2, 388 | #'returned' => 1, 389 | #'file' => test/test_foo.rb 390 | #'line' => 45 391 | #'source' => ok 1, 2 392 | #'snippet' => 393 | # - 44: ok 0,0 394 | # - 45: ok 1,2 395 | # - 46: ok 2,4 396 | #'coverage' => 397 | # 'file' => lib/foo.rb 398 | # 'line' => 11..13 399 | # 'code' => Foo#* 400 | 'exception' => { 401 | 'message' => clean_message(e.message), 402 | 'class' => e.class.name, 403 | 'file' => r_file, 404 | 'line' => e_line, 405 | 'source' => source(e_file)[e_line-1].strip, 406 | 'snippet' => code_snippet(e_file, e_line), 407 | 'backtrace' => filter_backtrace(e.backtrace) 408 | }, 409 | 'time' => Time.now - self.suite_start_time 410 | } 411 | return doc 412 | end 413 | 414 | # TAP record for failure. 415 | # 416 | # Returns [Hash]. 417 | def tapout_test_failure(result) 418 | e = result.exception 419 | e_file, e_line = location(result.exception) 420 | r_file = e_file.sub(Dir.pwd+'/', '') 421 | 422 | doc = { 423 | 'type' => 'test', 424 | 'subtype' => '', 425 | 'status' => 'fail', 426 | 'label' => "#{result.label}", 427 | #'setup' => "foo instance", 428 | #'expected' => 2, 429 | #'returned' => 1, 430 | #'file' => test/test_foo.rb 431 | #'line' => 45 432 | #'source' => ok 1, 2 433 | #'snippet' => 434 | # - 44: ok 0,0 435 | # - 45: ok 1,2 436 | # - 46: ok 2,4 437 | #'coverage' => 438 | # 'file' => lib/foo.rb 439 | # 'line' => 11..13 440 | # 'code' => Foo#* 441 | 'exception' => { 442 | 'message' => clean_message(e.message), 443 | 'class' => e.class.name, 444 | 'file' => r_file, 445 | 'line' => e_line, 446 | 'source' => source(e_file)[e_line-1].strip, 447 | 'snippet' => code_snippet(e_file, e_line), 448 | 'backtrace' => filter_backtrace(e.backtrace) 449 | }, 450 | 'time' => Time.now - self.suite_start_time # result.time 451 | } 452 | 453 | record_stdcom(doc) 454 | 455 | #stdout, stderr = @_stdout, @_stderr 456 | #doc['stdout'] = stdout unless stdout.empty? 457 | #doc['stderr'] = stderr unless stderr.empty? 458 | 459 | return doc 460 | end 461 | 462 | # TAP record for error. 463 | # 464 | # Returns [Hash]. 465 | def tapout_test_error(result) 466 | e = result.exception 467 | e_file, e_line = location(e) 468 | r_file = e_file.sub(Dir.pwd+'/', '') 469 | 470 | doc = { 471 | 'type' => 'test', 472 | 'subtype' => '', 473 | 'status' => 'error', 474 | 'label' => "#{result.label}", 475 | #'setup' => "foo instance", 476 | #'expected' => 2, 477 | #'returned' => 1, 478 | #'file' => test/test_foo.rb 479 | #'line' => 45 480 | #'source' => ok 1, 2 481 | #'snippet' => 482 | # - 44: ok 0,0 483 | # - 45: ok 1,2 484 | # - 46: ok 2,4 485 | #'coverage' => 486 | # 'file' => lib/foo.rb 487 | # 'line' => 11..13 488 | # 'code' => Foo#* 489 | 'exception' => { 490 | 'message' => clean_message(e.error.message), 491 | 'class' => e.error.class.name, 492 | 'file' => r_file, 493 | 'line' => e_line, 494 | 'source' => source(e_file)[e_line-1].strip, 495 | 'snippet' => code_snippet(e_file, e_line), 496 | 'backtrace' => filter_backtrace(e.backtrace) 497 | }, 498 | 'time' => Time.now - self.suite_start_time # result.time 499 | } 500 | 501 | record_stdcom(doc) 502 | 503 | #stdout, stderr = @_stdout, @_stderr 504 | #doc['stdout'] = stdout unless stdout.empty? 505 | #doc['stderr'] = stderr unless stderr.empty? 506 | 507 | return doc 508 | end 509 | 510 | # --------------------------------------------------------------------- 511 | 512 | # 513 | # 514 | # 515 | def record_stdcom(doc) 516 | begin 517 | doc['stdout'] = $stdout.string unless $stdout.length == 0 #empty? 518 | doc['stderr'] = $stderr.string unless $stderr.length == 0 #empty? 519 | $stdout.close; $stderr.close 520 | $stdout, $stderr = StringIO.new, StringIO.new 521 | #end 522 | rescue => err 523 | uncapture_io 524 | raise err 525 | end 526 | end 527 | 528 | # 529 | #def filter_backtrace(backtrace) 530 | # trace = backtrace 531 | # trace = clean_backtrace(trace) 532 | # trace = MiniTest::filter_backtrace(trace) 533 | # trace 534 | #end 535 | 536 | # Clean the backtrace of any reference to test framework itself. 537 | def filter_backtrace(backtrace) 538 | ## remove backtraces that match any pattern in IGNORE_CALLERS 539 | trace = backtrace.reject{|b| IGNORE_CALLERS.any?{|i| i=~b}} 540 | ## remove `:in ...` portion of backtraces 541 | trace = trace.map do |bt| 542 | i = bt.index(':in') 543 | i ? bt[0...i] : bt 544 | end 545 | ## now apply MiniTest's own filter (note: doesn't work if done first, why?) 546 | trace = Minitest::filter_backtrace(trace) 547 | ## if the backtrace is empty now then revert to the original 548 | trace = backtrace if trace.empty? 549 | ## simplify paths to be relative to current workding diectory 550 | trace = trace.map{ |bt| bt.sub(Dir.pwd+File::SEPARATOR,'') } 551 | return trace 552 | end 553 | 554 | # Returns a String of source code. 555 | def code_snippet(file, line) 556 | s = [] 557 | if File.file?(file) 558 | source = source(file) 559 | radius = 2 # TODO: make customizable (number of surrounding lines to show) 560 | region = [line - radius, 1].max .. 561 | [line + radius, source.length].min 562 | 563 | s = region.map do |n| 564 | {n => source[n-1].chomp} 565 | end 566 | end 567 | return s 568 | end 569 | 570 | # Cache source file text. This is only used if the TAP-Y stream 571 | # doesn not provide a snippet and the test file is locatable. 572 | def source(file) 573 | @_source_cache[file] ||= ( 574 | File.readlines(file) 575 | ) 576 | end 577 | 578 | # Parse source location from caller, caller[0] or an Exception object. 579 | def parse_source_location(caller) 580 | case caller 581 | when Exception 582 | trace = caller.backtrace.reject{ |bt| bt =~ INTERNALS } 583 | caller = trace.first 584 | when Array 585 | caller = caller.first 586 | end 587 | caller =~ /(.+?):(\d+(?=:|\z))/ or return "" 588 | source_file, source_line = $1, $2.to_i 589 | return source_file, source_line 590 | end 591 | 592 | # Get location of exception. 593 | def location e # :nodoc: 594 | last_before_assertion = "" 595 | e.backtrace.reverse_each do |s| 596 | break if s =~ /in .(assert|refute|flunk|pass|fail|raise|must|wont)/ 597 | last_before_assertion = s 598 | end 599 | file, line = last_before_assertion.sub(/:in .*$/, '').split(':') 600 | line = line.to_i if line 601 | return file, line 602 | end 603 | 604 | # 605 | def clean_message(message) 606 | message.strip #.gsub(/\s*\n\s*/, "\n") 607 | end 608 | 609 | # 610 | #def capture_io 611 | # ostdout, ostderr = $stdout, $stderr 612 | # cstdout, cstderr = StringIO.new, StringIO.new 613 | # $stdout, $stderr = cstdout, cstderr 614 | # 615 | # yield 616 | # 617 | # return cstdout.string.chomp("\n"), cstderr.string.chomp("\n") 618 | #ensure 619 | # $stdout = ostdout 620 | # $stderr = ostderr 621 | #end 622 | 623 | # 624 | def capture_io 625 | @_stdout, @_stderr = $stdout, $stderr 626 | $stdout, $stderr = StringIO.new, StringIO.new 627 | end 628 | 629 | # 630 | def uncapture_io 631 | $stdout, $stderr = @_stdout, @_stderr 632 | end 633 | 634 | end 635 | 636 | # 637 | # TestResult delegtes to Minitest's own test result object. 638 | # 639 | class TestResult 640 | # Create new TestResult instance. 641 | # 642 | # result - MiniTest's test result object. 643 | # 644 | def initialize(result) 645 | @result = result 646 | end 647 | 648 | def test_case 649 | @result.class 650 | end 651 | alias :testcase :test_case 652 | 653 | # Name of the test. 654 | def name 655 | @result.name 656 | end 657 | alias :test :name 658 | 659 | # 660 | def label 661 | if spec? 662 | name.sub(/^test_\d+_/, '').gsub('_', ' ') 663 | else 664 | name 665 | end 666 | end 667 | 668 | # Is this a Minitest::Spec? 669 | # 670 | # Returns [Boolean]. 671 | def spec? 672 | @is_spec ||= ( 673 | Minitest.const_defined?(:Spec) && @result.class < Minitest::Spec 674 | #@result.class.methods.include?(:it) || @result.class.methods.include?('it') 675 | ) 676 | end 677 | 678 | # Number of assertions made by test. 679 | # 680 | # Returns [Integer]. 681 | def assertions 682 | @result.assertions 683 | end 684 | 685 | # 686 | def time 687 | @result.time 688 | end 689 | 690 | # 691 | def exception 692 | @result.failure 693 | end 694 | 695 | # Result type. 696 | def type 697 | case exception 698 | when UnexpectedError 699 | :err 700 | when Skip 701 | :skip 702 | when Assertion 703 | :fail 704 | when nil 705 | :pass 706 | else 707 | :err 708 | end 709 | end 710 | end 711 | 712 | =begin 713 | # Runner for individual MiniTest tests. 714 | # 715 | # You *should not* create instances of this class directly. Instances of 716 | # {SuiteRunner} will create these and send them to the reporters. 717 | # 718 | # Based upon Ryan Davis of Seattle.rb's MiniTest (MIT License). 719 | # 720 | # @see https://github.com/seattlerb/minitest MiniTest 721 | class TestRunner 722 | attr_reader :suite, :test, :assertions, :result, :exception 723 | attr_reader :stdout, :stderr 724 | 725 | def initialize(suite, test) 726 | @suite = suite 727 | @test = test 728 | @assertions = 0 729 | end 730 | 731 | def run 732 | suite_instance = suite.new(test) 733 | test_result = nil 734 | @stdout, @stderr = capture_io do 735 | test_result = suite_instance.run(self) 736 | end 737 | @result, @exception = fix_result(test_result) 738 | @assertions = suite_instance._assertions 739 | end 740 | 741 | def puke(suite, test, exception) 742 | case exception 743 | when MiniTest::Skip then [:skip, exception] 744 | when MiniTest::Assertion then [:failure, exception] 745 | else [:error, exception] 746 | end 747 | end 748 | 749 | def record(suite, method, assertions, time, error) 750 | end 751 | 752 | private 753 | 754 | # 755 | def fix_result(result) 756 | result == '.' ? [:pass, nil] : result 757 | end 758 | 759 | # 760 | def capture_io 761 | ostdout, ostderr = $stdout, $stderr 762 | cstdout, cstderr = StringIO.new, StringIO.new 763 | $stdout, $stderr = cstdout, cstderr 764 | 765 | yield 766 | 767 | return cstdout.string.chomp("\n"), cstderr.string.chomp("\n") 768 | ensure 769 | $stdout = ostdout 770 | $stderr = ostderr 771 | end 772 | end 773 | =end 774 | 775 | =begin 776 | ## 777 | # Around advice. 778 | # 779 | module AroundTestHooks 780 | def self.before_test(instance) 781 | if before_test = (MiniTest::Unit.runner.method(:before_test) rescue nil) 782 | before_test.call(instance.class, instance.__name__) 783 | end 784 | end 785 | 786 | def self.after_test(instance) 787 | # MiniTest < 4.1.0 sends #record after all teardown hooks, so don't call 788 | # #after_test here. 789 | if MiniTest::Unit::VERSION > "4.1.0" 790 | if after_test = (MiniTest::Unit.runner.method(:after_test) rescue nil) 791 | after_test.call(instance.class, instance.__name__) 792 | end 793 | end 794 | end 795 | 796 | def before_setup 797 | AroundTestHooks.before_test(self) 798 | super 799 | end 800 | 801 | def after_teardown 802 | super 803 | AroundTestHooks.after_test(self) 804 | end 805 | end 806 | 807 | class Unit::TestCase 808 | include AroundTestHooks 809 | end 810 | =end 811 | 812 | ## 813 | # TAP-Y adapater. 814 | # 815 | class TapY < Minitap 816 | def initialize(options={}) 817 | require 'yaml' unless respond_to?(:to_yaml) 818 | super(options) 819 | end 820 | 821 | def tapout_before_suite() 822 | wp super().to_yaml 823 | end 824 | def tapout_before_case(test_case) 825 | wp super(test_case).to_yaml 826 | end 827 | def tapout_test_pass(result) 828 | wp super(result).to_yaml 829 | end 830 | def tapout_test_skip(result) 831 | wp super(result).to_yaml 832 | end 833 | def tapout_test_failure(result) 834 | wp super(result).to_yaml 835 | end 836 | def tapout_test_error(result) 837 | wp super(result).to_yaml 838 | end 839 | def tapout_after_suite() 840 | wp super().to_yaml 841 | wp "..." 842 | end 843 | 844 | def wp(str) 845 | io.puts(str) 846 | end 847 | end 848 | 849 | ## 850 | # TAP-J adapater. 851 | # 852 | class TapJ < Minitap 853 | def initialize(options={}) 854 | require 'json' unless respond_to?(:to_json) 855 | super(options) 856 | end 857 | 858 | def tapout_before_suite() 859 | wp super().to_json 860 | end 861 | def tapout_before_case(test_case) 862 | wp super(test_case).to_json 863 | end 864 | def tapout_test_pass(result) 865 | wp super(result).to_json 866 | end 867 | def tapout_test_skip(result) 868 | wp super(result).to_json 869 | end 870 | def tapout_test_failure(result) 871 | wp super(result).to_json 872 | end 873 | def tapout_test_error(result) 874 | wp super(result).to_json 875 | end 876 | def tapout_after_suite() 877 | wp super().to_json 878 | end 879 | 880 | def wp(str) 881 | io.puts(str) 882 | end 883 | end 884 | 885 | end 886 | --------------------------------------------------------------------------------