spicycode-micronaut 0.0.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 (47) hide show
  1. data/LICENSE +20 -0
  2. data/README +17 -0
  3. data/Rakefile +55 -0
  4. data/examples/example_helper.rb +19 -0
  5. data/examples/lib/micronaut/example_group_example.rb +116 -0
  6. data/examples/lib/micronaut/example_runner_example.rb +5 -0
  7. data/examples/lib/micronaut/expectations/differs/default_example.rb +126 -0
  8. data/examples/lib/micronaut/expectations/extensions/object_example.rb +78 -0
  9. data/examples/lib/micronaut/expectations/fail_with_example.rb +71 -0
  10. data/examples/lib/micronaut/expectations/wrap_expectation_example.rb +30 -0
  11. data/examples/lib/micronaut_example.rb +8 -0
  12. data/lib/autotest/discover.rb +3 -0
  13. data/lib/autotest/micronaut.rb +43 -0
  14. data/lib/micronaut/example_group.rb +100 -0
  15. data/lib/micronaut/example_runner.rb +108 -0
  16. data/lib/micronaut/example_world.rb +13 -0
  17. data/lib/micronaut/exceptions.rb +7 -0
  18. data/lib/micronaut/expectations/differs/default.rb +67 -0
  19. data/lib/micronaut/expectations/handler.rb +52 -0
  20. data/lib/micronaut/expectations/object_extensions.rb +62 -0
  21. data/lib/micronaut/expectations/string_and_symbol_extensions.rb +17 -0
  22. data/lib/micronaut/expectations/wrap_expectation.rb +51 -0
  23. data/lib/micronaut/expectations.rb +57 -0
  24. data/lib/micronaut/extensions/kernel.rb +15 -0
  25. data/lib/micronaut/matchers/be.rb +203 -0
  26. data/lib/micronaut/matchers/be_close.rb +37 -0
  27. data/lib/micronaut/matchers/change.rb +148 -0
  28. data/lib/micronaut/matchers/eql.rb +43 -0
  29. data/lib/micronaut/matchers/equal.rb +43 -0
  30. data/lib/micronaut/matchers/errors.rb +5 -0
  31. data/lib/micronaut/matchers/exist.rb +22 -0
  32. data/lib/micronaut/matchers/generated_descriptions.rb +36 -0
  33. data/lib/micronaut/matchers/has.rb +34 -0
  34. data/lib/micronaut/matchers/have.rb +150 -0
  35. data/lib/micronaut/matchers/include.rb +77 -0
  36. data/lib/micronaut/matchers/match.rb +41 -0
  37. data/lib/micronaut/matchers/method_missing.rb +9 -0
  38. data/lib/micronaut/matchers/operator_matcher.rb +72 -0
  39. data/lib/micronaut/matchers/raise_error.rb +132 -0
  40. data/lib/micronaut/matchers/respond_to.rb +46 -0
  41. data/lib/micronaut/matchers/satisfy.rb +47 -0
  42. data/lib/micronaut/matchers/simple_matcher.rb +132 -0
  43. data/lib/micronaut/matchers/throw_symbol.rb +100 -0
  44. data/lib/micronaut/matchers.rb +141 -0
  45. data/lib/micronaut/mocking/with_mocha.rb +23 -0
  46. data/lib/micronaut.rb +42 -0
  47. metadata +120 -0
@@ -0,0 +1,150 @@
1
+ module Micronaut
2
+ module Matchers
3
+ class Have #:nodoc:
4
+ def initialize(expected, relativity=:exactly)
5
+ @expected = (expected == :no ? 0 : expected)
6
+ @relativity = relativity
7
+ end
8
+
9
+ def relativities
10
+ @relativities ||= {
11
+ :exactly => "",
12
+ :at_least => "at least ",
13
+ :at_most => "at most "
14
+ }
15
+ end
16
+
17
+ def matches?(collection_owner)
18
+ if collection_owner.respond_to?(@collection_name)
19
+ collection = collection_owner.__send__(@collection_name, *@args, &@block)
20
+ elsif (@plural_collection_name && collection_owner.respond_to?(@plural_collection_name))
21
+ collection = collection_owner.__send__(@plural_collection_name, *@args, &@block)
22
+ elsif (collection_owner.respond_to?(:length) || collection_owner.respond_to?(:size))
23
+ collection = collection_owner
24
+ else
25
+ collection_owner.__send__(@collection_name, *@args, &@block)
26
+ end
27
+ @given = collection.size if collection.respond_to?(:size)
28
+ @given = collection.length if collection.respond_to?(:length)
29
+ raise not_a_collection if @given.nil?
30
+ return @given >= @expected if @relativity == :at_least
31
+ return @given <= @expected if @relativity == :at_most
32
+ return @given == @expected
33
+ end
34
+
35
+ def not_a_collection
36
+ "expected #{@collection_name} to be a collection but it does not respond to #length or #size"
37
+ end
38
+
39
+ def failure_message
40
+ "expected #{relative_expectation} #{@collection_name}, got #{@given}"
41
+ end
42
+
43
+ def negative_failure_message
44
+ if @relativity == :exactly
45
+ return "expected target not to have #{@expected} #{@collection_name}, got #{@given}"
46
+ elsif @relativity == :at_most
47
+ return <<-EOF
48
+ Isn't life confusing enough?
49
+ Instead of having to figure out the meaning of this:
50
+ should_not have_at_most(#{@expected}).#{@collection_name}
51
+ We recommend that you use this instead:
52
+ should have_at_least(#{@expected + 1}).#{@collection_name}
53
+ EOF
54
+ elsif @relativity == :at_least
55
+ return <<-EOF
56
+ Isn't life confusing enough?
57
+ Instead of having to figure out the meaning of this:
58
+ should_not have_at_least(#{@expected}).#{@collection_name}
59
+ We recommend that you use this instead:
60
+ should have_at_most(#{@expected - 1}).#{@collection_name}
61
+ EOF
62
+ end
63
+ end
64
+
65
+ def description
66
+ "have #{relative_expectation} #{@collection_name}"
67
+ end
68
+
69
+ def respond_to?(sym)
70
+ @expected.respond_to?(sym) || super
71
+ end
72
+
73
+ private
74
+
75
+ def method_missing(sym, *args, &block)
76
+ @collection_name = sym
77
+ if inflector = (defined?(ActiveSupport::Inflector) ? ActiveSupport::Inflector : (defined?(Inflector) ? Inflector : nil))
78
+ @plural_collection_name = inflector.pluralize(sym.to_s)
79
+ end
80
+ @args = args
81
+ @block = block
82
+ self
83
+ end
84
+
85
+ def relative_expectation
86
+ "#{relativities[@relativity]}#{@expected}"
87
+ end
88
+ end
89
+
90
+ # :call-seq:
91
+ # should have(number).named_collection__or__sugar
92
+ # should_not have(number).named_collection__or__sugar
93
+ #
94
+ # Passes if receiver is a collection with the submitted
95
+ # number of items OR if the receiver OWNS a collection
96
+ # with the submitted number of items.
97
+ #
98
+ # If the receiver OWNS the collection, you must use the name
99
+ # of the collection. So if a <tt>Team</tt> instance has a
100
+ # collection named <tt>#players</tt>, you must use that name
101
+ # to set the expectation.
102
+ #
103
+ # If the receiver IS the collection, you can use any name
104
+ # you like for <tt>named_collection</tt>. We'd recommend using
105
+ # either "elements", "members", or "items" as these are all
106
+ # standard ways of describing the things IN a collection.
107
+ #
108
+ # This also works for Strings, letting you set an expectation
109
+ # about its length
110
+ #
111
+ # == Examples
112
+ #
113
+ # # Passes if team.players.size == 11
114
+ # team.should have(11).players
115
+ #
116
+ # # Passes if [1,2,3].length == 3
117
+ # [1,2,3].should have(3).items #"items" is pure sugar
118
+ #
119
+ # # Passes if "this string".length == 11
120
+ # "this string".should have(11).characters #"characters" is pure sugar
121
+ def have(n)
122
+ Matchers::Have.new(n)
123
+ end
124
+ alias :have_exactly :have
125
+
126
+ # :call-seq:
127
+ # should have_at_least(number).items
128
+ #
129
+ # Exactly like have() with >=.
130
+ #
131
+ # == Warning
132
+ #
133
+ # +should_not+ +have_at_least+ is not supported
134
+ def have_at_least(n)
135
+ Matchers::Have.new(n, :at_least)
136
+ end
137
+
138
+ # :call-seq:
139
+ # should have_at_most(number).items
140
+ #
141
+ # Exactly like have() with <=.
142
+ #
143
+ # == Warning
144
+ #
145
+ # +should_not+ +have_at_most+ is not supported
146
+ def have_at_most(n)
147
+ Matchers::Have.new(n, :at_most)
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,77 @@
1
+ module Micronaut
2
+ module Matchers
3
+
4
+ class Include #:nodoc:
5
+
6
+ def initialize(*expecteds)
7
+ @expecteds = expecteds
8
+ end
9
+
10
+ def matches?(given)
11
+ @given = given
12
+ @expecteds.each do |expected|
13
+ case given
14
+ when Hash
15
+ expected.each_pair do |k,v|
16
+ return false unless given[k] == v
17
+ end
18
+ else
19
+ return false unless given.include?(expected)
20
+ end
21
+ end
22
+ true
23
+ end
24
+
25
+ def failure_message
26
+ _message
27
+ end
28
+
29
+ def negative_failure_message
30
+ _message("not ")
31
+ end
32
+
33
+ def description
34
+ "include #{_pretty_print(@expecteds)}"
35
+ end
36
+
37
+ private
38
+ def _message(maybe_not="")
39
+ "expected #{@given.inspect} #{maybe_not}to include #{_pretty_print(@expecteds)}"
40
+ end
41
+
42
+ def _pretty_print(array)
43
+ result = ""
44
+ array.each_with_index do |item, index|
45
+ if index < (array.length - 2)
46
+ result << "#{item.inspect}, "
47
+ elsif index < (array.length - 1)
48
+ result << "#{item.inspect} and "
49
+ else
50
+ result << "#{item.inspect}"
51
+ end
52
+ end
53
+ result
54
+ end
55
+ end
56
+
57
+ # :call-seq:
58
+ # should include(expected)
59
+ # should_not include(expected)
60
+ #
61
+ # Passes if given includes expected. This works for
62
+ # collections and Strings. You can also pass in multiple args
63
+ # and it will only pass if all args are found in collection.
64
+ #
65
+ # == Examples
66
+ #
67
+ # [1,2,3].should include(3)
68
+ # [1,2,3].should include(2,3) #would pass
69
+ # [1,2,3].should include(2,3,4) #would fail
70
+ # [1,2,3].should_not include(4)
71
+ # "spread".should include("read")
72
+ # "spread".should_not include("red")
73
+ def include(*expected)
74
+ Matchers::Include.new(*expected)
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,41 @@
1
+ module Micronaut
2
+ module Matchers
3
+
4
+ class Match #:nodoc:
5
+ def initialize(regexp)
6
+ @regexp = regexp
7
+ end
8
+
9
+ def matches?(given)
10
+ @given = given
11
+ return true if given =~ @regexp
12
+ return false
13
+ end
14
+
15
+ def failure_message
16
+ return "expected #{@given.inspect} to match #{@regexp.inspect}", @regexp, @given
17
+ end
18
+
19
+ def negative_failure_message
20
+ return "expected #{@given.inspect} not to match #{@regexp.inspect}", @regexp, @given
21
+ end
22
+
23
+ def description
24
+ "match #{@regexp.inspect}"
25
+ end
26
+ end
27
+
28
+ # :call-seq:
29
+ # should match(regexp)
30
+ # should_not match(regexp)
31
+ #
32
+ # Given a Regexp, passes if given =~ regexp
33
+ #
34
+ # == Examples
35
+ #
36
+ # email.should match(/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i)
37
+ def match(regexp)
38
+ Matchers::Match.new(regexp)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,9 @@
1
+ module Micronaut
2
+ module Matchers
3
+ def method_missing(sym, *args, &block) # :nodoc:
4
+ return Matchers::Be.new(sym, *args) if sym.starts_with?("be_")
5
+ return Matchers::Has.new(sym, *args) if sym.starts_with?("have_")
6
+ super
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,72 @@
1
+ module Micronaut
2
+ module Matchers
3
+ class BaseOperatorMatcher
4
+ def initialize(given)
5
+ @given = given
6
+ end
7
+
8
+ def ==(expected)
9
+ __delegate_method_missing_to_given("==", expected)
10
+ end
11
+
12
+ def ===(expected)
13
+ __delegate_method_missing_to_given("===", expected)
14
+ end
15
+
16
+ def =~(expected)
17
+ __delegate_method_missing_to_given("=~", expected)
18
+ end
19
+
20
+ def >(expected)
21
+ __delegate_method_missing_to_given(">", expected)
22
+ end
23
+
24
+ def >=(expected)
25
+ __delegate_method_missing_to_given(">=", expected)
26
+ end
27
+
28
+ def <(expected)
29
+ __delegate_method_missing_to_given("<", expected)
30
+ end
31
+
32
+ def <=(expected)
33
+ __delegate_method_missing_to_given("<=", expected)
34
+ end
35
+
36
+ def fail_with_message(message)
37
+ Micronaut::Expectations.fail_with(message, @expected, @given)
38
+ end
39
+
40
+ def description
41
+ "#{@operator} #{@expected.inspect}"
42
+ end
43
+
44
+ end
45
+
46
+ class PositiveOperatorMatcher < BaseOperatorMatcher #:nodoc:
47
+
48
+ def __delegate_method_missing_to_given(operator, expected)
49
+ @expected = expected
50
+ @operator = operator
51
+ ::Micronaut::Matchers.last_matcher = self
52
+ return true if @given.__send__(operator, expected)
53
+ return fail_with_message("expected: #{expected.inspect},\n got: #{@given.inspect} (using #{operator})") if ['==','===', '=~'].include?(operator)
54
+ return fail_with_message("expected: #{operator} #{expected.inspect},\n got: #{operator.gsub(/./, ' ')} #{@given.inspect}")
55
+ end
56
+
57
+ end
58
+
59
+ class NegativeOperatorMatcher < BaseOperatorMatcher #:nodoc:
60
+
61
+ def __delegate_method_missing_to_given(operator, expected)
62
+ @expected = expected
63
+ @operator = operator
64
+ ::Micronaut::Matchers.last_matcher = self
65
+ return true unless @given.__send__(operator, expected)
66
+ return fail_with_message("expected not: #{operator} #{expected.inspect},\n got: #{operator.gsub(/./, ' ')} #{@given.inspect}")
67
+ end
68
+
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,132 @@
1
+ module Micronaut
2
+ module Matchers
3
+ class RaiseError #:nodoc:
4
+ def initialize(expected_error_or_message=Exception, expected_message=nil, &block)
5
+ @block = block
6
+ case expected_error_or_message
7
+ when String, Regexp
8
+ @expected_error, @expected_message = Exception, expected_error_or_message
9
+ else
10
+ @expected_error, @expected_message = expected_error_or_message, expected_message
11
+ end
12
+ end
13
+
14
+ def matches?(given_proc)
15
+ @raised_expected_error = false
16
+ @with_expected_message = false
17
+ @eval_block = false
18
+ @eval_block_passed = false
19
+ begin
20
+ given_proc.call
21
+ rescue @expected_error => @given_error
22
+ @raised_expected_error = true
23
+ @with_expected_message = verify_message
24
+ rescue Exception => @given_error
25
+ # This clause should be empty, but rcov will not report it as covered
26
+ # unless something (anything) is executed within the clause
27
+ rcov_error_report = "http://eigenclass.org/hiki.rb?rcov-0.8.0"
28
+ end
29
+
30
+ unless negative_expectation?
31
+ eval_block if @raised_expected_error && @with_expected_message && @block
32
+ end
33
+ ensure
34
+ return (@raised_expected_error && @with_expected_message) ? (@eval_block ? @eval_block_passed : true) : false
35
+ end
36
+
37
+ def eval_block
38
+ @eval_block = true
39
+ begin
40
+ @block[@given_error]
41
+ @eval_block_passed = true
42
+ rescue Exception => err
43
+ @given_error = err
44
+ end
45
+ end
46
+
47
+ def verify_message
48
+ case @expected_message
49
+ when nil
50
+ return true
51
+ when Regexp
52
+ return @expected_message =~ @given_error.message
53
+ else
54
+ return @expected_message == @given_error.message
55
+ end
56
+ end
57
+
58
+ def failure_message
59
+ if @eval_block
60
+ return @given_error.message
61
+ else
62
+ return "expected #{expected_error}#{given_error}"
63
+ end
64
+ end
65
+
66
+ def negative_failure_message
67
+ "expected no #{expected_error}#{given_error}"
68
+ end
69
+
70
+ def description
71
+ "raise #{expected_error}"
72
+ end
73
+
74
+ private
75
+ def expected_error
76
+ case @expected_message
77
+ when nil
78
+ @expected_error
79
+ when Regexp
80
+ "#{@expected_error} with message matching #{@expected_message.inspect}"
81
+ else
82
+ "#{@expected_error} with #{@expected_message.inspect}"
83
+ end
84
+ end
85
+
86
+ def given_error
87
+ @given_error.nil? ? " but nothing was raised" : ", got #{@given_error.inspect}"
88
+ end
89
+
90
+ def negative_expectation?
91
+ # YES - I'm a bad person... help me find a better way - ryand
92
+ caller.first(3).find { |s| s =~ /should_not/ }
93
+ end
94
+ end
95
+
96
+ # :call-seq:
97
+ # should raise_error()
98
+ # should raise_error(NamedError)
99
+ # should raise_error(NamedError, String)
100
+ # should raise_error(NamedError, Regexp)
101
+ # should raise_error() { |error| ... }
102
+ # should raise_error(NamedError) { |error| ... }
103
+ # should raise_error(NamedError, String) { |error| ... }
104
+ # should raise_error(NamedError, Regexp) { |error| ... }
105
+ # should_not raise_error()
106
+ # should_not raise_error(NamedError)
107
+ # should_not raise_error(NamedError, String)
108
+ # should_not raise_error(NamedError, Regexp)
109
+ #
110
+ # With no args, matches if any error is raised.
111
+ # With a named error, matches only if that specific error is raised.
112
+ # With a named error and messsage specified as a String, matches only if both match.
113
+ # With a named error and messsage specified as a Regexp, matches only if both match.
114
+ # Pass an optional block to perform extra verifications on the exception matched
115
+ #
116
+ # == Examples
117
+ #
118
+ # lambda { do_something_risky }.should raise_error
119
+ # lambda { do_something_risky }.should raise_error(PoorRiskDecisionError)
120
+ # lambda { do_something_risky }.should raise_error(PoorRiskDecisionError) { |error| error.data.should == 42 }
121
+ # lambda { do_something_risky }.should raise_error(PoorRiskDecisionError, "that was too risky")
122
+ # lambda { do_something_risky }.should raise_error(PoorRiskDecisionError, /oo ri/)
123
+ #
124
+ # lambda { do_something_risky }.should_not raise_error
125
+ # lambda { do_something_risky }.should_not raise_error(PoorRiskDecisionError)
126
+ # lambda { do_something_risky }.should_not raise_error(PoorRiskDecisionError, "that was too risky")
127
+ # lambda { do_something_risky }.should_not raise_error(PoorRiskDecisionError, /oo ri/)
128
+ def raise_error(error=Exception, message=nil, &block)
129
+ Matchers::RaiseError.new(error, message, &block)
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,46 @@
1
+ module Micronaut
2
+ module Matchers
3
+
4
+ class RespondTo #:nodoc:
5
+ def initialize(*names)
6
+ @names = names
7
+ @names_not_responded_to = []
8
+ end
9
+
10
+ def matches?(given)
11
+ @given = given
12
+ @names.each do |name|
13
+ unless given.respond_to?(name)
14
+ @names_not_responded_to << name
15
+ end
16
+ end
17
+ return @names_not_responded_to.empty?
18
+ end
19
+
20
+ def failure_message
21
+ "expected #{@given.inspect} to respond to #{@names_not_responded_to.collect {|name| name.inspect }.join(', ')}"
22
+ end
23
+
24
+ def negative_failure_message
25
+ "expected #{@given.inspect} not to respond to #{@names.collect {|name| name.inspect }.join(', ')}"
26
+ end
27
+
28
+ def description
29
+ "respond to ##{@names.to_s}"
30
+ end
31
+ end
32
+
33
+ # :call-seq:
34
+ # should respond_to(*names)
35
+ # should_not respond_to(*names)
36
+ #
37
+ # Matches if the target object responds to all of the names
38
+ # provided. Names can be Strings or Symbols.
39
+ #
40
+ # == Examples
41
+ #
42
+ def respond_to(*names)
43
+ Matchers::RespondTo.new(*names)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,47 @@
1
+ module Micronaut
2
+ module Matchers
3
+
4
+ class Satisfy #:nodoc:
5
+ def initialize(&block)
6
+ @block = block
7
+ end
8
+
9
+ def matches?(given, &block)
10
+ @block = block if block
11
+ @given = given
12
+ @block.call(given)
13
+ end
14
+
15
+ def failure_message
16
+ "expected #{@given} to satisfy block"
17
+ end
18
+
19
+ def negative_failure_message
20
+ "expected #{@given} not to satisfy block"
21
+ end
22
+ end
23
+
24
+ # :call-seq:
25
+ # should satisfy {}
26
+ # should_not satisfy {}
27
+ #
28
+ # Passes if the submitted block returns true. Yields target to the
29
+ # block.
30
+ #
31
+ # Generally speaking, this should be thought of as a last resort when
32
+ # you can't find any other way to specify the behaviour you wish to
33
+ # specify.
34
+ #
35
+ # If you do find yourself in such a situation, you could always write
36
+ # a custom matcher, which would likely make your specs more expressive.
37
+ #
38
+ # == Examples
39
+ #
40
+ # 5.should satisfy { |n|
41
+ # n > 3
42
+ # }
43
+ def satisfy(&block)
44
+ Matchers::Satisfy.new(&block)
45
+ end
46
+ end
47
+ end