rubytest 0.4.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/.ruby CHANGED
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  source:
3
3
  - var
4
- - var/
5
4
  authors:
6
5
  - name: trans
7
6
  email: transfire@gmail.com
@@ -37,7 +36,7 @@ revision: 0
37
36
  created: '2011-07-23'
38
37
  summary: Ruby Universal Test Harness
39
38
  title: Ruby Test
40
- version: 0.4.2
39
+ version: 0.5.0
41
40
  name: rubytest
42
41
  description: ! "Ruby Test is a universal test harness for Ruby. It can handle any
43
42
  compliant \ntest framework, even running tests from multiple frameworks in a single
data/HISTORY.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # RELEASE HISTORY
2
2
 
3
+ ## 0.5.0 / 2012-03-22
4
+
5
+ This release improves the command line interface, the handling of
6
+ configuration and provides a mechinism for adding custom test
7
+ observers. The later can be used for things like mock library
8
+ verifcation steps.
9
+
10
+ Changes:
11
+
12
+ * Make CLI an actual class.
13
+ * Refactor configuration file lookup and support Confection.
14
+ * Add customizable test observer via new Advice class.
15
+
16
+
3
17
  ## 0.4.2 / 2012-03-04
4
18
 
5
19
  Minor release to fix detection of pre-existance of Exception core
File without changes
data/bin/ruby-test CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'rubytest'
3
- Test::Runner.cli(*ARGV)
3
+ Test::CLI.run(*ARGV)
4
4
 
data/bin/rubytest CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'rubytest'
3
- Test::Runner.cli(*ARGV)
3
+ Test::CLI.run(*ARGV)
4
4
 
@@ -0,0 +1,134 @@
1
+ module Test
2
+
3
+ # The Advice class is an observer that can be customized to
4
+ # initiate before, after and upon procedures for all of RubyTests
5
+ # observable points.
6
+ #
7
+ # Only one procedure is allowed per-point.
8
+ #
9
+ class Advice
10
+
11
+ #
12
+ def self.joinpoints
13
+ @joinpoints ||= []
14
+ end
15
+
16
+ # TODO: Should before and affter hooks be evaluated in the context of test
17
+ # object scope? The #scope field has been added to the RubyTest spec
18
+ # just in case.
19
+
20
+ #
21
+ def self.joinpoint(name)
22
+ joinpoints << name.to_sym
23
+
24
+ class_eval %{
25
+ def #{name}(*args)
26
+ procedure = @table[:#{name}]
27
+ procedure.call(*args) if procedure
28
+ end
29
+ }
30
+ end
31
+
32
+ #
33
+ def initialize
34
+ @table = {}
35
+ end
36
+
37
+ # @method begin_suite(suite)
38
+ joinpoint :begin_suite
39
+
40
+ # @method begin_case(case)
41
+ joinpoint :begin_case
42
+
43
+ # @method skip_test(test, reason)
44
+ joinpoint :skip_test
45
+
46
+ # @method begin_test(test)
47
+ joinpoint :begin_test
48
+
49
+ # @method pass(test)
50
+ joinpoint :pass
51
+
52
+ # @method fail(test, exception)
53
+ joinpoint :fail
54
+
55
+ # @method error(test, exception)
56
+ joinpoint :error
57
+
58
+ # @method todo(test, exception)
59
+ joinpoint :todo
60
+
61
+ # @method end_test(test)
62
+ joinpoint :end_test
63
+
64
+ # @method end_case(case)
65
+ joinpoint :end_case
66
+
67
+ # @method end_suite(suite)
68
+ joinpoint :end_suite
69
+
70
+ #
71
+ #def [](key)
72
+ # @table[key.to_sym]
73
+ #end
74
+
75
+ # Add a procedure to one of the join-points.
76
+ def join(type, &block)
77
+ type = valid_type(type)
78
+ @table[type] = block
79
+ end
80
+
81
+ # Add a procedure to one of the before join-points.
82
+ def join_before(type, &block)
83
+ join("begin_#{type}", &block)
84
+ end
85
+
86
+ # Add a procedure to one of the after join-points.
87
+ def join_after(type, &block)
88
+ join("end_#{type}", &block)
89
+ end
90
+
91
+ # Ignore any other signals (precautionary).
92
+ def method_missing(*)
93
+ end
94
+
95
+ private
96
+
97
+ #def invoke(symbol, *args)
98
+ # if @table.key?(symbol)
99
+ # self[symbol].call(*args)
100
+ # end
101
+ #end
102
+
103
+ #
104
+ def valid_type(type)
105
+ type = message_type(type)
106
+ unless self.class.joinpoints.include?(type)
107
+ raise ArgumentError, "not a valid advice type -- #{type}"
108
+ end
109
+ type
110
+ end
111
+
112
+ #
113
+ def message_type(type)
114
+ type = type.to_sym
115
+ case type
116
+ when :each
117
+ type = :test
118
+ when :all
119
+ type = :case
120
+ when :begin_each
121
+ type = :begin_test
122
+ when :begin_all
123
+ type = :begin_case
124
+ when :end_each
125
+ type = :end_test
126
+ when :end_all
127
+ type = :end_case
128
+ end
129
+ return type
130
+ end
131
+
132
+ end
133
+
134
+ end
data/lib/rubytest/cli.rb CHANGED
@@ -1,16 +1,51 @@
1
1
  module Test
2
2
 
3
- # Command line interface.
4
- class Runner
3
+ # Command line interface to test runner.
4
+ #
5
+ class CLI
5
6
 
6
- # Test runner command line interface.
7
7
  #
8
- def self.cli(*argv)
9
- runner = Runner.new
8
+ # Convenience method for invoking the CLI.
9
+ #
10
+ def self.run(*argv)
11
+ new.run(*argv)
12
+ end
13
+
14
+ #
15
+ # Initialize CLI instance.
16
+ #
17
+ def initialize
18
+ require 'optparse'
10
19
 
11
20
  Test::Config.load
12
21
 
13
- cli_options(runner, argv)
22
+ @profile = 'default'
23
+ @config = Test.config
24
+ @runner = Runner.new
25
+ end
26
+
27
+ #
28
+ # @return [Runner]
29
+ #
30
+ attr :runner
31
+
32
+ #
33
+ # @return [Hash]
34
+ #
35
+ attr :config
36
+
37
+ #
38
+ attr_accessor :profile
39
+
40
+ #
41
+ # Run tests.
42
+ #
43
+ def run(*argv)
44
+ options.parse!(argv)
45
+
46
+ run_profile
47
+
48
+ runner.files.replace(argv) unless argv.empty?
14
49
 
15
50
  Test::Config.load_path_setup #unless runner.autopath == false
16
51
 
@@ -24,31 +59,43 @@ module Test
24
59
  end
25
60
 
26
61
  #
27
- def self.cli_options(runner, argv)
28
- require 'optparse'
62
+ # Run the common profile if defined and then the specific
63
+ # profile.
64
+ #
65
+ def run_profile
66
+ raise "no such profile -- #{profile}" unless config[profile] or profile == 'default'
29
67
 
30
- config = Test.config.dup
31
- config_loaded = false
68
+ common = config['common']
69
+ common.call(runner) if common
32
70
 
33
- common = config.delete('common')
34
- default = config.delete('default')
71
+ profig = config[profile]
72
+ profig.call(runner) if profig
73
+ end
35
74
 
36
- common.call(runner) if common
75
+ #
76
+ # Setup OptionsParser instance.
77
+ #
78
+ def options
79
+ this = self
37
80
 
38
81
  OptionParser.new do |opt|
39
82
  opt.banner = "Usage: #{$0} [options] [files ...]"
40
83
 
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
84
+ opt.separator "PRESET OPTIONS:"
85
+
86
+ opt.on '-p', '--profile NAME', "use configuration profile" do |name|
87
+ this.profile = name.to_s
88
+ end
89
+
90
+ config_names = config.keys - ['common', 'default']
91
+
92
+ unless config_names.empty?
93
+ config_names.each do |name|
94
+ opt.separator((" " * 40) + "* #{name}")
47
95
  end
48
96
  end
49
97
 
50
98
  opt.separator "CONFIG OPTIONS:"
51
-
52
99
  opt.on '-f', '--format NAME', 'report format' do |name|
53
100
  runner.format = name
54
101
  end
@@ -83,22 +130,20 @@ module Test
83
130
  #opt.on('--log DIRECTORY', 'log directory'){ |dir|
84
131
  # options[:log] = dir
85
132
  #}
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'){
133
+ opt.on("--[no-]ansi" , 'turn on/off ANSI colors'){ |v| $ansi = v }
134
+ opt.on("--debug" , 'turn on debugging mode'){ $DEBUG = true }
135
+
136
+ opt.separator "COMMAND OPTIONS:"
137
+ #opt.on("--about" , 'display information about rubytest'){
89
138
  # puts "Ruby Test v#{VERSION}"
90
139
  # puts "#{COPYRIGHT}"
91
140
  # exit
92
141
  #}
93
- opt.on_tail('-h', '--help', 'display this help message'){
142
+ opt.on('-h', '--help', 'display this help message'){
94
143
  puts opt
95
144
  exit
96
145
  }
97
- end.parse!(argv)
98
-
99
- default.call(runner) if default && !config_loaded
100
-
101
- runner.files.replace(argv) unless argv.empty?
146
+ end
102
147
  end
103
148
 
104
149
  end
@@ -1,57 +1,104 @@
1
1
  module Test
2
2
 
3
3
  #
4
- def self.run(name=:default, &block)
4
+ def self.run(name=nil, &block)
5
+ name = name ? name : 'default'
6
+
5
7
  @config ||= {}
6
8
  @config[name.to_s] = block
7
9
  end
8
10
 
11
+ #
9
12
  def self.config
10
13
  @config ||= {}
11
14
  end
12
15
 
16
+ # Handle test run configruation.
17
+ #
18
+ # @todo Why not use the instace level for `Test.config` ?
13
19
  #
14
20
  class Config
15
21
 
16
- # Test configuration file.
22
+ # Tradional test configuration file glob. This glob
23
+ # looks for a `Testfile` or a `.test` file.
24
+ # Either can have an optional `.rb` extension.
25
+ GLOB_RC = '{testfile.rb,testfile,.test.rb,.test}'
26
+
27
+ # If a root level test file can't be found, then use this
28
+ # glob to search the task directory for `*.rubytest` files.
29
+ GLOB_TASK = 'task/*.rubytest'
30
+
31
+ # Glob used to find project root directory.
32
+ GLOB_ROOT = '{.ruby,.git,.hg,_darcs,lib/}'
33
+
17
34
  #
18
- # The name of the file is an ode to the original Ruby cli test tool.
35
+ # Load configuration. This will first look for a root level `Testfile.rb`
36
+ # or `.test.rb` file. Failing that it will look for `task/*.rubytest` files.
37
+ # An example entry into any of these look like:
19
38
  #
20
- # @example
21
- # .test
22
- # .testrb
23
- # .test.rb
24
- # .config/test.rb
39
+ # Test.run :name do |run|
40
+ # run.files << 'test/case_*.rb'
41
+ # end
25
42
  #
26
- # @todo Too many options for ruby-test configuration file.
27
- GLOB_RC = '{.testrb,.test.rb,.test,.config/test.rb,config/test.rb}'
28
-
43
+ # Use `:default` for name for non-specific profile and `:common` for code that
44
+ # should apply to all configurations.
29
45
  #
30
- GLOB_ROOT = '{.ruby,.git,.hg}'
31
-
46
+ # Failing any traditional configuration files, the Confection system will
47
+ # be used. An example entry in a projects `Confile` is:
48
+ #
49
+ # config :test, :name do |run|
50
+ # run.files << 'test/case_*.rb'
51
+ # end
52
+ #
53
+ # You can leave the `:name` parameter out for `:default`.
32
54
  #
33
55
  def self.load
34
- super(rc_file) if rc_file
35
- #Ruth.module_eval(File.read(rc_file)) if rc_file
56
+ if rc_files.empty?
57
+ if confection_file
58
+ require 'confection'
59
+ confection('test', '*').each do |c|
60
+ name = c.profile ? c.profile : :default
61
+ Test.run(name, &c)
62
+ end
63
+ end
64
+ else
65
+ rc_files.each do |file|
66
+ super(file)
67
+ end
68
+ end
69
+ end
70
+
71
+ #
72
+ def self.confection_file
73
+ @confection_file ||= (
74
+ Dir.glob(File.join(root, '{,.}confile{,.rb}'), File::FNM_CASEFOLD).first
75
+ )
36
76
  end
37
77
 
38
78
  # 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 == '/'
79
+ def self.rc_files
80
+ @rc_files ||= (
81
+ if file = Dir.glob(File.join(root, GLOB_RC), File::FNM_CASEFOLD).first
82
+ [file]
83
+ else
84
+ Dir.glob(File.join(root, GLOB_TASK))
52
85
  end
53
- file ? file : default
54
86
  )
87
+
88
+ # glob = GLOB_RC
89
+ # stop = root
90
+ # default = nil
91
+ # dir = Dir.pwd
92
+ # file = nil
93
+ # loop do
94
+ # files = Dir.glob(File.join(dir, glob), File::FNM_CASEFOLD)
95
+ # file = files.find{ |f| File.file?(f) }
96
+ # break file if file
97
+ # break if dir == stop
98
+ # dir = File.dirname(dir)
99
+ # break if dir == '/'
100
+ # end
101
+ # file ? file : default
55
102
  end
56
103
 
57
104
  # Find and cache project root directory.
@@ -14,8 +14,8 @@ module Test
14
14
  end
15
15
 
16
16
  #
17
- def skip(test)
18
- self[:skip] << test
17
+ def skip_test(test, reason)
18
+ self[:skip] << [test, reason]
19
19
  end
20
20
 
21
21
  # Add `test` to pass set.
@@ -35,9 +35,9 @@ module Test
35
35
  self[:todo] << [test, exception]
36
36
  end
37
37
 
38
- def omit(test, exception)
39
- self[:omit] << [test, exception]
40
- end
38
+ #def omit(test, exception)
39
+ # self[:omit] << [test, exception]
40
+ #end
41
41
 
42
42
  # Returns true if their are no test errors or failures.
43
43
  def success?
@@ -63,7 +63,7 @@ module Test
63
63
  def fail(test, exception)
64
64
  end
65
65
 
66
- #
66
+ # Report a test error.
67
67
  def error(test, exception)
68
68
  end
69
69
 
@@ -71,10 +71,6 @@ module Test
71
71
  def todo(test, exception)
72
72
  end
73
73
 
74
- # Report an omitted test.
75
- def omit(test, exception)
76
- end
77
-
78
74
  #
79
75
  def end_test(test)
80
76
  end
@@ -5,6 +5,10 @@ module Test::Reporters
5
5
  # Simple Dot-Progress Reporter
6
6
  class Dotprogress < Abstract
7
7
 
8
+ def skip_test(unit, reason)
9
+ print "S".ansi(:cyan) if runner.verbose?
10
+ end
11
+
8
12
  def pass(unit)
9
13
  print "."
10
14
  $stdout.flush
@@ -25,11 +29,6 @@ module Test::Reporters
25
29
  $stdout.flush
26
30
  end
27
31
 
28
- def omit(unit, exception)
29
- print "O".ansi(:cyan)
30
- $stdout.flush
31
- end
32
-
33
32
  def end_suite(suite)
34
33
  puts; puts
35
34
  puts timestamp
@@ -37,12 +36,10 @@ module Test::Reporters
37
36
 
38
37
  if runner.verbose?
39
38
  unless record[:omit].empty?
40
- puts "OMISSIONS\n\n"
41
- record[:omit].each do |test, exception|
39
+ puts "SKIPPED\n\n"
40
+ record[:skip].each do |test, reason|
42
41
  puts " #{test}".ansi(:bold)
43
- puts " #{exception}"
44
- puts " #{file_and_line(exception)}"
45
- #puts code(exception)
42
+ puts " #{reason}" if String===reason
46
43
  puts
47
44
  end
48
45
  end
@@ -113,6 +113,29 @@ module Test
113
113
  @hard = !!boolean
114
114
  end
115
115
 
116
+ # Instance of Advice is a special customizable observer.
117
+ def advice
118
+ @advice
119
+ end
120
+
121
+ # Define universal before advice.
122
+ def before(type, &block)
123
+ advice.join_before(type, &block)
124
+ end
125
+
126
+ # Define universal after advice. Can be used by mock libraries,
127
+ # for example to run mock verification.
128
+ def after(type, &block)
129
+ advice.join_after(type, &block)
130
+ end
131
+
132
+ # Define universal upon advice.
133
+ #
134
+ # See {Advice} for valid join-points.
135
+ def upon(type, &block)
136
+ advice.join(type, &block)
137
+ end
138
+
116
139
  # New Runner.
117
140
  #
118
141
  # @param [Array] suite
@@ -128,13 +151,15 @@ module Test
128
151
  @verbose = options[:verbose] || self.class.verbose
129
152
  @hard = options[:hard] || self.class.hard
130
153
 
154
+ @advice = Advice.new
155
+
131
156
  block.call(self) if block
132
157
  end
133
158
 
134
159
  # The reporter to use for ouput.
135
160
  attr :reporter
136
161
 
137
- # Record pass, fail, error, pending and omitted tests.
162
+ # Record pass, fail, error and pending tests.
138
163
  attr :recorder
139
164
 
140
165
  # Array of observers, typically this just contains the recorder and
@@ -155,7 +180,8 @@ module Test
155
180
 
156
181
  @reporter = reporter_load(format)
157
182
  @recorder = Recorder.new
158
- @observers = [@reporter, @recorder]
183
+
184
+ @observers = [advice, @recorder, @reporter]
159
185
 
160
186
  #cd_tmp do
161
187
  observers.each{ |o| o.begin_suite(suite) }
@@ -196,8 +222,8 @@ module Test
196
222
  # Run a test case.
197
223
  #
198
224
  def run_case(tcase)
199
- if tcase.respond_to?(:skip?) && tcase.skip?
200
- return observers.each{ |o| o.skip_case(tcase) }
225
+ if tcase.respond_to?(:skip?) && (reason = tcase.skip?)
226
+ return observers.each{ |o| o.skip_case(tcase, reason) }
201
227
  end
202
228
 
203
229
  observers.each{ |o| o.begin_case(tcase) }
@@ -219,8 +245,8 @@ module Test
219
245
  # The test to run, must repsond to #call.
220
246
  #
221
247
  def run_test(test)
222
- if test.respond_to?(:skip?) && test.skip?
223
- return observers.each{ |o| o.skip_test(test) }
248
+ if test.respond_to?(:skip?) && (reason = test.skip?)
249
+ return observers.each{ |o| o.skip_test(test, reason) }
224
250
  end
225
251
 
226
252
  observers.each{ |o| o.begin_test(test) }
data/lib/rubytest.rb CHANGED
@@ -11,6 +11,7 @@ if RUBY_VERSION < '1.9'
11
11
  require 'rubytest/code_snippet'
12
12
  require 'rubytest/config'
13
13
  require 'rubytest/recorder'
14
+ require 'rubytest/advice'
14
15
  require 'rubytest/runner'
15
16
  require 'rubytest/cli'
16
17
  require 'rubytest/reporters/abstract'
@@ -18,8 +19,9 @@ if RUBY_VERSION < '1.9'
18
19
  else
19
20
  require_relative 'rubytest/core_ext'
20
21
  require_relative 'rubytest/code_snippet'
21
- require_relative 'rubytest/recorder'
22
22
  require_relative 'rubytest/config'
23
+ require_relative 'rubytest/recorder'
24
+ require_relative 'rubytest/advice'
23
25
  require_relative 'rubytest/runner'
24
26
  require_relative 'rubytest/cli'
25
27
  require_relative 'rubytest/reporters/abstract'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubytest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.5.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-04 00:00:00.000000000 Z
12
+ date: 2012-03-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ansi
16
- requirement: &20859580 !ruby/object:Gem::Requirement
16
+ requirement: &14620080 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *20859580
24
+ version_requirements: *14620080
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: detroit
27
- requirement: &20856920 !ruby/object:Gem::Requirement
27
+ requirement: &14639980 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *20856920
35
+ version_requirements: *14639980
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: qed
38
- requirement: &20879280 !ruby/object:Gem::Requirement
38
+ requirement: &14638520 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *20879280
46
+ version_requirements: *14638520
47
47
  description: ! "Ruby Test is a universal test harness for Ruby. It can handle any
48
48
  compliant \ntest framework, even running tests from multiple frameworks in a single
49
49
  pass."
@@ -54,18 +54,18 @@ executables:
54
54
  - rubytest
55
55
  extensions: []
56
56
  extra_rdoc_files:
57
+ - LICENSE.txt
57
58
  - HISTORY.md
58
59
  - README.md
59
- - NOTICE.md
60
60
  files:
61
61
  - .ruby
62
- - .test
63
62
  - bin/ruby-test
64
63
  - bin/rubytest
65
64
  - demo/01_test.md
66
65
  - demo/02_case.md
67
66
  - demo/applique/ae.rb
68
67
  - demo/applique/rubytest.rb
68
+ - lib/rubytest/advice.rb
69
69
  - lib/rubytest/autorun.rb
70
70
  - lib/rubytest/cli.rb
71
71
  - lib/rubytest/code_snippet.rb
@@ -93,9 +93,9 @@ files:
93
93
  - lib/test.rb
94
94
  - test/basic_case.rb
95
95
  - Gemfile.lock
96
+ - LICENSE.txt
96
97
  - HISTORY.md
97
98
  - README.md
98
- - NOTICE.md
99
99
  homepage: http://rubyworks.github.com/rubytest
100
100
  licenses:
101
101
  - BSD-2-Clause
data/.test DELETED
@@ -1,11 +0,0 @@
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
-