test 0.2.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/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
data/bin/ruby-test ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require 'test/cli'
3
+ Test::Runner.cli(*ARGV)
4
+
data/lib/test.rb ADDED
@@ -0,0 +1,3 @@
1
+ # TODO: Should we have test.rb file?
2
+
3
+ require 'test/autorun'
@@ -0,0 +1,18 @@
1
+ $TEST_SUITE = [] unless defined?($TEST_SUITE)
2
+
3
+ at_exit {
4
+ if RUBY_VERSION < '1.9'
5
+ require 'test/runner'
6
+ else
7
+ require_relative 'runner'
8
+ end
9
+
10
+ suite = $TEST_SUITE
11
+ options = {
12
+ :format => ENV['ruby-test-format'] # TODO: better name?
13
+ }
14
+
15
+ runner = Test::Runner.new(suite, options)
16
+ success = runner.run
17
+ exit -1 unless success
18
+ }
data/lib/test/cli.rb ADDED
@@ -0,0 +1,110 @@
1
+ module Test
2
+
3
+ require 'test/config'
4
+ require 'test/runner'
5
+
6
+ # Command line interface.
7
+ class Runner
8
+
9
+ # Test runner command line interface.
10
+ #
11
+ def self.cli(*argv)
12
+ runner = new
13
+
14
+ Test::Config.load
15
+
16
+ cli_options(runner, argv)
17
+
18
+ begin
19
+ # Add standard location if it exists.
20
+ $LOAD_PATH.unshift(File.expand_path('lib')) if File.directory?('lib')
21
+
22
+ success = runner.run
23
+ exit -1 unless success
24
+ rescue => error
25
+ raise error if $DEBUG
26
+ $stderr.puts('ERROR: ' + error.to_s)
27
+ end
28
+ end
29
+
30
+ #
31
+ def self.cli_options(runner, argv)
32
+ require 'optparse'
33
+
34
+ config = Test.config.dup
35
+ config_loaded = false
36
+
37
+ common = config.delete('common')
38
+ default = config.delete('default')
39
+
40
+ common.call(runner) if common
41
+
42
+ OptionParser.new do |opt|
43
+ opt.banner = "Usage: #{$0} [options] [files ...]"
44
+
45
+ unless config.empty?
46
+ opt.separator "PRESET OPTIONS:"
47
+ config.each do |name, block|
48
+ opt.on("--#{name}") do
49
+ block.call(runner)
50
+ end
51
+ end
52
+ end
53
+
54
+ opt.separator "CONFIG OPTIONS:"
55
+
56
+ opt.on '-f', '--format NAME', 'report format' do |name|
57
+ runner.format = name
58
+ end
59
+ opt.on '-y', '--tapy', 'shortcut for -f tapy' do
60
+ runner.format = 'tapy'
61
+ end
62
+ opt.on '-j', '--tapj', 'shortcut for -f tapj' do
63
+ runner.format = 'tapj'
64
+ end
65
+
66
+ opt.on '-t', '--tag TAG', 'select tests by tag' do |tag|
67
+ runner.tags << tag
68
+ end
69
+ opt.on '-u', '--unit TAG', 'select tests by software unit' do |unit|
70
+ runner.units << unit
71
+ end
72
+ opt.on '-m', '--match TEXT', 'select tests by description' do |text|
73
+ runner.match << text
74
+ end
75
+
76
+ opt.on '-I', '--loadpath PATH', 'add to $LOAD_PATH' do |paths|
77
+ paths.split(/[:;]/).reverse_each do |path|
78
+ $LOAD_PATH.unshift path
79
+ end
80
+ end
81
+ opt.on '-r', '--require FILE', 'require file' do |file|
82
+ require file
83
+ end
84
+ opt.on '-v' , '--verbose', 'provide extra detailed report' do
85
+ runner.verbose = true
86
+ end
87
+ #opt.on('--log DIRECTORY', 'log directory'){ |dir|
88
+ # options[:log] = dir
89
+ #}
90
+ opt.on_tail("--[no-]ansi" , 'turn on/off ANSI colors'){ |v| $ansi = v }
91
+ opt.on_tail("--debug" , 'turn on debugging mode'){ $DEBUG = true }
92
+ #opt.on_tail("--about" , 'display information about lemon'){
93
+ # puts "Ruby Test v#{VERSION}"
94
+ # puts "#{COPYRIGHT}"
95
+ # exit
96
+ #}
97
+ opt.on_tail('-h', '--help', 'display this help message'){
98
+ puts opt
99
+ exit
100
+ }
101
+ end.parse!(argv)
102
+
103
+ default.call(runner) if default && !config_loaded
104
+
105
+ runner.files.replace(argv) unless argv.empty?
106
+ end
107
+
108
+ end
109
+
110
+ 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.readlines(file)
10
+ end
11
+
12
+ #
13
+ def self.from_backtrace(backtrace)
14
+ backtrace.first =~ /(.+?):(\d+(?=:|\z))/ or return ""
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,72 @@
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
+ GLOB_RC = '{.testrb,.test.rb,.test,.config/test.rb,config/test.rb}'
27
+
28
+ #
29
+ GLOB_ROOT = '{.ruby,.git,.hg}'
30
+
31
+ #
32
+ def self.load
33
+ super(rc_file) if rc_file
34
+ end
35
+
36
+ # Find rc file.
37
+ def self.rc_file
38
+ @rc_file ||= (
39
+ glob = GLOB_RC
40
+ stop = root
41
+ default = nil
42
+ dir = Dir.pwd
43
+ file = nil
44
+ loop do
45
+ file = Dir[File.join(dir, glob)].first
46
+ break file if file
47
+ break if dir == stop
48
+ dir = File.dirname(dir)
49
+ break if dir == '/'
50
+ end
51
+ file ? file : default
52
+ )
53
+ end
54
+
55
+ # Find project root.
56
+ def self.root
57
+ @root ||= (
58
+ glob = GLOB_ROOT
59
+ stop = '/'
60
+ default = Dir.pwd
61
+ dir = Dir.pwd
62
+ until dir == stop
63
+ break dir if Dir[File.join(dir, glob)].first
64
+ dir = File.dirname(dir)
65
+ end
66
+ dir == stop ? default : dir
67
+ )
68
+ end
69
+
70
+ end
71
+
72
+ end
@@ -0,0 +1,9 @@
1
+ if RUBY_VERSION < '1.9'
2
+ require 'test/core_ext/assertion'
3
+ require 'test/core_ext/exception'
4
+ require 'test/core_ext/string'
5
+ else
6
+ require_relative 'core_ext/assertion'
7
+ require_relative 'core_ext/exception'
8
+ require_relative 'core_ext/string'
9
+ 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
@@ -0,0 +1,30 @@
1
+ class String
2
+
3
+ # Preserves relative tabbing.
4
+ # The first non-empty line ends up with n spaces before nonspace.
5
+ #
6
+ # This is a Ruby Facet (http://rubyworks.github.com/facets).
7
+
8
+ def tabto(n)
9
+ if self =~ /^( *)\S/
10
+ indent(n - $1.length)
11
+ else
12
+ self
13
+ end
14
+ end unless method_defined?(:tabto)
15
+
16
+ # Indent left or right by n spaces.
17
+ # (This used to be called #tab and aliased as #indent.)
18
+ #
19
+ # This is a Ruby Facet (http://rubyworks.github.com/facets).
20
+
21
+ def indent(n, c=' ')
22
+ if n >= 0
23
+ gsub(/^/, c * n)
24
+ else
25
+ gsub(/^#{Regexp.escape(c)}{0,#{-n}}/, "")
26
+ end
27
+ end unless method_defined?(:indent)
28
+
29
+ end
30
+
data/lib/test/rake.rb ADDED
@@ -0,0 +1,120 @@
1
+ require 'rake/tasklib'
2
+
3
+ module Test
4
+
5
+ module Rake
6
+
7
+ # Define a test rake task.
8
+ #
9
+ # The `TEST` environment variable can be used to select tests
10
+ # when using the task.
11
+ #
12
+ #--
13
+ # TODO: The test task uses #fork. Maybe it should shell out instead?
14
+ # Or provide the option for either?
15
+ #++
16
+ class TestTask < ::Rake::TaskLib
17
+
18
+ # Glob patterns are used by default to select test scripts.
19
+ DEFAULT_TESTS = [
20
+ 'test/**/case_*.rb',
21
+ 'test/**/*_case.rb',
22
+ 'test/**/test_*.rb',
23
+ 'test/**/*_test.rb'
24
+ ]
25
+
26
+ # Test scripts to load. Can be a file glob.
27
+ attr_accessor :tests
28
+
29
+ # Paths to add to $LOAD_PATH.
30
+ attr_accessor :loadpath
31
+
32
+ # Scripts to load prior to loading tests.
33
+ attr_accessor :requires
34
+
35
+ # Report format to use.
36
+ attr_accessor :format
37
+
38
+ # Filter tests based by tags.
39
+ attr_accessor :tags
40
+
41
+ # Filter tests by matching description.
42
+ attr_accessor :match
43
+
44
+ #
45
+ def initialize(name='test', desc="run tests", &block)
46
+ @name = name
47
+ @desc = desc
48
+
49
+ @loadpath = ['lib']
50
+ @requires = []
51
+ @tests = [ENV['TEST'] || DEFAULT_TESTS].flatten
52
+ @format = nil
53
+ @match = nil
54
+ @tags = []
55
+
56
+ block.call(self)
57
+
58
+ define_task
59
+ end
60
+
61
+ #
62
+ def define_task
63
+ desc @desc
64
+ task @name do
65
+ @tests ||= default_tests
66
+ run
67
+ end
68
+ end
69
+
70
+ #
71
+ def run
72
+ fork {
73
+ #require 'test'
74
+ require 'test/runner'
75
+
76
+ loadpath.each { |d| $LOAD_PATH.unshift(d) }
77
+ requires.each { |f| require f }
78
+ test_files.each { |f| require f }
79
+
80
+ suite = $TEST_SUITE || []
81
+ runner = new(suite, :format=>format, :tags=>tags, :match=>match)
82
+ success = runner.run
83
+
84
+ exit -1 unless success
85
+ }
86
+ Process.wait
87
+ end
88
+
89
+ # Resolve test globs.
90
+ #--
91
+ # TODO: simplify?
92
+ #++
93
+ def test_files
94
+ files = tests
95
+ files = files.map{ |f| Dir[f] }.flatten
96
+ files = files.map{ |f| File.directory?(f) ? Dir[File.join(f, '**/*.rb')] : f }
97
+ files = files.flatten.uniq
98
+ files = files.map{ |f| File.expand_path(f) }
99
+ files
100
+ end
101
+
102
+ #
103
+ def default_tests
104
+ if ENV['tests']
105
+ ENV['tests'].split(/[:;]/)
106
+ else
107
+ DEFAULT_TESTS
108
+ end
109
+ end
110
+
111
+ #
112
+ #def ruby_command
113
+ # File.join(RbConfig::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
114
+ #end
115
+
116
+ end
117
+
118
+ end
119
+
120
+ end