test 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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