public
Rubygem
Description: Makes tests easy on the fingers and the eyes
Homepage: http://www.thoughtbot.com/projects/shoulda
Clone URL: git://github.com/thoughtbot/shoulda.git
shoulda / lib / shoulda / general.rb
100644 130 lines (115 sloc) 5.005 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
module ThoughtBot # :nodoc:
  module Shoulda # :nodoc:
    module General
      def self.included(other) # :nodoc:
        other.class_eval do
          extend ThoughtBot::Shoulda::General::ClassMethods
        end
      end
      
      module ClassMethods
        # Loads all fixture files (<tt>test/fixtures/*.yml</tt>)
        def load_all_fixtures
          all_fixtures = Dir.glob(File.join(Test::Unit::TestCase.fixture_path, "*.yml")).collect do |f|
            File.basename(f, '.yml').to_sym
          end
          fixtures *all_fixtures
        end
      end
      
      # Prints a message to stdout, tagged with the name of the calling method.
      def report!(msg = "")
        puts("#{caller.first}: #{msg}")
      end
 
      # Asserts that two arrays contain the same elements, the same number of times. Essentially ==, but unordered.
      #
      # assert_same_elements([:a, :b, :c], [:c, :a, :b]) => passes
      def assert_same_elements(a1, a2, msg = nil)
        [:select, :inject, :size].each do |m|
          [a1, a2].each {|a| assert_respond_to(a, m, "Are you sure that #{a.inspect} is an array? It doesn't respond to #{m}.") }
        end
 
        assert a1h = a1.inject({}) { |h,e| h[e] = a1.select { |i| i == e }.size; h }
        assert a2h = a2.inject({}) { |h,e| h[e] = a2.select { |i| i == e }.size; h }
 
        assert_equal(a1h, a2h, msg)
      end
 
      # Asserts that the given collection contains item x. If x is a regular expression, ensure that
      # at least one element from the collection matches x. +extra_msg+ is appended to the error message if the assertion fails.
      #
      # assert_contains(['a', '1'], /\d/) => passes
      # assert_contains(['a', '1'], 'a') => passes
      # assert_contains(['a', '1'], /not there/) => fails
      def assert_contains(collection, x, extra_msg = "")
        collection = [collection] unless collection.is_a?(Array)
        msg = "#{x.inspect} not found in #{collection.to_a.inspect} #{extra_msg}"
        case x
        when Regexp: assert(collection.detect { |e| e =~ x }, msg)
        else assert(collection.include?(x), msg)
        end
      end
 
      # Asserts that the given collection does not contain item x. If x is a regular expression, ensure that
      # none of the elements from the collection match x.
      def assert_does_not_contain(collection, x, extra_msg = "")
        collection = [collection] unless collection.is_a?(Array)
        msg = "#{x.inspect} found in #{collection.to_a.inspect} " + extra_msg
        case x
        when Regexp: assert(!collection.detect { |e| e =~ x }, msg)
        else assert(!collection.include?(x), msg)
        end
      end
      
      # Asserts that the given object can be saved
      #
      # assert_save User.new(params)
      def assert_save(obj)
        assert obj.save, "Errors: #{pretty_error_messages obj}"
        obj.reload
      end
 
      # Asserts that the given object is valid
      #
      # assert_valid User.new(params)
      def assert_valid(obj)
        assert obj.valid?, "Errors: #{pretty_error_messages obj}"
      end
      
      # Asserts that the block uses ActionMailer to send emails
      #
      # assert_sends_email(2) { Mailer.deliver_messages }
      def assert_sends_email(num = 1, &blk)
        ActionMailer::Base.deliveries.clear
        blk.call
        msg = "Sent #{ActionMailer::Base.deliveries.size} emails, when #{num} expected:\n"
        ActionMailer::Base.deliveries.each { |m| msg << " '#{m.subject}' sent to #{m.to.to_sentence}\n" }
        assert(num == ActionMailer::Base.deliveries.size, msg)
      end
 
      # Asserts that an email was delivered. Can take a blog that can further
      # narrow down the types of emails you're expecting.
      #
      # assert_sent_email
      #
      # passes if ActionMailer::Base.deliveries has an email
      #
      # assert_sent_email do |email|
      # email.subject =~ /hi there/ && email.to == 'none@none.com'
      # end
      #
      # passes if there is an email with subject containing 'hi there' and
      # recipient equal to 'none@none.com'
      #
      def assert_sent_email
        emails = ActionMailer::Base.deliveries
        assert !emails.empty?, "No emails were sent"
        if block_given?
          matching_emails = emails.select {|email| yield email }
          assert !matching_emails.empty?, "None of the emails matched."
        end
      end
 
      # Asserts that no ActionMailer mails were delivered
      #
      # assert_did_not_send_email
      def assert_did_not_send_email
        msg = "Sent #{ActionMailer::Base.deliveries.size} emails.\n"
        ActionMailer::Base.deliveries.each { |m| msg << " '#{m.subject}' sent to #{m.to.to_sentence}\n" }
        assert ActionMailer::Base.deliveries.empty?, msg
      end
 
      def pretty_error_messages(obj)
        obj.errors.map { |a, m| "#{a} #{m} (#{obj.send(a).inspect})" }
      end
      
    end
  end
end