rsanheim-micronaut 0.1.3.2

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 (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