assert 2.15.0 → 2.15.1

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.
Files changed (41) hide show
  1. checksums.yaml +7 -7
  2. data/Gemfile +0 -1
  3. data/{LICENSE.txt → LICENSE} +0 -0
  4. data/README.md +106 -35
  5. data/assert.gemspec +2 -2
  6. data/lib/assert/assert_runner.rb +19 -12
  7. data/lib/assert/assertions.rb +1 -0
  8. data/lib/assert/cli.rb +3 -0
  9. data/lib/assert/config.rb +24 -6
  10. data/lib/assert/config_helpers.rb +15 -28
  11. data/lib/assert/context.rb +4 -3
  12. data/lib/assert/context/test_dsl.rb +3 -2
  13. data/lib/assert/context_info.rb +19 -0
  14. data/lib/assert/default_runner.rb +12 -0
  15. data/lib/assert/default_suite.rb +64 -0
  16. data/lib/assert/default_view.rb +17 -15
  17. data/lib/assert/file_line.rb +3 -2
  18. data/lib/assert/result.rb +6 -0
  19. data/lib/assert/runner.rb +58 -21
  20. data/lib/assert/suite.rb +61 -100
  21. data/lib/assert/test.rb +3 -3
  22. data/lib/assert/version.rb +1 -1
  23. data/lib/assert/view.rb +58 -74
  24. data/lib/assert/view_helpers.rb +10 -48
  25. data/test/helper.rb +9 -0
  26. data/test/support/factory.rb +5 -5
  27. data/test/unit/assertions/assert_raises_tests.rb +20 -0
  28. data/test/unit/config_helpers_tests.rb +29 -29
  29. data/test/unit/config_tests.rb +43 -10
  30. data/test/unit/context/suite_dsl_tests.rb +1 -1
  31. data/test/unit/context_info_tests.rb +55 -0
  32. data/test/unit/default_runner_tests.rb +18 -0
  33. data/test/unit/default_suite_tests.rb +74 -0
  34. data/test/unit/file_line_tests.rb +6 -2
  35. data/test/unit/result_tests.rb +15 -4
  36. data/test/unit/runner_tests.rb +128 -6
  37. data/test/unit/suite_tests.rb +73 -182
  38. data/test/unit/view_helpers_tests.rb +44 -38
  39. data/test/unit/view_tests.rb +15 -39
  40. metadata +42 -28
  41. data/Rakefile +0 -1
@@ -3,6 +3,7 @@ require 'assert/context/setup_dsl'
3
3
  require 'assert/context/subject_dsl'
4
4
  require 'assert/context/suite_dsl'
5
5
  require 'assert/context/test_dsl'
6
+ require 'assert/context_info'
6
7
  require 'assert/macros/methods'
7
8
  require 'assert/result'
8
9
  require 'assert/suite'
@@ -40,7 +41,7 @@ module Assert
40
41
 
41
42
  self.suite.tests << Test.for_method(
42
43
  method_name.to_s,
43
- Suite::ContextInfo.new(self, nil, caller.first),
44
+ ContextInfo.new(self, nil, caller.first),
44
45
  self.suite.config
45
46
  )
46
47
  end
@@ -116,13 +117,13 @@ module Assert
116
117
  # alter the backtraces of fail results generated in the given block
117
118
  def with_backtrace(bt, &block)
118
119
  bt ||= []
119
- current_results.count.tap do |count|
120
+ current_results.size.tap do |size|
120
121
  begin
121
122
  instance_eval(&block)
122
123
  rescue Result::TestSkipped, Result::TestFailure => e
123
124
  e.set_backtrace(bt); raise(e)
124
125
  ensure
125
- current_results[count..-1].each{ |r| r.set_backtrace(bt) }
126
+ current_results[size..-1].each{ |r| r.set_backtrace(bt) }
126
127
  end
127
128
  end
128
129
  end
@@ -1,3 +1,4 @@
1
+ require 'assert/context_info'
1
2
  require 'assert/macro'
2
3
  require 'assert/suite'
3
4
  require 'assert/test'
@@ -14,7 +15,7 @@ class Assert::Context
14
15
  # create a test from the given code block
15
16
  self.suite.tests << Assert::Test.for_block(
16
17
  desc_or_macro.kind_of?(Assert::Macro) ? desc_or_macro.name : desc_or_macro,
17
- Assert::Suite::ContextInfo.new(self, called_from, first_caller || caller.first),
18
+ Assert::ContextInfo.new(self, called_from, first_caller || caller.first),
18
19
  self.suite.config,
19
20
  &block
20
21
  )
@@ -25,7 +26,7 @@ class Assert::Context
25
26
 
26
27
  def test_eventually(desc_or_macro, called_from = nil, first_caller = nil, &block)
27
28
  # create a test from a proc that just skips
28
- ci = Assert::Suite::ContextInfo.new(self, called_from, first_caller || caller.first)
29
+ ci = Assert::ContextInfo.new(self, called_from, first_caller || caller.first)
29
30
  self.suite.tests << Assert::Test.for_block(
30
31
  desc_or_macro.kind_of?(Assert::Macro) ? desc_or_macro.name : desc_or_macro,
31
32
  ci,
@@ -0,0 +1,19 @@
1
+ module Assert
2
+
3
+ class ContextInfo
4
+
5
+ attr_reader :called_from, :klass, :file
6
+
7
+ def initialize(klass, called_from = nil, first_caller = nil)
8
+ @called_from = called_from || first_caller
9
+ @klass = klass
10
+ @file = @called_from.gsub(/\:[0-9]+.*$/, '') if @called_from
11
+ end
12
+
13
+ def test_name(name)
14
+ [klass.description.to_s, name.to_s].compact.reject(&:empty?).join(' ')
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,12 @@
1
+ require 'assert/runner'
2
+
3
+ module Assert
4
+
5
+ # This is the default runner used by assert. It adds no special behavior on
6
+ # top of the base runner's behavior
7
+
8
+ class DefaultRunner < Assert::Runner
9
+
10
+ end
11
+
12
+ end
@@ -0,0 +1,64 @@
1
+ require 'assert/suite'
2
+
3
+ module Assert
4
+
5
+ # This is the default suite used by assert. It stores test/result data in-memory.
6
+
7
+ class DefaultSuite < Assert::Suite
8
+
9
+ # Test data
10
+
11
+ def ordered_tests
12
+ self.tests
13
+ end
14
+
15
+ def reversed_tests
16
+ self.tests.reverse
17
+ end
18
+
19
+ def ordered_tests_by_run_time
20
+ self.ordered_tests.sort{ |a, b| a.run_time <=> b.run_time }
21
+ end
22
+
23
+ def reversed_tests_by_run_time
24
+ self.ordered_tests_by_run_time.reverse
25
+ end
26
+
27
+ def test_count
28
+ self.tests.size
29
+ end
30
+
31
+ # Result data
32
+
33
+ def ordered_results
34
+ self.ordered_tests.inject([]){ |results, test| results += test.results }
35
+ end
36
+
37
+ def reversed_results
38
+ self.ordered_results.reverse
39
+ end
40
+
41
+ # dump failed or errored results,
42
+ # dump skipped or ignored results if they have a message
43
+ def ordered_results_for_dump
44
+ self.ordered_results.select do |result|
45
+ [:fail, :error].include?(result.to_sym) ||
46
+ !!([:skip, :ignore].include?(result.to_sym) && result.message)
47
+ end
48
+ end
49
+
50
+ def reversed_results_for_dump
51
+ self.ordered_results_for_dump.reverse
52
+ end
53
+
54
+ def result_count(type = nil)
55
+ self.tests.inject(0){ |count, test| count += test.result_count(type) }
56
+ end
57
+
58
+ # Callbacks
59
+
60
+ # no custom callbacks
61
+
62
+ end
63
+
64
+ end
@@ -1,11 +1,13 @@
1
1
  require 'assert/view'
2
+ require 'assert/view_helpers'
2
3
 
3
4
  module Assert
4
5
 
5
6
  # This is the default view used by assert. It renders ansi test output
6
7
  # designed for terminal viewing.
7
8
 
8
- class DefaultView < Assert::View::Base
9
+ class DefaultView < Assert::View
10
+ include Assert::ViewHelpers::Ansi
9
11
 
10
12
  # setup options and their default values
11
13
 
@@ -69,7 +71,9 @@ module Assert
69
71
 
70
72
  puts "#{result_count_statement}: #{styled_results_sentence}"
71
73
  puts
72
- puts "(#{run_time} seconds, #{test_rate} tests/s, #{result_rate} results/s)"
74
+ puts "(#{formatted_run_time} seconds, " \
75
+ "#{formatted_test_rate} tests/s, " \
76
+ "#{formatted_result_rate} results/s)"
73
77
  end
74
78
 
75
79
  def on_interrupt(err)
@@ -82,22 +86,20 @@ module Assert
82
86
  print "\n"
83
87
  puts
84
88
 
85
- # output detailed results for the tests in reverse test/result order
86
- tests = config.suite.ordered_tests.reverse
87
- result_details_for(tests, :reversed).each do |details|
88
- if show_result_details?(details.result)
89
- # output the styled result details
90
- result = details.result
91
- puts ansi_styled_msg(result.to_s, result)
89
+ config.suite.reversed_results_for_dump.each do |result|
90
+ # output the styled result details
91
+ puts ansi_styled_msg(result.to_s, result)
92
92
 
93
- # output any captured stdout
94
- output = details.output
95
- puts captured_output(output) if output && !output.empty?
93
+ # output any captured stdout
94
+ puts captured_output(result.output) if result.output && !result.output.empty?
96
95
 
97
- # add an empty line between each result detail
98
- puts
99
- end
96
+ # output re-run CLI cmd
97
+ puts re_run_test_cmd(result.test_id)
98
+
99
+ # add an empty line between each result detail
100
+ puts
100
101
  end
102
+
101
103
  end
102
104
 
103
105
  end
@@ -3,7 +3,7 @@ module Assert
3
3
  class FileLine
4
4
 
5
5
  def self.parse(file_line_path)
6
- self.new(*(file_line_path.to_s.match(/(.+)\:(.+)/) || [])[1..2])
6
+ self.new(*(file_line_path.to_s.match(/(^[^\:]*)\:*(\d*)$/) || [])[1..2])
7
7
  end
8
8
 
9
9
  attr_reader :file, :line
@@ -18,7 +18,8 @@ module Assert
18
18
 
19
19
  def ==(other_file_line)
20
20
  if other_file_line.kind_of?(FileLine)
21
- self.file == other_file_line.file && self.line == other_file_line.line
21
+ self.file == other_file_line.file &&
22
+ self.line == other_file_line.line
22
23
  else
23
24
  super
24
25
  end
@@ -31,7 +31,9 @@ module Assert::Result
31
31
  def self.for_test(test, message, bt)
32
32
  self.new({
33
33
  :test_name => test.name,
34
+ :test_id => test.file_line.to_s,
34
35
  :message => message,
36
+ :output => test.output,
35
37
  :backtrace => Backtrace.new(bt)
36
38
  })
37
39
  end
@@ -43,7 +45,9 @@ module Assert::Result
43
45
  def type; @type ||= (@build_data[:type] || self.class.type).to_sym; end
44
46
  def name; @name ||= (@build_data[:name] || self.class.name.to_s); end
45
47
  def test_name; @test_name ||= (@build_data[:test_name] || ''); end
48
+ def test_id; @test_id ||= (@build_data[:test_id] || ''); end
46
49
  def message; @message ||= (@build_data[:message] || ''); end
50
+ def output; @output ||= (@build_data[:output] || ''); end
47
51
  def backtrace; @backtrace ||= (@build_data[:backtrace] || Backtrace.new([])); end
48
52
  def trace; @trace ||= (@build_data[:trace] || build_trace(self.backtrace)); end
49
53
 
@@ -62,7 +66,9 @@ module Assert::Result
62
66
  { :type => self.type,
63
67
  :name => self.name,
64
68
  :test_name => self.test_name,
69
+ :test_id => self.test_id,
65
70
  :message => self.message,
71
+ :output => self.output,
66
72
  :backtrace => self.backtrace,
67
73
  :trace => self.trace,
68
74
  }
@@ -1,5 +1,6 @@
1
1
  require 'assert/config_helpers'
2
2
  require 'assert/suite'
3
+ require 'assert/view'
3
4
 
4
5
  module Assert
5
6
 
@@ -12,40 +13,76 @@ module Assert
12
13
  @config = config
13
14
  end
14
15
 
16
+ def runner; self; end
17
+
15
18
  def run
16
- suite, view = @config.suite, @config.view
17
- raise ArgumentError if !suite.kind_of?(Suite)
18
- if tests?
19
- view.puts "Running tests in random order, seeded with \"#{runner_seed}\""
19
+ self.on_start
20
+ self.suite.on_start
21
+ self.view.on_start
22
+
23
+ if self.single_test?
24
+ self.view.puts "Running test: #{self.single_test_file_line}"
25
+ elsif self.tests?
26
+ self.view.puts "Running tests in random order, " \
27
+ "seeded with \"#{self.runner_seed}\""
20
28
  end
21
- view.fire(:on_start)
22
29
 
23
30
  begin
24
- suite.setup
25
-
26
- suite.start_time = Time.now
27
- tests_to_run(suite).each do |test|
28
- view.fire(:before_test, test)
29
- test.run{ |result| view.fire(:on_result, result) }
30
- view.fire(:after_test, test)
31
+ self.suite.start_time = Time.now
32
+ self.suite.setups.each(&:call)
33
+ tests_to_run.each do |test|
34
+ self.before_test(test)
35
+ self.suite.before_test(test)
36
+ self.view.before_test(test)
37
+ test.run do |result|
38
+ self.on_result(result)
39
+ self.suite.on_result(result)
40
+ self.view.on_result(result)
41
+ end
42
+ self.after_test(test)
43
+ self.suite.after_test(test)
44
+ self.view.after_test(test)
31
45
  end
32
- suite.end_time = Time.now
33
-
34
- suite.teardown
46
+ self.suite.teardowns.each(&:call)
47
+ self.suite.end_time = Time.now
35
48
  rescue Interrupt => err
36
- view.fire(:on_interrupt, err)
49
+ self.on_interrupt(err)
50
+ self.suite.on_interrupt(err)
51
+ self.view.on_interrupt(err)
37
52
  raise(err)
38
53
  end
39
54
 
40
- view.fire(:on_finish)
41
- suite.count(:failed) + suite.count(:errored)
55
+ (self.suite.count(:fail) + self.suite.count(:error)).tap do
56
+ self.view.on_finish
57
+ self.suite.on_finish
58
+ self.on_finish
59
+ end
42
60
  end
43
61
 
62
+ # Callbacks
63
+
64
+ # define callback handlers to do special behavior during the test run. These
65
+ # will be called by the test runner
66
+
67
+ def before_load(test_files); end
68
+ def after_load; end
69
+ def on_start; end
70
+ def before_test(test); end
71
+ def on_result(result); end
72
+ def after_test(test); end
73
+ def on_finish; end
74
+ def on_interrupt(err); end
75
+
44
76
  private
45
77
 
46
- def tests_to_run(suite)
47
- srand self.config.runner_seed
48
- suite.tests.sort.sort_by{ rand suite.tests.size }
78
+ def tests_to_run
79
+ if self.single_test?
80
+ [ self.suite.tests.find{ |t| t.file_line == self.single_test_file_line }
81
+ ].compact
82
+ else
83
+ srand self.runner_seed
84
+ self.suite.tests.sort.sort_by{ rand self.suite.tests.size }
85
+ end
49
86
  end
50
87
 
51
88
  end
@@ -1,98 +1,102 @@
1
+ require 'assert/config_helpers'
1
2
  require 'assert/test'
2
3
 
3
4
  module Assert
5
+
4
6
  class Suite
7
+ include Assert::ConfigHelpers
5
8
 
6
- TEST_METHOD_REGEX = /^test./
9
+ TEST_METHOD_REGEX = /^test./.freeze
7
10
 
8
11
  # A suite is a set of tests to run. When a test class subclasses
9
12
  # the Context class, that test class is pushed to the suite.
10
13
 
11
- attr_accessor :config, :tests, :test_methods, :start_time, :end_time
14
+ attr_reader :config, :tests, :test_methods, :setups, :teardowns
15
+ attr_accessor :start_time, :end_time
12
16
 
13
17
  def initialize(config)
14
- @config = config
15
- @tests = []
18
+ @config = config
19
+ @tests = []
16
20
  @test_methods = []
17
- @start_time = Time.now
18
- @end_time = @start_time
21
+ @setups = []
22
+ @teardowns = []
23
+ @start_time = Time.now
24
+ @end_time = @start_time
19
25
  end
20
26
 
21
- def run_time
22
- @end_time - @start_time
23
- end
27
+ def suite; self; end
24
28
 
25
- def test_rate
26
- get_rate(self.tests.size, self.run_time)
29
+ def setup(&block)
30
+ self.setups << (block || proc{})
27
31
  end
32
+ alias_method :startup, :setup
28
33
 
29
- def result_rate
30
- get_rate(self.results.size, self.run_time)
34
+ def teardown(&block)
35
+ self.teardowns << (block || proc{})
31
36
  end
37
+ alias_method :shutdown, :teardown
32
38
 
33
- alias_method :ordered_tests, :tests
39
+ def run_time
40
+ @end_time - @start_time
41
+ end
34
42
 
35
- def ordered_tests_by_run_time
36
- self.ordered_tests.sort{ |a, b| a.run_time <=> b.run_time }
43
+ def test_rate
44
+ get_rate(self.test_count, self.run_time)
37
45
  end
38
46
 
39
- def results
40
- tests.inject([]){ |results, test| results += test.results }
47
+ def result_rate
48
+ get_rate(self.result_count, self.run_time)
41
49
  end
42
- alias_method :ordered_results, :results
43
50
 
44
51
  def count(thing)
45
- case thing
46
- when :tests
52
+ if thing == :tests
47
53
  test_count
48
- when :results
54
+ elsif thing == :results
49
55
  result_count
50
- when :passed, :pass
56
+ elsif thing == :pass || thing == :passed
51
57
  result_count(:pass)
52
- when :failed, :fail
58
+ elsif thing == :fail || thing == :failed
53
59
  result_count(:fail)
54
- when :ignored, :ignore
55
- result_count(:ignore)
56
- when :skipped, :skip
57
- result_count(:skip)
58
- when :errored, :error
60
+ elsif thing == :error || thing == :errored
59
61
  result_count(:error)
62
+ elsif thing == :skip || thing == :skipped
63
+ result_count(:skip)
64
+ elsif thing == :ignore || thing == :ignored
65
+ result_count(:ignore)
60
66
  else
61
67
  0
62
68
  end
63
69
  end
64
70
 
65
- def test_count
66
- self.tests.size
67
- end
71
+ # Test data
68
72
 
69
- def result_count(type = nil)
70
- if type
71
- self.tests.inject(0) do |count, test|
72
- count += test.result_count(type)
73
- end
74
- else
75
- self.results.size
76
- end
77
- end
73
+ def ordered_tests; end
74
+ def reversed_tests; end
75
+ def ordered_tests_by_run_time; end
76
+ def reversed_tests_by_run_time; end
77
+ def test_count; end
78
78
 
79
- def setup(&block)
80
- if block_given?
81
- self.setups << block
82
- else
83
- self.setups.each{ |setup| setup.call }
84
- end
85
- end
86
- alias_method :startup, :setup
79
+ # Result data
87
80
 
88
- def teardown(&block)
89
- if block_given?
90
- self.teardowns << block
91
- else
92
- self.teardowns.reverse.each{ |teardown| teardown.call }
93
- end
94
- end
95
- alias_method :shutdown, :teardown
81
+ def ordered_results; end
82
+ def reversed_results; end
83
+ def ordered_results_for_dump; end
84
+ def reversed_results_for_dump; end
85
+ def result_count(type = nil); end
86
+
87
+ # Callbacks
88
+
89
+ # define callback handlers to do special behavior during the test run. These
90
+ # will be called by the test runner
91
+
92
+ def before_load(test_files); end
93
+ def after_load; end
94
+ def on_start; end
95
+ def before_test(test); end
96
+ def on_result(result); end
97
+ def after_test(test); end
98
+ def on_finish; end
99
+ def on_interrupt(err); end
96
100
 
97
101
  def inspect
98
102
  "#<#{self.class}:#{'0x0%x' % (object_id << 1)}"\
@@ -100,55 +104,12 @@ module Assert
100
104
  " result_count=#{self.result_count.inspect}>"
101
105
  end
102
106
 
103
- protected
104
-
105
- def setups
106
- @setups ||= []
107
- end
108
-
109
- def teardowns
110
- @teardowns ||= []
111
- end
112
-
113
- def local_public_test_methods(klass)
114
- # start with all public meths, store off the local ones
115
- methods = klass.public_instance_methods
116
- local_methods = klass.public_instance_methods(false)
117
-
118
- # remove any from the superclass
119
- while (klass.superclass)
120
- methods -= (klass = klass.superclass).public_instance_methods
121
- end
122
-
123
- # add back in the local ones (to work around super having the same methods)
124
- methods += local_methods
125
-
126
- # uniq and remove any that don't start with 'test'
127
- methods.uniq.delete_if {|method_name| method_name !~ TEST_METHOD_REGEX }
128
- end
129
-
130
107
  private
131
108
 
132
109
  def get_rate(count, time)
133
110
  time == 0 ? 0.0 : (count.to_f / time.to_f)
134
111
  end
135
112
 
136
- class ContextInfo
137
-
138
- attr_reader :called_from, :klass, :file
139
-
140
- def initialize(klass, called_from = nil, first_caller = nil)
141
- @called_from = called_from || first_caller
142
- @klass = klass
143
- @file = @called_from.gsub(/\:[0-9]+.*$/, '') if @called_from
144
- end
145
-
146
- def test_name(name)
147
- [klass.description.to_s, name.to_s].compact.reject(&:empty?).join(' ')
148
- end
149
-
150
- end
151
-
152
113
  end
153
114
 
154
115
  end