rubytest 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.ruby ADDED
@@ -0,0 +1,45 @@
1
+ ---
2
+ source:
3
+ - var
4
+ authors:
5
+ - name: trans
6
+ email: transfire@gmail.com
7
+ copyrights:
8
+ - holder: RubyWorks
9
+ year: '2011'
10
+ license: BSD-2-Clause
11
+ replacements: []
12
+ alternatives: []
13
+ requirements:
14
+ - name: ansi
15
+ - name: detroit
16
+ groups:
17
+ - build
18
+ development: true
19
+ - name: qed
20
+ groups:
21
+ - test
22
+ development: true
23
+ dependencies: []
24
+ conflicts: []
25
+ repositories:
26
+ - uri: git@github.com:rubyworks/ruby-test.git
27
+ scm: git
28
+ name: upstream
29
+ resources:
30
+ home: http://rubyworks.github.com/ruby-test
31
+ code: http://github.com/rubyworks/ruby-test
32
+ mail: http://groups.google.com/group/rubyworks-mailinglist
33
+ extra: {}
34
+ load_path:
35
+ - lib
36
+ revision: 0
37
+ created: '2011-07-23'
38
+ summary: Ruby Universal Test Harness
39
+ title: Ruby Test
40
+ version: 0.3.0
41
+ name: rubytest
42
+ description: ! "Ruby Test is a universal test harness for Ruby. It can handle any
43
+ compliant \ntest framework, even running tests from multiple frameworks in a single
44
+ pass."
45
+ date: '2011-12-23'
data/.test ADDED
@@ -0,0 +1,11 @@
1
+ Test.run(:default) do |run|
2
+ run.files << 'test/*_case.rb'
3
+ end
4
+
5
+ Test.run(:cov) do |run|
6
+ run.files << 'test/*_case.rb'
7
+ SimpleCov.start do |cov|
8
+ cov.coverage_dir = 'log/coverage'
9
+ end
10
+ end
11
+
data/HISTORY.md ADDED
@@ -0,0 +1,43 @@
1
+ # RELEASE HISTORY
2
+
3
+ ## 0.3.0 / 2011-12-22
4
+
5
+ Technically this is a fairly minor release that improves backtrace output
6
+ and prepares the `LOAD_PATH` automtically if a `.ruby` file is present.
7
+ However, it is significant in that the name of the gem has been changed
8
+ from `test` to `rubytest`.
9
+
10
+ Changes:
11
+
12
+ * Change gem name to `rubytest`.
13
+ * Improve backtrace filtering in reporters.
14
+ * Setup `LOAD_PATH` based on .ruby file if present.
15
+
16
+
17
+ ## 0.2.0 / 2011-08-10
18
+
19
+ With this release Ruby Test is essentially feature complete. Of course there
20
+ are plenty of tweaks and improvements yet to come, but Ruby Test is fully usable
21
+ at this point. Only one major aspect of the design remains in question --the
22
+ way per-testcase "before and after all" advice is handled. Other than that
23
+ the API fairly solid, even as this early state of development. Always helps
24
+ when you have a spec to go by!
25
+
26
+ Changes:
27
+
28
+ * Use Config class to look-up .test file.
29
+ * Support hard testing, topic and pre-case setup.
30
+ * Add autorun.rb runner script.
31
+ * Add a test reporter to use for testing Ruby Test itself.
32
+ * Improved dotprogess reporter's handling of omissions.
33
+ * Add unit selection to test runner.
34
+
35
+
36
+ ## 0.1.0 / 2011-07-30
37
+
38
+ First release of Ruby Test.
39
+
40
+ Changes:
41
+
42
+ * It's Your Birthday!
43
+
data/NOTICE.md ADDED
@@ -0,0 +1,33 @@
1
+ # COPYRIGHT NOTICES
2
+
3
+ ## Ruby Test
4
+
5
+ **Project** | Ruby Test
6
+ --------------|------------------------------------------
7
+ **Website** | http://rubyworks.github.com/ruby-test
8
+ **License** | BSD-2-Clause
9
+ **Copyright** | (c) 2011 Rubyworks
10
+
11
+ Copyright 2011 Rubyworks. All rights reserved.
12
+
13
+ Redistribution and use in source and binary forms, with or without
14
+ modification, are permitted provided that the following conditions are met:
15
+
16
+ 1. Redistributions of source code must retain the above copyright notice,
17
+ this list of conditions and the following disclaimer.
18
+
19
+ 2. Redistributions in binary form must reproduce the above copyright
20
+ notice, this list of conditions and the following disclaimer in the
21
+ documentation and/or other materials provided with the distribution.
22
+
23
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
25
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26
+ COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
30
+ OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
32
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
+
data/README.md ADDED
@@ -0,0 +1,112 @@
1
+ # Ruby Test
2
+
3
+ [Homepage](http://rubyworks.github.com/rubytest) /
4
+ [User Guide](http://wiki.github.com/rubyworks/rubytest) /
5
+ [Development](http://github.com/rubyworks/rubytest) /
6
+ [Issues](http://github.com/rubyworks/rubytest/issues)
7
+
8
+ ## Description
9
+
10
+ Ruby Test is a universal test harness for Ruby that can be used by any Ruby
11
+ test framework. Ruby Test defines a simple specification for compliance, which
12
+ allows tests from various frameworks to all run
13
+
14
+ Ruby Test defines a straight-forward specification that any test framework can
15
+ easily support which allows Ruby Test to run the frameworks tests through a
16
+ single uniform user interface in a single pass.
17
+
18
+ ## Specification
19
+
20
+ The universal access point for testing is the `$TEST_SUITE` global array. A test
21
+ framework need only add compliant test objects to `$TEST_SUITE`.
22
+ Ruby Test will iterate through these objects. If a test object responds to
23
+ `#call`, it is run as a test procedure. If it responds to `#each` it is iterated
24
+ over as a test case with each entry handled in the same manner. All test
25
+ objects must respond to `#to_s` so their description can be used in test
26
+ reports.
27
+
28
+ Any raised exception that responds to `#assertion?` in the affirmative is taken
29
+ to be a failed assertion rather than simply an error. Ruby Test extends the
30
+ Exception class to support this method for all exceptions.
31
+
32
+ A test framework may raise a `NotImplementedError` to have a test recorded
33
+ as "pending" --a _todo_ item to remind the developer of tests that still
34
+ need to be written. The `NotImplementedError` is a standard Ruby exception
35
+ and a subclass of `ScriptError`.
36
+
37
+ If the `NotImplmentedError` responds in the affirmative to `#assertion?` then
38
+ the test is taken to be a purposeful _omission_, rather than simply pending.
39
+
40
+ That is the crux of Ruby Test specification. Ruby Test supports some
41
+ additional features that can makes its usage even more convenient.
42
+ See the [Wiki](http://github.com/rubyworks/test/wiki) for further details.
43
+
44
+
45
+ ## Usage
46
+
47
+ There are a few ways to run tests. First, there is a command line tool:
48
+
49
+ $ rubytest
50
+
51
+ The command line tool takes various options, use `--help` to see them.
52
+ Be sure to load in your test framework or framework's Ruby Test adapter.
53
+
54
+ Preconfigurations can be defined in a `.test` file, e.g.
55
+
56
+ Test.run 'default' do |r|
57
+ r.format = 'progress'
58
+ r.requires << 'lemon'
59
+ r.files << 'test/*_case.rb'
60
+ end
61
+
62
+ There is also a 'rubytest/autorun.rb' library script that can be loaded which
63
+ creates an `at_exit` runner, for which `test.rb` provides a nice shortcut:
64
+
65
+ $ ruby -r test
66
+
67
+ There is also a Rake task.
68
+
69
+ require 'rubytest/rake'
70
+
71
+ Test::Rake::TestTask.new
72
+
73
+ A Detroit plugin is in the works and should be available soon.
74
+
75
+
76
+ ## Installation
77
+
78
+ Ruby Test is available as Gem package.
79
+
80
+ $ gem install rubytest
81
+
82
+
83
+ ## Requirements
84
+
85
+ Ruby Test uses the [ANSI](http://rubyworks.github.com/ansi) gem for color output.
86
+
87
+ Because of the "foundational" nature of this library we will look at removing
88
+ this dependencies for future versions, but for early development the
89
+ requirements does the job and does it well.
90
+
91
+
92
+ ## Development
93
+
94
+ Ruby Test is still a "nuby" gem. Please feel OBLIGATED to help improve it ;-)
95
+
96
+ Ruby Test is a [RubyWorks](http://rubyworks.github.com) project. If you can't
97
+ contribue code, you can still help out by contributing to our development fund.
98
+
99
+
100
+ ## Reference Material
101
+
102
+ [1] [Standard Definition Of Unit Test](http://c2.com/cgi/wiki?StandardDefinitionOfUnitTest)
103
+
104
+
105
+ ## Copyrights
106
+
107
+ Copyright (c) 2011 Rubyworks
108
+
109
+ Made available according to the terms of the <b>FreeBSD license</b>.
110
+
111
+ See NOTICE.md for details.
112
+
data/bin/rubytest ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubytest'
3
+ Test::Runner.cli(*ARGV)
4
+
data/demo/01_test.md ADDED
@@ -0,0 +1,29 @@
1
+ ## Defining a Test
2
+
3
+ Any object in a test suite that responds to #call, will be executed as
4
+ a test. For instance, given an abtriray object defined as follows.
5
+
6
+ test = Object.new
7
+
8
+ def test.okay
9
+ @okay
10
+ end
11
+
12
+ def test.call
13
+ @okay = true
14
+ end
15
+
16
+ If we pass this to a test runner as part of a test suite,
17
+
18
+ runner = Test::Runner.new(:suite=>[test], :format=>'test')
19
+
20
+ success = runner.run
21
+
22
+ We will see that the test was called.
23
+
24
+ test.assert.okay
25
+
26
+ And testing was successful.
27
+
28
+ success.assert == true
29
+
data/demo/02_case.md ADDED
@@ -0,0 +1,34 @@
1
+ ## Defining a Test Case
2
+
3
+ Any object in a test suite that responds to #each, will be iterated over
4
+ and each entry run a test or another sub-case. For instance, given an abitrary
5
+ object defined as follows.
6
+
7
+ test = Object.new
8
+
9
+ def test.okay
10
+ @okay
11
+ end
12
+
13
+ def test.call
14
+ @okay = true
15
+ end
16
+
17
+ And placed into an array.
18
+
19
+ tests = [test]
20
+
21
+ If we pass this to a test runner as part of a test suite,
22
+
23
+ runner = Test::Runner.new(:suite=>[tests], :format=>'test')
24
+
25
+ success = runner.run
26
+
27
+ We will see that the test was called.
28
+
29
+ test.assert.okay
30
+
31
+ And testing was successful.
32
+
33
+ success.assert == true
34
+
@@ -0,0 +1,2 @@
1
+ require 'test/runner'
2
+
@@ -0,0 +1,19 @@
1
+ #$TEST_SUITE = [] unless defined?($TEST_SUITE)
2
+
3
+ if RUBY_VERSION < '1.9'
4
+ require 'ruth'
5
+ else
6
+ require_relative '../ruth'
7
+ end
8
+
9
+ at_exit {
10
+ suite = $TEST_SUITE
11
+ options = {
12
+ :format => ENV['rubytest-format'] # TODO: better name?
13
+ }
14
+
15
+ runner = Ruth::Test::Runner.new(suite, options)
16
+ success = runner.run
17
+ exit -1 unless success
18
+ }
19
+
@@ -0,0 +1,106 @@
1
+ module Test
2
+
3
+ # Command line interface.
4
+ class Runner
5
+
6
+ # Test runner command line interface.
7
+ #
8
+ def self.cli(*argv)
9
+ runner = Runner.new
10
+
11
+ Test::Config.load
12
+
13
+ cli_options(runner, argv)
14
+
15
+ Test::Config.load_path_setup #unless runner.autopath == false
16
+
17
+ begin
18
+ success = runner.run
19
+ exit -1 unless success
20
+ rescue => error
21
+ raise error if $DEBUG
22
+ $stderr.puts('ERROR: ' + error.to_s)
23
+ end
24
+ end
25
+
26
+ #
27
+ def self.cli_options(runner, argv)
28
+ require 'optparse'
29
+
30
+ config = Test.config.dup
31
+ config_loaded = false
32
+
33
+ common = config.delete('common')
34
+ default = config.delete('default')
35
+
36
+ common.call(runner) if common
37
+
38
+ OptionParser.new do |opt|
39
+ opt.banner = "Usage: #{$0} [options] [files ...]"
40
+
41
+ unless config.empty?
42
+ opt.separator "PRESET OPTIONS:"
43
+ config.each do |name, block|
44
+ opt.on("--#{name}") do
45
+ block.call(runner)
46
+ end
47
+ end
48
+ end
49
+
50
+ opt.separator "CONFIG OPTIONS:"
51
+
52
+ opt.on '-f', '--format NAME', 'report format' do |name|
53
+ runner.format = name
54
+ end
55
+ opt.on '-y', '--tapy', 'shortcut for -f tapy' do
56
+ runner.format = 'tapy'
57
+ end
58
+ opt.on '-j', '--tapj', 'shortcut for -f tapj' do
59
+ runner.format = 'tapj'
60
+ end
61
+
62
+ opt.on '-t', '--tag TAG', 'select tests by tag' do |tag|
63
+ runner.tags << tag
64
+ end
65
+ opt.on '-u', '--unit TAG', 'select tests by software unit' do |unit|
66
+ runner.units << unit
67
+ end
68
+ opt.on '-m', '--match TEXT', 'select tests by description' do |text|
69
+ runner.match << text
70
+ end
71
+
72
+ opt.on '-I', '--loadpath PATH', 'add to $LOAD_PATH' do |paths|
73
+ paths.split(/[:;]/).reverse_each do |path|
74
+ $LOAD_PATH.unshift path
75
+ end
76
+ end
77
+ opt.on '-r', '--require FILE', 'require file' do |file|
78
+ require file
79
+ end
80
+ opt.on '-v' , '--verbose', 'provide extra detailed report' do
81
+ runner.verbose = true
82
+ end
83
+ #opt.on('--log DIRECTORY', 'log directory'){ |dir|
84
+ # options[:log] = dir
85
+ #}
86
+ opt.on_tail("--[no-]ansi" , 'turn on/off ANSI colors'){ |v| $ansi = v }
87
+ opt.on_tail("--debug" , 'turn on debugging mode'){ $DEBUG = true }
88
+ #opt.on_tail("--about" , 'display information about lemon'){
89
+ # puts "Ruby Test v#{VERSION}"
90
+ # puts "#{COPYRIGHT}"
91
+ # exit
92
+ #}
93
+ opt.on_tail('-h', '--help', 'display this help message'){
94
+ puts opt
95
+ exit
96
+ }
97
+ end.parse!(argv)
98
+
99
+ default.call(runner) if default && !config_loaded
100
+
101
+ runner.files.replace(argv) unless argv.empty?
102
+ end
103
+
104
+ end
105
+
106
+ end
@@ -0,0 +1,93 @@
1
+ module Test
2
+
3
+ # Thanks goes to Suraj N. Kurapati for the origins of this code.
4
+ #
5
+ class CodeSnippet
6
+
7
+ def self.cache(file)
8
+ @cache ||= {}
9
+ @cache[file] ||= File.exist?(file) ? File.readlines(file) : ['(N/A)']
10
+ end
11
+
12
+ #
13
+ def self.from_backtrace(backtrace)
14
+ backtrace.first =~ /(.+?):(\d+(?=:|\z))/ or return nil
15
+ file, line = $1, $2.to_i
16
+ new(file, line)
17
+ end
18
+
19
+ #
20
+ def self.from_error(exception)
21
+ backtrace = exception.backtrace
22
+ from_backtrace(backtrace)
23
+ end
24
+
25
+ #
26
+ def initialize(file, line)
27
+ @file = file
28
+ @line = line || 1
29
+ @code = CodeSnippet.cache(file)
30
+ end
31
+
32
+ #
33
+ attr :file
34
+
35
+ #
36
+ attr :line
37
+
38
+ #
39
+ attr :code
40
+
41
+ #
42
+ alias :source :code
43
+
44
+ #
45
+ def to_str
46
+ code[line-1].strip
47
+ end
48
+
49
+ #
50
+ #--
51
+ # TODO: ensure proper alignment by zero-padding line numbers
52
+ #++
53
+ def to_s(radius=2)
54
+ r = range(radius)
55
+ f = " %2s %0#{r.last.to_s.length}d %s"
56
+ r.map do |n|
57
+ f % [('=>' if n == line), n, code[n-1].chomp]
58
+ end.join("\n")
59
+ end
60
+
61
+ #
62
+ def to_a(radius=2)
63
+ r = range(radius)
64
+ r.map do |n|
65
+ code[n-1].chomp
66
+ end
67
+ end
68
+
69
+ #
70
+ def to_omap(radius=2)
71
+ a = []
72
+ r = range(radius)
73
+ r.each do |n|
74
+ a << {n => code[n-1].chomp}
75
+ end
76
+ a
77
+ end
78
+
79
+ #
80
+ def succ
81
+ line += 1
82
+ end
83
+
84
+ private
85
+
86
+ #
87
+ def range(radius)
88
+ [line - radius, 1].max..[line + radius, source.length].min
89
+ end
90
+
91
+ end
92
+
93
+ end
@@ -0,0 +1,106 @@
1
+ module Test
2
+
3
+ #
4
+ def self.run(name=:default, &block)
5
+ @config ||= {}
6
+ @config[name.to_s] = block
7
+ end
8
+
9
+ def self.config
10
+ @config ||= {}
11
+ end
12
+
13
+ #
14
+ class Config
15
+
16
+ # Test configuration file.
17
+ #
18
+ # The name of the file is an ode to the original Ruby cli test tool.
19
+ #
20
+ # @example
21
+ # .test
22
+ # .testrb
23
+ # .test.rb
24
+ # .config/test.rb
25
+ #
26
+ # @todo Too many options for ruby-test configuration file.
27
+ GLOB_RC = '{.testrb,.test.rb,.test,.config/test.rb,config/test.rb}'
28
+
29
+ #
30
+ GLOB_ROOT = '{.ruby,.git,.hg}'
31
+
32
+ #
33
+ def self.load
34
+ super(rc_file) if rc_file
35
+ #Ruth.module_eval(File.read(rc_file)) if rc_file
36
+ end
37
+
38
+ # Find rc file.
39
+ def self.rc_file
40
+ @rc_file ||= (
41
+ glob = GLOB_RC
42
+ stop = root
43
+ default = nil
44
+ dir = Dir.pwd
45
+ file = nil
46
+ loop do
47
+ file = Dir[File.join(dir, glob)].first
48
+ break file if file
49
+ break if dir == stop
50
+ dir = File.dirname(dir)
51
+ break if dir == '/'
52
+ end
53
+ file ? file : default
54
+ )
55
+ end
56
+
57
+ # Find and cache project root directory.
58
+ #
59
+ # @return [String] Project's root path.
60
+ def self.root
61
+ @root ||= (
62
+ glob = GLOB_ROOT
63
+ stop = '/'
64
+ default = Dir.pwd
65
+ dir = Dir.pwd
66
+ until dir == stop
67
+ break dir if Dir[File.join(dir, glob)].first
68
+ dir = File.dirname(dir)
69
+ end
70
+ dir == stop ? default : dir
71
+ )
72
+ end
73
+
74
+ # Load and cache a project's `.ruby` file.
75
+ #
76
+ # @return [Hash] Project's loaded `.ruby` file, if it has one.
77
+ def self.dotruby
78
+ @dotruby ||= (
79
+ drfile = File.join(root, '.ruby')
80
+ if File.exist?(drfile)
81
+ YAML.load_file(drfile)
82
+ else
83
+ {}
84
+ end
85
+ )
86
+ end
87
+
88
+ # Setup $LOAD_PATH based on .ruby file.
89
+ #
90
+ # @todo Maybe we should not fallback to typical load path?
91
+ def self.load_path_setup
92
+ if load_paths = dotruby['load_path']
93
+ load_paths.each do |path|
94
+ $LOAD_PATH.unshift(File.join(root, path))
95
+ end
96
+ else
97
+ typical_load_path = File.join(root, 'lib')
98
+ if File.directory?(typical_load_path)
99
+ $LOAD_PATH.unshift(typical_load_path)
100
+ end
101
+ end
102
+ end
103
+
104
+ end
105
+
106
+ end
@@ -0,0 +1,30 @@
1
+ class Assertion < Exception
2
+
3
+ # New assertion (failure).
4
+ #
5
+ # @param message [String] the failure message
6
+ # @param options [Hash] options such as :backtrace
7
+ #
8
+ def initialize(message=nil, options={})
9
+ super(message)
10
+ backtrace = options[:backtrace]
11
+ set_backtrace(backtrace) if backtrace
12
+ @assertion = true
13
+ end
14
+
15
+ # Technically any object that affirmatively responds to #assertion?
16
+ # can be taken to be an Assertion. This makes it easier for various
17
+ # libraries to work together without having to depend upon a common
18
+ # Assertion base class.
19
+ def assertion?
20
+ true # @assertion
21
+ end
22
+
23
+ # Parents error message prefixed with "(assertion)".
24
+ #
25
+ # @return [String] error message
26
+ def to_s
27
+ '(assertion) ' + super
28
+ end
29
+
30
+ end
@@ -0,0 +1,8 @@
1
+ class Exception
2
+ def set_assertion(boolean)
3
+ @assertion = boolean
4
+ end
5
+ def assertion?
6
+ @assertion
7
+ end
8
+ end