rsanheim-micronaut 0.1.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. data/LICENSE +45 -0
  2. data/README +17 -0
  3. data/RSPEC-LICENSE +23 -0
  4. data/Rakefile +83 -0
  5. data/bin/micronaut +4 -0
  6. data/examples/example_helper.rb +36 -0
  7. data/examples/lib/micronaut/behaviour_example.rb +188 -0
  8. data/examples/lib/micronaut/configuration_example.rb +70 -0
  9. data/examples/lib/micronaut/example_example.rb +46 -0
  10. data/examples/lib/micronaut/expectations/extensions/object_example.rb +72 -0
  11. data/examples/lib/micronaut/expectations/fail_with_example.rb +17 -0
  12. data/examples/lib/micronaut/expectations/wrap_expectation_example.rb +31 -0
  13. data/examples/lib/micronaut/formatters/base_formatter_example.rb +107 -0
  14. data/examples/lib/micronaut/formatters/documentation_formatter_example.rb +5 -0
  15. data/examples/lib/micronaut/formatters/progress_formatter_example.rb +74 -0
  16. data/examples/lib/micronaut/kernel_extensions_example.rb +13 -0
  17. data/examples/lib/micronaut/matchers/be_close_example.rb +52 -0
  18. data/examples/lib/micronaut/matchers/be_example.rb +298 -0
  19. data/examples/lib/micronaut/matchers/change_example.rb +360 -0
  20. data/examples/lib/micronaut/matchers/description_generation_example.rb +175 -0
  21. data/examples/lib/micronaut/matchers/eql_example.rb +35 -0
  22. data/examples/lib/micronaut/matchers/equal_example.rb +35 -0
  23. data/examples/lib/micronaut/matchers/handler_example.rb +153 -0
  24. data/examples/lib/micronaut/matchers/has_example.rb +71 -0
  25. data/examples/lib/micronaut/matchers/have_example.rb +575 -0
  26. data/examples/lib/micronaut/matchers/include_example.rb +103 -0
  27. data/examples/lib/micronaut/matchers/match_example.rb +43 -0
  28. data/examples/lib/micronaut/matchers/matcher_methods_example.rb +66 -0
  29. data/examples/lib/micronaut/matchers/operator_matcher_example.rb +189 -0
  30. data/examples/lib/micronaut/matchers/raise_error_example.rb +346 -0
  31. data/examples/lib/micronaut/matchers/respond_to_example.rb +54 -0
  32. data/examples/lib/micronaut/matchers/satisfy_example.rb +36 -0
  33. data/examples/lib/micronaut/matchers/simple_matcher_example.rb +93 -0
  34. data/examples/lib/micronaut/matchers/throw_symbol_example.rb +96 -0
  35. data/examples/lib/micronaut/runner_example.rb +5 -0
  36. data/examples/lib/micronaut/runner_options_example.rb +5 -0
  37. data/examples/lib/micronaut/world_example.rb +102 -0
  38. data/examples/lib/micronaut_example.rb +23 -0
  39. data/examples/resources/example_classes.rb +67 -0
  40. data/lib/autotest/discover.rb +3 -0
  41. data/lib/autotest/micronaut.rb +47 -0
  42. data/lib/micronaut/behaviour.rb +211 -0
  43. data/lib/micronaut/configuration.rb +133 -0
  44. data/lib/micronaut/example.rb +28 -0
  45. data/lib/micronaut/expectations/extensions/object.rb +62 -0
  46. data/lib/micronaut/expectations/extensions/string_and_symbol.rb +19 -0
  47. data/lib/micronaut/expectations/handler.rb +52 -0
  48. data/lib/micronaut/expectations/wrap_expectation.rb +57 -0
  49. data/lib/micronaut/expectations.rb +46 -0
  50. data/lib/micronaut/formatters/base_formatter.rb +82 -0
  51. data/lib/micronaut/formatters/base_text_formatter.rb +148 -0
  52. data/lib/micronaut/formatters/documentation_formatter.rb +62 -0
  53. data/lib/micronaut/formatters/progress_formatter.rb +36 -0
  54. data/lib/micronaut/formatters.rb +12 -0
  55. data/lib/micronaut/kernel_extensions.rb +11 -0
  56. data/lib/micronaut/matchers/be.rb +204 -0
  57. data/lib/micronaut/matchers/be_close.rb +22 -0
  58. data/lib/micronaut/matchers/change.rb +148 -0
  59. data/lib/micronaut/matchers/eql.rb +26 -0
  60. data/lib/micronaut/matchers/equal.rb +26 -0
  61. data/lib/micronaut/matchers/generated_descriptions.rb +36 -0
  62. data/lib/micronaut/matchers/has.rb +19 -0
  63. data/lib/micronaut/matchers/have.rb +153 -0
  64. data/lib/micronaut/matchers/include.rb +80 -0
  65. data/lib/micronaut/matchers/match.rb +22 -0
  66. data/lib/micronaut/matchers/method_missing.rb +9 -0
  67. data/lib/micronaut/matchers/operator_matcher.rb +50 -0
  68. data/lib/micronaut/matchers/raise_error.rb +128 -0
  69. data/lib/micronaut/matchers/respond_to.rb +50 -0
  70. data/lib/micronaut/matchers/satisfy.rb +50 -0
  71. data/lib/micronaut/matchers/simple_matcher.rb +135 -0
  72. data/lib/micronaut/matchers/throw_symbol.rb +108 -0
  73. data/lib/micronaut/matchers.rb +148 -0
  74. data/lib/micronaut/mocking/with_absolutely_nothing.rb +11 -0
  75. data/lib/micronaut/mocking/with_mocha.rb +13 -0
  76. data/lib/micronaut/mocking/with_rr.rb +24 -0
  77. data/lib/micronaut/mocking.rb +7 -0
  78. data/lib/micronaut/runner.rb +57 -0
  79. data/lib/micronaut/runner_options.rb +33 -0
  80. data/lib/micronaut/world.rb +75 -0
  81. data/lib/micronaut.rb +37 -0
  82. metadata +149 -0
@@ -0,0 +1,133 @@
1
+ module Micronaut
2
+
3
+ class Configuration
4
+ # Destired mocking framework - expects the symbol name of the framework
5
+ # Currently supported: :mocha, :rr, or nothing (the default if this is not set at all)
6
+ attr_reader :mock_framework
7
+
8
+ # Array of regular expressions to scrub from backtrace
9
+ attr_reader :backtrace_clean_patterns
10
+
11
+ # An array of arrays to store before and after blocks
12
+ attr_reader :before_and_afters
13
+
14
+ # Filters allow you to exclude or include certain examples from running based on options you pass in
15
+ attr_reader :filters
16
+
17
+ # When this is true, if you have filters enabled and no examples match, all examples are added and run - defaults to true
18
+ attr_accessor :run_all_when_everything_filtered
19
+
20
+ # Enable profiling of the top 10 slowest examples - defaults to false
21
+ attr_accessor :profile_examples
22
+
23
+ def initialize
24
+ @backtrace_clean_patterns = [/\/lib\/ruby\//, /bin\/rcov:/, /vendor\/rails/]
25
+ @profile_examples = false
26
+ @run_all_when_everything_filtered = true
27
+ @filters = []
28
+ @before_and_afters = []
29
+ end
30
+
31
+ def cleaned_from_backtrace?(line)
32
+ return true if line.starts_with?(::Micronaut::InstallDirectory)
33
+
34
+ @backtrace_clean_patterns.any? do |pattern|
35
+ line =~ pattern
36
+ end
37
+ end
38
+
39
+ def mock_with(make_a_mockery_with=nil)
40
+ @mock_framework = case make_a_mockery_with
41
+ when :mocha
42
+ require 'micronaut/mocking/with_mocha'
43
+ Micronaut::Mocking::WithMocha
44
+ when :rr
45
+ require 'micronaut/mocking/with_rr'
46
+ Micronaut::Mocking::WithRR
47
+ else
48
+ Micronaut::Mocking::WithAbsolutelyNothing
49
+ end
50
+
51
+ Micronaut::Behaviour.send(:include, @mock_framework)
52
+ end
53
+
54
+ def autorun!
55
+ Micronaut::Runner.autorun unless Micronaut::Runner.installed_at_exit?
56
+ end
57
+
58
+ def options=(new_options)
59
+ raise ArguementError unless new_options.is_a?(Micronaut::RunnerOptions)
60
+ @options = new_options
61
+ end
62
+
63
+ def options
64
+ # Do we need this?
65
+ @options ||= Micronaut::RunnerOptions.new(:color => true, :formatter => :documentation)
66
+ end
67
+
68
+ def extra_modules
69
+ @extra_modules ||= []
70
+ end
71
+
72
+ def include(module_to_include, options={})
73
+ extra_modules << [:include, module_to_include, options]
74
+ end
75
+
76
+ def extend(module_to_extend, options={})
77
+ extra_modules << [:extend, module_to_extend, options]
78
+ end
79
+
80
+ def find_modules(group)
81
+ extra_modules.select do |include_or_extend, mod, options|
82
+ options.all? do |key, value|
83
+ case value
84
+ when Hash
85
+ value.all? { |k, v| group.metadata[key][k] == v }
86
+ when Regexp
87
+ group.metadata[key] =~ value
88
+ when Proc
89
+ value.call(group.metadata[key]) rescue false
90
+ else
91
+ group.metadata[key] == value
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ def add_filter(options={})
98
+ filters << options
99
+ end
100
+
101
+ def run_all_when_everything_filtered?
102
+ @run_all_when_everything_filtered
103
+ end
104
+
105
+ def before(type=:each, options={}, &block)
106
+ before_and_afters << [:before, :each, options, block]
107
+ end
108
+
109
+ def after(type=:each, options={}, &block)
110
+ before_and_afters << [:after, :each, options, block]
111
+ end
112
+
113
+ def find_before_or_after(desired_type, desired_each_or_all, group)
114
+ before_and_afters.select do |type, each_or_all, options, block|
115
+ type == desired_type && each_or_all == desired_each_or_all &&
116
+ options.all? do |key, value|
117
+ case value
118
+ when Hash
119
+ value.all? { |k, v| group.metadata[key][k] == v }
120
+ when Regexp
121
+ group.metadata[key] =~ value
122
+ when Proc
123
+ value.call(group.metadata[key]) rescue false
124
+ else
125
+ group.metadata[key] == value
126
+ end
127
+ end
128
+ end.map { |type, each_or_all, options, block| block }
129
+ end
130
+
131
+ end
132
+
133
+ end
@@ -0,0 +1,28 @@
1
+ module Micronaut
2
+
3
+ class Example
4
+
5
+ attr_reader :behaviour, :description, :options, :example_block
6
+
7
+ def initialize(behaviour, desc, options, example_block=nil)
8
+ @behaviour, @description, @options, @example_block = behaviour, desc, options, example_block
9
+ end
10
+
11
+ def metadata
12
+ @metadata ||= behaviour.metadata.dup
13
+ @metadata[:description] = description
14
+ @metadata[:options].update(options)
15
+ @metadata
16
+ end
17
+
18
+ def inspect
19
+ "#{behaviour.name} - #{description}"
20
+ end
21
+
22
+ def to_s
23
+ inspect
24
+ end
25
+
26
+ end
27
+
28
+ end
@@ -0,0 +1,62 @@
1
+ module Micronaut
2
+ module Expectations
3
+ # rspec adds #should and #should_not to every Object (and, implicitly, every Class).
4
+ module ObjectExpectations
5
+ # :call-seq:
6
+ # should(matcher)
7
+ # should == expected
8
+ # should === expected
9
+ # should =~ expected
10
+ #
11
+ # receiver.should(matcher)
12
+ # => Passes if matcher.matches?(receiver)
13
+ #
14
+ # receiver.should == expected #any value
15
+ # => Passes if (receiver == expected)
16
+ #
17
+ # receiver.should === expected #any value
18
+ # => Passes if (receiver === expected)
19
+ #
20
+ # receiver.should =~ regexp
21
+ # => Passes if (receiver =~ regexp)
22
+ #
23
+ # See Micronaut::Matchers for more information about matchers
24
+ #
25
+ # == Warning
26
+ #
27
+ # NOTE that this does NOT support receiver.should != expected.
28
+ # Instead, use receiver.should_not == expected
29
+ def should(matcher=nil, &block)
30
+ ExpectationMatcherHandler.handle_matcher(self, matcher, &block)
31
+ end
32
+
33
+ # :call-seq:
34
+ # should_not(matcher)
35
+ # should_not == expected
36
+ # should_not === expected
37
+ # should_not =~ expected
38
+ #
39
+ # receiver.should_not(matcher)
40
+ # => Passes unless matcher.matches?(receiver)
41
+ #
42
+ # receiver.should_not == expected
43
+ # => Passes unless (receiver == expected)
44
+ #
45
+ # receiver.should_not === expected
46
+ # => Passes unless (receiver === expected)
47
+ #
48
+ # receiver.should_not =~ regexp
49
+ # => Passes unless (receiver =~ regexp)
50
+ #
51
+ # See Micronaut::Matchers for more information about matchers
52
+ def should_not(matcher=nil, &block)
53
+ NegativeExpectationMatcherHandler.handle_matcher(self, matcher, &block)
54
+ end
55
+
56
+ end
57
+ end
58
+ end
59
+
60
+ class Object
61
+ include Micronaut::Expectations::ObjectExpectations
62
+ end
@@ -0,0 +1,19 @@
1
+ module Micronaut
2
+ module Expectations
3
+ module StringHelpers
4
+
5
+ def starts_with?(prefix)
6
+ to_s[0..(prefix.to_s.length - 1)] == prefix.to_s
7
+ end
8
+
9
+ end
10
+ end
11
+ end
12
+
13
+ class String
14
+ include Micronaut::Expectations::StringHelpers
15
+ end
16
+
17
+ class Symbol
18
+ include Micronaut::Expectations::StringHelpers
19
+ end
@@ -0,0 +1,52 @@
1
+ module Micronaut
2
+ module Expectations
3
+ class InvalidMatcherError < ArgumentError; end
4
+
5
+ class ExpectationMatcherHandler
6
+
7
+ def self.handle_matcher(actual, matcher, &block)
8
+ ::Micronaut::Matchers.last_should = "should"
9
+ return Micronaut::Matchers::PositiveOperatorMatcher.new(actual) if matcher.nil?
10
+
11
+ unless matcher.respond_to?(:matches?)
12
+ raise InvalidMatcherError, "Expected a matcher, got #{matcher.inspect}."
13
+ end
14
+
15
+ match = matcher.matches?(actual, &block)
16
+ ::Micronaut::Matchers.last_matcher = matcher
17
+ Micronaut::Expectations.fail_with(matcher.failure_message) unless match
18
+ match
19
+ end
20
+
21
+ end
22
+
23
+ class NegativeExpectationMatcherHandler
24
+
25
+ def self.handle_matcher(actual, matcher, &block)
26
+ ::Micronaut::Matchers.last_should = "should not"
27
+ return Micronaut::Matchers::NegativeOperatorMatcher.new(actual) if matcher.nil?
28
+
29
+ unless matcher.respond_to?(:matches?)
30
+ raise InvalidMatcherError, "Expected a matcher, got #{matcher.inspect}."
31
+ end
32
+
33
+ unless matcher.respond_to?(:negative_failure_message)
34
+ Micronaut::Expectations.fail_with(
35
+ <<-EOF
36
+ Matcher does not support should_not.
37
+ See Micronaut::Matchers for more information
38
+ about matchers.
39
+ EOF
40
+ )
41
+ end
42
+ match = matcher.matches?(actual, &block)
43
+ ::Micronaut::Matchers.last_matcher = matcher
44
+ Micronaut::Expectations.fail_with(matcher.negative_failure_message) if match
45
+ match
46
+ end
47
+
48
+ end
49
+
50
+ end
51
+ end
52
+
@@ -0,0 +1,57 @@
1
+ module Micronaut
2
+ module Matchers
3
+
4
+ # wraps an expectation in a block that will return true if the
5
+ # expectation passes and false if it fails (without bubbling up
6
+ # the failure).
7
+ #
8
+ # This is intended to be used in the context of a simple matcher,
9
+ # and is especially useful for wrapping multiple expectations or
10
+ # one or more assertions from test/unit extensions when running
11
+ # with test/unit.
12
+ #
13
+ # == Examples
14
+ #
15
+ # def eat_cheese(cheese)
16
+ # simple_matcher do |mouse, matcher|
17
+ # matcher.negative_failure_message = "expected #{mouse} not to eat cheese"
18
+ # wrap_expectation do |matcher|
19
+ # assert_eats_cheese(mouse)
20
+ # end
21
+ # end
22
+ # end
23
+ #
24
+ # describe Mouse do
25
+ # it "eats cheese" do
26
+ # Mouse.new.should eat_cheese
27
+ # end
28
+ # end
29
+ #
30
+ # You might be wondering "why would I do this if I could just say"
31
+ # assert_eats_cheese?", a fair question, indeed. You might prefer
32
+ # to replace the word assert with something more aligned with the
33
+ # rest of your code examples. You are using rspec, after all.
34
+ #
35
+ # The other benefit you get is that you can use the negative version
36
+ # of the matcher:
37
+ #
38
+ # describe Cat do
39
+ # it "does not eat cheese" do
40
+ # Cat.new.should_not eat_cheese
41
+ # end
42
+ # end
43
+ #
44
+ # So in the event there is no assert_does_not_eat_cheese available,
45
+ # you're all set!
46
+ def wrap_expectation(matcher, &block)
47
+ begin
48
+ block.call(matcher)
49
+ return true
50
+ rescue Exception => e
51
+ matcher.failure_message = e.message
52
+ return false
53
+ end
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,46 @@
1
+ require 'micronaut/matchers'
2
+ require 'micronaut/expectations/extensions/object'
3
+ require 'micronaut/expectations/extensions/string_and_symbol'
4
+ require 'micronaut/expectations/handler'
5
+ require 'micronaut/expectations/wrap_expectation'
6
+
7
+ module Micronaut
8
+
9
+ # Micronaut::Expectations lets you set expectations on your objects.
10
+ #
11
+ # result.should == 37
12
+ # team.should have(11).players_on_the_field
13
+ #
14
+ # == How Expectations work.
15
+ #
16
+ # Micronaut::Expectations adds two methods to Object:
17
+ #
18
+ # should(matcher=nil)
19
+ # should_not(matcher=nil)
20
+ #
21
+ # Both methods take an optional Expression Matcher (See Micronaut::Matchers).
22
+ #
23
+ # When +should+ receives an Expression Matcher, it calls <tt>matches?(self)</tt>. If
24
+ # it returns +true+, the spec passes and execution continues. If it returns
25
+ # +false+, then the spec fails with the message returned by <tt>matcher.failure_message</tt>.
26
+ #
27
+ # Similarly, when +should_not+ receives a matcher, it calls <tt>matches?(self)</tt>. If
28
+ # it returns +false+, the spec passes and execution continues. If it returns
29
+ # +true+, then the spec fails with the message returned by <tt>matcher.negative_failure_message</tt>.
30
+ #
31
+ # Micronaut ships with a standard set of useful matchers, and writing your own
32
+ # matchers is quite simple. See Micronaut::Matchers for details.
33
+ module Expectations
34
+
35
+ class ExpectationNotMetError < ::StandardError; end
36
+
37
+ def self.fail_with(message, expected=nil, target=nil) # :nodoc:
38
+ if Array === message && message.length == 3
39
+ message, expected, target = message[0], message[1], message[2]
40
+ end
41
+ Kernel::raise(Micronaut::Expectations::ExpectationNotMetError.new(message))
42
+ end
43
+
44
+ end
45
+
46
+ end
@@ -0,0 +1,82 @@
1
+ module Micronaut
2
+ module Formatters
3
+ # Baseclass for formatters that implements all required methods as no-ops.
4
+ class BaseFormatter
5
+ attr_accessor :behaviour, :options, :output, :total_example_failed, :total_example_pending
6
+
7
+ def initialize(options, output_to)
8
+ @options, @output = options, output_to
9
+ @total_example_failed, @total_example_pending = 0, 0
10
+ end
11
+
12
+ def profile_examples?
13
+ Micronaut.configuration.profile_examples
14
+ end
15
+
16
+ # This method is invoked before any examples are run, right after
17
+ # they have all been collected. This can be useful for special
18
+ # formatters that need to provide progress on feedback (graphical ones)
19
+ #
20
+ # This method will only be invoked once, and the next one to be invoked
21
+ # is #add_behaviour
22
+ def start(example_count)
23
+ end
24
+
25
+ # This method is invoked at the beginning of the execution of each behaviour.
26
+ # +behaviour+ is the behaviour.
27
+ #
28
+ # The next method to be invoked after this is #example_failed or #example_finished
29
+ def add_behaviour(behaviour)
30
+ @behaviour = behaviour
31
+ end
32
+
33
+ # This method is invoked when an +example+ starts.
34
+ def example_started(example)
35
+
36
+ end
37
+
38
+ # This method is invoked when an +example+ passes.
39
+ def example_passed(example)
40
+ end
41
+
42
+ # This method is invoked when an +example+ fails, i.e. an exception occurred
43
+ # inside it (such as a failed should or other exception). +counter+ is the
44
+ # sequence number of the failure (starting at 1) and +failure+ is the associated
45
+ # exception.
46
+ def example_failed(example, exception)
47
+ @total_example_failed += 1
48
+ end
49
+
50
+ # This method is invoked when an example is not yet implemented (i.e. has not
51
+ # been provided a block), or when an ExamplePendingError is raised.
52
+ # +message+ is the message from the ExamplePendingError, if it exists, or the
53
+ # default value of "Not Yet Implemented"
54
+ # +pending_caller+ is the file and line number of the spec which
55
+ # has called the pending method
56
+ def example_pending(example, message)
57
+ end
58
+
59
+ # This method is invoked after all of the examples have executed. The next method
60
+ # to be invoked after this one is #dump_failure (once for each failed example),
61
+ def start_dump
62
+ end
63
+
64
+ # Dumps detailed information about each example failure.
65
+ def dump_failures
66
+ end
67
+
68
+ # This method is invoked after the dumping of examples and failures.
69
+ def dump_summary(duration, example_count, failure_count, pending_count)
70
+ end
71
+
72
+ # This gets invoked after the summary if option is set to do so.
73
+ def dump_pending
74
+ end
75
+
76
+ # This method is invoked at the very end. Allows the formatter to clean up, like closing open streams.
77
+ def close
78
+ end
79
+ end
80
+
81
+ end
82
+ end
@@ -0,0 +1,148 @@
1
+ module Micronaut
2
+
3
+ module Formatters
4
+
5
+ class BaseTextFormatter < BaseFormatter
6
+ attr_reader :pending_examples, :failed_examples
7
+
8
+ def initialize(options, output_to)
9
+ super
10
+ @pending_examples = []
11
+ @failed_examples = []
12
+ @example_profiling_info = []
13
+ end
14
+
15
+ def example_passed(example)
16
+ super
17
+ # Why && @start_time
18
+ if profile_examples? && @start_time
19
+ @example_profiling_info << [example, Time.now - @start_time]
20
+ end
21
+ end
22
+
23
+ def example_started(example)
24
+ @start_time = Time.now
25
+ end
26
+
27
+ def example_pending(example, message)
28
+ @pending_examples << [example, message]
29
+ end
30
+
31
+ def example_failed(example, exception)
32
+ super
33
+ @failed_examples << [example, exception]
34
+ end
35
+
36
+ def dump_failures
37
+ @output.puts
38
+ @failed_examples.each_with_index do |examples_with_exception, index|
39
+ example, exception = examples_with_exception.first, examples_with_exception.last
40
+ @output.puts "#{index.next}) #{example}"
41
+ @output.puts colorise(exception.message, exception)
42
+ @output.puts format_backtrace(exception.backtrace)
43
+ @output.puts
44
+ @output.flush
45
+ end
46
+ end
47
+
48
+ def colorise(s, failure)
49
+ if failure.is_a?(Micronaut::Expectations::ExpectationNotMetError)
50
+ red(s)
51
+ else
52
+ magenta(s)
53
+ end
54
+ end
55
+
56
+ def dump_summary(duration, example_count, failure_count, pending_count)
57
+ @output.puts "\nFinished in #{duration} seconds\n"
58
+
59
+ summary = "#{example_count} example#{'s' unless example_count == 1}, #{failure_count} failure#{'s' unless failure_count == 1}"
60
+ summary << ", #{pending_count} pending" if pending_count > 0
61
+
62
+ if failure_count == 0
63
+ if pending_count > 0
64
+ @output.puts yellow(summary)
65
+ else
66
+ @output.puts green(summary)
67
+ end
68
+ else
69
+ @output.puts red(summary)
70
+ end
71
+
72
+ if profile_examples?
73
+ sorted_examples = @example_profiling_info.sort_by { |desc, time| time }
74
+ @output.puts "\nTop 10 slowest examples:\n"
75
+ sorted_examples.last(10).reverse.each do |desc, time|
76
+ @output.puts " (#{sprintf("%.7f", time)} seconds) #{desc}"
77
+ end
78
+ end
79
+
80
+ @output.flush
81
+ end
82
+
83
+ def dump_pending
84
+ unless @pending_examples.empty?
85
+ @output.puts
86
+ @output.puts "Pending:"
87
+ @pending_examples.each do |pending_example, message|
88
+ @output.puts "\n #{pending_example.behaviour}\n - #{pending_example.description}"
89
+ end
90
+ end
91
+ @output.flush
92
+ end
93
+
94
+ def close
95
+ if IO === @output && @output != $stdout
96
+ @output.close
97
+ end
98
+ end
99
+
100
+ def format_backtrace(backtrace)
101
+ return "" if backtrace.nil?
102
+ cleansed = backtrace.map { |line| backtrace_line(line) }.compact.join("\n")
103
+ cleansed.empty? ? backtrace : cleansed
104
+ end
105
+
106
+ protected
107
+
108
+ def enable_color_in_output?
109
+ @options.enable_color_in_output?
110
+ end
111
+
112
+ def backtrace_line(line)
113
+ return nil if Micronaut.configuration.cleaned_from_backtrace?(line)
114
+ line.sub!(/\A([^:]+:\d+)$/, '\\1')
115
+ return nil if line == '-e:1'
116
+ line
117
+ end
118
+
119
+ def color(text, color_code)
120
+ return text unless enable_color_in_output?
121
+ "#{color_code}#{text}\e[0m"
122
+ end
123
+
124
+ def green(text)
125
+ color(text, "\e[32m")
126
+ end
127
+
128
+ def red(text)
129
+ color(text, "\e[31m")
130
+ end
131
+
132
+ def magenta(text)
133
+ color(text, "\e[35m")
134
+ end
135
+
136
+ def yellow(text)
137
+ color(text, "\e[33m")
138
+ end
139
+
140
+ def blue(text)
141
+ color(text, "\e[34m")
142
+ end
143
+
144
+ end
145
+
146
+ end
147
+
148
+ end
@@ -0,0 +1,62 @@
1
+ module Micronaut
2
+ module Formatters
3
+
4
+ class DocumentationFormatter < BaseTextFormatter
5
+
6
+ attr_reader :previous_nested_behaviours
7
+
8
+ def initialize(options, output_to)
9
+ super
10
+ @previous_nested_behaviours = []
11
+ end
12
+
13
+ def add_behaviour(behaviour)
14
+ super
15
+
16
+ described_behaviour_chain.each_with_index do |nested_behaviour, i|
17
+ unless nested_behaviour == previous_nested_behaviours[i]
18
+ desc_or_name = (i == 0) ? nested_behaviour.name : nested_behaviour.description
19
+ output.puts "#{' ' * i}#{desc_or_name}"
20
+ end
21
+ end
22
+
23
+ @previous_nested_behaviours = described_behaviour_chain
24
+ end
25
+
26
+ def example_failed(example, exception)
27
+ super
28
+ expectation_not_met = exception.is_a?(Micronaut::Expectations::ExpectationNotMetError)
29
+
30
+ message = if expectation_not_met
31
+ "#{current_indentation}#{example.description} (FAILED)"
32
+ else
33
+ "#{current_indentation}#{example.description} (ERROR)"
34
+ end
35
+
36
+ @output.puts(expectation_not_met ? red(message) : magenta(message))
37
+ @output.flush
38
+ end
39
+
40
+ def example_passed(example)
41
+ output.puts green("#{current_indentation}#{example.description}")
42
+ output.flush
43
+ end
44
+
45
+ def example_pending(example, message)
46
+ super
47
+ output.puts yellow("#{current_indentation}#{example.description} (PENDING: #{message})")
48
+ output.flush
49
+ end
50
+
51
+ def current_indentation
52
+ ' ' * previous_nested_behaviours.length
53
+ end
54
+
55
+ def described_behaviour_chain
56
+ behaviour.ancestors
57
+ end
58
+
59
+ end
60
+
61
+ end
62
+ end