spicycode-micronaut 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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