riot 0.11.4 → 0.12.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/CHANGELOG +6 -0
  2. data/VERSION +1 -1
  3. data/lib/riot/assertion.rb +10 -5
  4. data/lib/riot/assertion_macro.rb +10 -0
  5. data/lib/riot/assertion_macros/any.rb +16 -2
  6. data/lib/riot/assertion_macros/assigns.rb +42 -16
  7. data/lib/riot/assertion_macros/empty.rb +13 -2
  8. data/lib/riot/assertion_macros/equals.rb +17 -2
  9. data/lib/riot/assertion_macros/equivalent_to.rb +15 -1
  10. data/lib/riot/assertion_macros/exists.rb +13 -1
  11. data/lib/riot/assertion_macros/includes.rb +16 -0
  12. data/lib/riot/assertion_macros/kind_of.rb +13 -0
  13. data/lib/riot/assertion_macros/matches.rb +14 -0
  14. data/lib/riot/assertion_macros/nil.rb +10 -0
  15. data/lib/riot/assertion_macros/not_borat.rb +10 -0
  16. data/lib/riot/assertion_macros/raises.rb +28 -0
  17. data/lib/riot/assertion_macros/respond_to.rb +14 -0
  18. data/lib/riot/assertion_macros/same_elements.rb +13 -2
  19. data/lib/riot/assertion_macros/size.rb +12 -0
  20. data/lib/riot/context.rb +4 -126
  21. data/lib/riot/context_helpers.rb +132 -0
  22. data/lib/riot/context_options.rb +24 -0
  23. data/riot.gemspec +46 -27
  24. data/test.watchr +70 -0
  25. data/test/core/assertion_macros/any_test.rb +36 -4
  26. data/test/core/assertion_macros/assigns_test.rb +28 -0
  27. data/test/core/assertion_macros/empty_test.rb +35 -7
  28. data/test/core/assertion_macros/equals_test.rb +29 -0
  29. data/test/core/assertion_macros/equivalent_to_test.rb +36 -17
  30. data/test/core/assertion_macros/exists_test.rb +25 -4
  31. data/test/core/assertion_macros/includes_test.rb +12 -0
  32. data/test/core/assertion_macros/kind_of_test.rb +15 -0
  33. data/test/core/assertion_macros/matches_test.rb +49 -0
  34. data/test/core/assertion_macros/nil_test.rb +10 -8
  35. data/test/core/assertion_macros/not_borat_test.rb +14 -8
  36. data/test/core/assertion_macros/raises_test.rb +39 -6
  37. data/test/core/assertion_macros/respond_to_test.rb +18 -1
  38. data/test/core/assertion_macros/same_elements_test.rb +17 -0
  39. data/test/core/assertion_macros/size_test.rb +45 -5
  40. data/test/core/context/asserts_topic_test.rb +21 -0
  41. data/test/core/context/context_test.rb +35 -0
  42. data/test/core/{context_with_options_test.rb → context/context_with_options_test.rb} +0 -0
  43. data/test/core/context/deny_test.rb +25 -0
  44. data/test/core/context/helper_test.rb +11 -0
  45. data/test/core/context/hookup_test.rb +13 -0
  46. data/test/core/context/nested_contexts_test.rb +40 -0
  47. data/test/core/context/premium_setup_test.rb +19 -0
  48. data/test/core/context/should_test.rb +17 -0
  49. data/test/core/{using_describe_in_a_test.rb → context/using_describe_in_a_test.rb} +9 -0
  50. data/test/core/{chained_context_middleware_test.rb → middleware/chained_context_middleware_test.rb} +0 -0
  51. data/test/core/{context_middleware_test.rb → middleware/context_middleware_test.rb} +0 -0
  52. data/test/core/{assertion_macro_test.rb → runnable/assertion_macro_test.rb} +0 -0
  53. data/test/core/{assertion_test.rb → runnable/assertion_test.rb} +0 -0
  54. data/test/core/{message_test.rb → runnable/message_test.rb} +0 -0
  55. data/test/core/runnable/negative_assertion_test.rb +36 -0
  56. data/test/core/{setup_test.rb → runnable/setup_test.rb} +0 -0
  57. data/test/core/{situation_test.rb → runnable/situation_test.rb} +0 -0
  58. data/test/core/{teardown_test.rb → runnable/teardown_test.rb} +0 -0
  59. metadata +54 -32
  60. data/test/core/assertion_macros/matching_test.rb +0 -24
  61. data/test/core/context_test.rb +0 -157
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ *0.12.0.pre*
2
+
3
+ * Negative tests are finally here! Added support for `denies` and adjusted macros to care about it with `devaluate`. [jaknowlden, achiu]
4
+
5
+ denies("my name") { "Rumplestiltzkin" }.equals("Henry")
6
+
1
7
  *0.11.4*
2
8
 
3
9
  * Passing Proc's instead of lambdas to `instance_eval` to comply with ruby 1.9.2. [skade]
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.11.4
1
+ 0.12.0.pre
@@ -8,18 +8,19 @@ module Riot
8
8
  end
9
9
  end
10
10
 
11
- def initialize(description, &definition)
12
- super
13
- @expectings, @expectation_block = [], false, nil
11
+ def initialize(description, negative=false, &definition)
12
+ super(description, &definition)
13
+ @negative = negative
14
+ @expectings, @expectation_block = [], nil
14
15
  @macro = AssertionMacro.default
15
16
  end
16
17
 
17
18
  def run(situation)
18
19
  @expectings << situation.evaluate(&@expectation_block) if @expectation_block
19
20
  actual = situation.evaluate(&definition)
20
- @macro.evaluate((@macro.expects_exception? ? nil : actual), *@expectings)
21
+ assert((@macro.expects_exception? ? nil : actual), *@expectings)
21
22
  rescue Exception => e
22
- @macro.expects_exception? ? @macro.evaluate(e, *@expectings) : @macro.error(e)
23
+ @macro.expects_exception? ? assert(e, *@expectings) : @macro.error(e)
23
24
  end
24
25
  private
25
26
  def enhance_with_macro(name, *expectings, &expectation_block)
@@ -30,5 +31,9 @@ module Riot
30
31
  self
31
32
  end
32
33
  alias :method_missing :enhance_with_macro
34
+
35
+ def assert(*arguments)
36
+ @negative ? @macro.devaluate(*arguments) : @macro.evaluate(*arguments)
37
+ end
33
38
  end # Assertion
34
39
  end # Riot
@@ -22,6 +22,10 @@ module Riot
22
22
  # def evaluate(actual)
23
23
  # actual.length == 0 ? pass : fail(expected_message(actual).to_be_empty)
24
24
  # end
25
+ #
26
+ # def devaluate(actual)
27
+ # actual.empty? ? fail(expected_message(actual).to_not_be_empty) : pass(new_message.is_empty)
28
+ # end
25
29
  # end
26
30
  #
27
31
  class AssertionMacro
@@ -55,10 +59,16 @@ module Riot
55
59
 
56
60
  def expects_exception?; self.class.expects_exception; end
57
61
 
62
+ # Supports positive assertion testing
58
63
  def evaluate(actual)
59
64
  actual ? pass : fail("Expected non-false but got #{actual.inspect} instead")
60
65
  end
61
66
 
67
+ # Supports negative/converse assertion testing
68
+ def devaluate(actual)
69
+ !actual ? pass : fail("Expected non-true but got #{actual.inspect} instead")
70
+ end
71
+
62
72
  # Messaging
63
73
 
64
74
  def new_message(*phrases) Message.new(*phrases); end
@@ -1,12 +1,26 @@
1
1
  module Riot
2
- # Asserts the result has items
2
+ # In the positive case, asserts the result has items using the +any?+ operator.
3
+ #
3
4
  # asserts("an array") { [1] }.any
4
5
  # asserts("a hash") { {:name => 'washington'} }.any
6
+ #
7
+ # In the negative case, asserts the result has no items using the +any?+ operator.
8
+ #
9
+ # denies("an empty array") { [] }.any
10
+ # denies("an empty hash") { {} }.any
5
11
  class AnyMacro < AssertionMacro
6
12
  register :any
7
13
 
8
14
  def evaluate(actual)
9
- actual.any? ? pass("is not empty") : fail(expected_message(actual).to_have_items)
15
+ any?(actual) ? pass("is not empty") : fail(expected_message(actual).to_have_items)
16
+ end
17
+
18
+ def devaluate(actual)
19
+ any?(actual) ? fail(expected_message(actual).not_to_have_elements) : pass("has elements")
20
+ end
21
+ private
22
+ def any?(object)
23
+ object.kind_of?(String) ? object.length > 0 : object.any?
10
24
  end
11
25
  end
12
26
  end
@@ -1,27 +1,53 @@
1
1
  module Riot
2
- # Asserts that an instance variable is defined for the result of the assertion. Value of instance
3
- # variable is expected to not be nil
2
+ # In the positive case, asserts that an instance variable is defined for the result of the assertion.
3
+ # Value of instance variable is expected to not be nil.
4
+ #
4
5
  # setup { User.new(:email => "foo@bar.baz") }
5
- # topic.assigns(:email)
6
+ # asserts_topic.assigns(:email)
6
7
  #
7
8
  # If a value is provided in addition to the variable name, the actual value of the instance variable
8
- # must equal the expected value
9
+ # must equal the expected value.
10
+ #
9
11
  # setup { User.new(:email => "foo@bar.baz") }
10
- # topic.assigns(:email, "foo@bar.baz")
12
+ # asserts_topic.assigns(:email, "foo@bar.baz")
13
+ #
14
+ # In the negative case, asserts that an instance variables *is not* defined or has a nil value. If a value
15
+ # is provided in addition to the name, then ensure that the actual value does not equal the expected value.
16
+ #
17
+ # setup { User.new(:email => "foo@bar.baz") }
18
+ # denies("topic") { topic }.assigns(:first_name)
19
+ # denies("topic") { topic }.assigns(:email, "bar@baz.boo")
11
20
  class AssignsMacro < AssertionMacro
12
21
  register :assigns
13
22
 
14
23
  def evaluate(actual, *expectings)
15
- variable, expected_value = expectings
16
- variable_name = "@#{variable}"
17
- actual_value = actual.instance_variable_defined?(variable_name) ? actual.instance_variable_get(variable_name) : nil
18
- if actual_value.nil?
19
- fail expected_message(variable).to_be_assigned_a_value
20
- elsif !expected_value.nil? && expected_value != actual_value
21
- fail expected_message(variable).to_be_equal_to(expected_value).not(actual_value)
22
- else
23
- pass
24
+ prepare(actual, *expectings) do |variable, expected_value, actual_value|
25
+ if actual_value.nil?
26
+ fail expected_message(variable).to_be_assigned_a_value
27
+ elsif !expected_value.nil? && expected_value != actual_value
28
+ fail expected_message(variable).to_be_equal_to(expected_value).not(actual_value)
29
+ else
30
+ pass
31
+ end
24
32
  end
25
33
  end
26
- end
27
- end
34
+
35
+ def devaluate(actual, *expectings)
36
+ prepare(actual, *expectings) do |variable, expected_value, actual_value|
37
+ if actual_value.nil? || (expected_value && expected_value != actual_value)
38
+ pass
39
+ else
40
+ message = expected_message(variable).to_not_be
41
+ fail(expected_value.nil? ? message.assigned_a_value : message.equal_to(expected_value))
42
+ end
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def prepare(actual, *expectings, &block)
49
+ variable, expected_value = expectings
50
+ yield(variable, expected_value, actual.instance_variable_get("@#{variable}"))
51
+ end
52
+ end # AssignsMacro
53
+ end # Riot
@@ -1,13 +1,24 @@
1
1
  module Riot
2
- # Asserts the result is empty
2
+ # In the postive case, asserts the result of the test is empty.
3
+ #
3
4
  # asserts("a string") { "" }.empty
4
5
  # asserts("an array") { [] }.empty
5
6
  # asserts("a hash") { Hash.new }.empty
7
+ #
8
+ # In the negative case, asserts the result of the test is not empty.
9
+ #
10
+ # denies("a string") { "foo" }.empty
11
+ # denies("an array") { [1] }.empty
12
+ # denies("a hash") { {:foo => "bar" } }.empty
6
13
  class EmptyMacro < AssertionMacro
7
14
  register :empty
8
15
 
9
16
  def evaluate(actual)
10
- actual.length == 0 ? pass : fail(expected_message(actual).to_be_empty)
17
+ actual.empty? ? pass(new_message.is_empty) : fail(expected_message(actual).to_be_empty)
18
+ end
19
+
20
+ def devaluate(actual)
21
+ actual.empty? ? fail(expected_message(actual).to_not_be_empty) : pass(new_message.is_empty)
11
22
  end
12
23
  end
13
24
  end
@@ -1,9 +1,16 @@
1
1
  module Riot
2
- # Asserts that the result of the test equals the expected value. Using the +==+ operator to assert
3
- # equality.
2
+ # In the positive case, asserts that the result of the test equals the expected value. Using the +==+
3
+ # operator to assert equality.
4
+ #
4
5
  # asserts("test") { "foo" }.equals("foo")
5
6
  # should("test") { "foo" }.equals("foo")
6
7
  # asserts("test") { "foo" }.equals { "foo" }
8
+ #
9
+ # In the negative case, asserts that the result of the test *does not* equal the expected value. Using the
10
+ # +==+ operator.
11
+ #
12
+ # denies("test") { "foo" }.equals("bar")
13
+ # denies("test") { "foo" }.equals { "bar" }
7
14
  class EqualsMacro < AssertionMacro
8
15
  register :equals
9
16
 
@@ -14,5 +21,13 @@ module Riot
14
21
  fail expected_message(expected).not(actual)
15
22
  end
16
23
  end
24
+
25
+ def devaluate(actual, expected)
26
+ if expected != actual
27
+ pass new_message.is_equal_to(expected).when_it_is(actual)
28
+ else
29
+ fail new_message.did_not_expect(actual)
30
+ end
31
+ end
17
32
  end
18
33
  end
@@ -5,7 +5,12 @@ module Riot
5
5
  # should("test") { "foo" }.equivalent_to("foo")
6
6
  # asserts("test") { "foo" }.equivalent_to { "foo" }
7
7
  #
8
- # Underneath the hood, this assertion macro says:
8
+ # You can also assert that the expected value is not equivalent to something else:
9
+ #
10
+ # denies("test") { "foo" }.equivalent_to(Boolean)
11
+ # denies("test") { "foo" }.equivalent_to("bar")
12
+ #
13
+ # Underneath the hood, this assertion macro uses:
9
14
  #
10
15
  # expected === actual
11
16
  class EquivalentToMacro < AssertionMacro
@@ -18,5 +23,14 @@ module Riot
18
23
  fail expected_message(actual).to_be_equivalent_to(expected)
19
24
  end
20
25
  end
26
+
27
+ def devaluate(actual, expected)
28
+ if expected === actual
29
+ fail expected_message(actual).not_to_be_equivalent_to(expected)
30
+ else
31
+ pass new_message.is_not_equivalent_to(expected)
32
+ end
33
+ end
34
+
21
35
  end
22
36
  end
@@ -1,15 +1,27 @@
1
1
  module Riot
2
2
  # Asserts that the result of the test is a non-nil value. This is useful in the case where you don't want
3
3
  # to translate the result of the test into a boolean value
4
+ #
4
5
  # asserts("test") { "foo" }.exists
5
6
  # should("test") { 123 }.exists
6
7
  # asserts("test") { "" }.exists
7
8
  # asserts("test") { nil }.exists # This would fail
9
+ #
10
+ # You can also test for non-existince (being nil), but if you would better if you used the +nil+ macro:
11
+ #
12
+ # denies("test") { nil }.exists # would pass
13
+ # asserts("test") { nil }.nil # same thing
14
+ #
15
+ # denies("test") { "foo" }.exists # would fail
8
16
  class ExistsMacro < AssertionMacro
9
17
  register :exists
10
18
 
11
19
  def evaluate(actual)
12
- !actual.nil? ? pass("is not nil") : fail("expected a non-nil value")
20
+ actual.nil? ? fail("expected a non-nil value") : pass("is not nil")
21
+ end
22
+
23
+ def devaluate(actual)
24
+ actual.nil? ? pass("is nil") : fail("expected a nil value")
13
25
  end
14
26
  end
15
27
  end
@@ -1,8 +1,15 @@
1
1
  module Riot
2
2
  # Asserts the result contains the expected element
3
+ #
3
4
  # asserts("a string") { "world" }.includes('o')
4
5
  # asserts("an array") { [1,2,3] }.includes(2)
5
6
  # asserts("a range") { (1..15) }.includes(10)
7
+ #
8
+ # You can also assert that the result does not contain an element:
9
+ #
10
+ # denies("a string") { "world" }.includes('f')
11
+ # denies("an array") { [1,2,3,4,5] }.includes(0)
12
+ # denies("a range") { (1..15) }.includes(16)
6
13
  class IncludesMacro < AssertionMacro
7
14
  register :includes
8
15
 
@@ -13,5 +20,14 @@ module Riot
13
20
  fail expected_message(actual).to_include(expected)
14
21
  end
15
22
  end
23
+
24
+ def devaluate(actual, expected)
25
+ if actual.include?(expected)
26
+ fail expected_message(actual).to_not_include(expected)
27
+ else
28
+ pass new_message.does_not_include(expected)
29
+ end
30
+ end
31
+
16
32
  end
17
33
  end
@@ -1,7 +1,12 @@
1
1
  module Riot
2
2
  # Asserts that the result of the test is an object that is a kind of the expected type
3
+ #
3
4
  # asserts("test") { "foo" }.kind_of(String)
4
5
  # should("test") { "foo" }.kind_of(String)
6
+ #
7
+ # You can also test the result is not a kind of a thing:
8
+ #
9
+ # denies("test") { "foo" }.kind_of(Boolean)
5
10
  class KindOfMacro < AssertionMacro
6
11
  register :kind_of
7
12
 
@@ -12,5 +17,13 @@ module Riot
12
17
  fail expected_message.kind_of(expected).not(actual.class)
13
18
  end
14
19
  end
20
+
21
+ def devaluate(actual, expected)
22
+ if actual.kind_of?(expected)
23
+ fail expected_message.not_kind_of(expected).not(actual.class)
24
+ else
25
+ pass new_message.is_not_a_kind_of(expected)
26
+ end
27
+ end
15
28
  end
16
29
  end
@@ -1,7 +1,12 @@
1
1
  module Riot
2
2
  # Asserts that the result of the test equals matches against the proved expression
3
+ #
3
4
  # asserts("test") { "12345" }.matches(/\d+/)
4
5
  # should("test") { "12345" }.matches(/\d+/)
6
+ #
7
+ # You can also test that the result does not match your regex:
8
+ #
9
+ # denies("test") { "hello, world"}.matches(/\d+/)
5
10
  class MatchesMacro < AssertionMacro
6
11
  register :matches
7
12
 
@@ -13,5 +18,14 @@ module Riot
13
18
  fail(expected_message(expected).to_match(actual))
14
19
  end
15
20
  end
21
+
22
+ def devaluate(actual, expected)
23
+ expected = %r[#{Regexp.escape(expected)}] if expected.kind_of?(String)
24
+ if actual.to_s =~ expected
25
+ fail(expected_message(expected).not_to_match(actual))
26
+ else
27
+ pass(new_message.does_not_match(expected))
28
+ end
29
+ end
16
30
  end
17
31
  end
@@ -1,12 +1,22 @@
1
1
  module Riot
2
2
  # Asserts that the result of the test is nil
3
+ #
3
4
  # asserts("test") { nil }.nil
4
5
  # should("test") { nil }.nil
6
+ #
7
+ # You could test that the result is not nil, but it would make more sense to use the +exists+ macro:
8
+ #
9
+ # denies("test") { "foo" }.nil
10
+ # asserts("test") { "foo" }.exists
5
11
  class NilMacro < AssertionMacro
6
12
  register :nil
7
13
 
8
14
  def evaluate(actual)
9
15
  actual.nil? ? pass("is nil") : fail(expected_message.nil.not(actual))
10
16
  end
17
+
18
+ def devaluate(actual)
19
+ actual.nil? ? fail(expected_message.is_nil.not('non-nil')) : pass("is not nil")
20
+ end
11
21
  end
12
22
  end
@@ -1,16 +1,26 @@
1
1
  module Riot
2
2
  # Asserts the result of the test is a non-truthy value. Read the following assertions in the way Borat
3
3
  # learned about humor:
4
+ #
4
5
  # asserts("you are funny") { false }.not!
5
6
  # should("be funny") { nil }.not!
6
7
  #
7
8
  # Thusly, Borat would say "You are funny ... not!" The above two assertions would pass because the values
8
9
  # are non-truthy.
10
+ #
11
+ # You can also apply not to the negative assertion (denies), but I'm not sure how much sense it would make.
12
+ # It would be kind of like a double negative:
13
+ #
14
+ # denies("you are funny") { true }.not!
9
15
  class NotMacro < AssertionMacro
10
16
  register :not!
11
17
 
12
18
  def evaluate(actual)
13
19
  actual ? fail("expected to exist ... not!") : pass("does exist ... not!")
14
20
  end
21
+
22
+ def devaluate(actual)
23
+ actual ? pass("does not exist ... not!") : fail("expected to not exist ... not!")
24
+ end
15
25
  end
16
26
  end
@@ -7,6 +7,13 @@ module Riot
7
7
  # from the actual raised exception will be converted to a string before any comparison is executed.
8
8
  # asserts("test") { raise My::Exception, "Foo" }.raises(My::Exception, "Foo")
9
9
  # asserts("test") { raise My::Exception, "Foo Bar" }.raises(My::Exception, /Bar/)
10
+ #
11
+ # In the negative case, you can test that an exception was not raised or that if an exception was raised
12
+ # that the type of exception was different (sounds confusing).
13
+ #
14
+ # denies("test") { "foo" }.raises(Exception) # would pass
15
+ # denies("test") { raise Exception }.raises(My::Exception) # would pass
16
+ # denies("test") { raise Exception }.raises(Exception) # would fail
10
17
  class RaisesMacro < AssertionMacro
11
18
  register :raises
12
19
  expects_exception!
@@ -24,5 +31,26 @@ module Riot
24
31
  pass(expected_message ? message.with_message(expected_message) : message)
25
32
  end
26
33
  end # evaluate
34
+
35
+ def devaluate(actual_exception, expected_class, expected_message=nil)
36
+ actual_message = actual_exception && actual_exception.message
37
+ if actual_exception.nil?
38
+ pass new_message.raised_nothing
39
+ elsif expected_class != actual_exception.class
40
+ if expected_message && !(actual_message.to_s =~ %r[#{expected_message}])
41
+ pass new_message.not_raised(expected_class).with_message(expected_message)
42
+ else
43
+ pass new_message.not_raised(expected_class)
44
+ end
45
+ else
46
+ message = should_have_message.not_raised(expected_class)
47
+ if expected_message
48
+ fail message.with_message(expected_message).but.raised(actual_exception.class).
49
+ with_message(actual_exception.message)
50
+ else
51
+ fail message.but.raised(actual_exception.class)
52
+ end
53
+ end
54
+ end # devaluate
27
55
  end # RaisesMacro
28
56
  end