File: has_sent_mail.rb

package info (click to toggle)
ruby-mail 2.6.4%2Bdfsg1-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 4,256 kB
  • ctags: 1,327
  • sloc: ruby: 44,678; makefile: 3
file content (181 lines) | stat: -rw-r--r-- 5,108 bytes parent folder | download
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# frozen_string_literal: true
module Mail
  module Matchers
    def have_sent_email
      HasSentEmailMatcher.new(self)
    end

    class HasSentEmailMatcher
      def initialize(_context)
      end

      def matches?(subject)
        matching_deliveries = filter_matched_deliveries(Mail::TestMailer.deliveries)
        !(matching_deliveries.empty?)
      end

      def from(sender)
        @sender = sender
        self
      end

      def to(recipient_or_list)
        @recipients ||= []

        if recipient_or_list.kind_of?(Array)
          @recipients += recipient_or_list
        else
          @recipients << recipient_or_list
        end
        self
      end

      def cc(recipient_or_list)
        @copy_recipients ||= []

        if recipient_or_list.kind_of?(Array)
          @copy_recipients += recipient_or_list
        else
          @copy_recipients << recipient_or_list
        end
        self
      end

      def bcc(recipient_or_list)
        @blind_copy_recipients ||= []
        @blind_copy_recipients.concat(Array(recipient_or_list))
        self
      end

      def with_attachments(attachments)
        @attachments ||= []
        @attachments.concat(Array(attachments))
        self
      end

      def with_no_attachments
        @having_attachments = false
        self
      end

      def with_any_attachments
        @having_attachments = true
        self
      end

      def with_subject(subject)
        @subject = subject
        self
      end

      def matching_subject(subject_matcher)
        @subject_matcher = subject_matcher
        self
      end

      def with_body(body)
        @body = body
        self
      end

      def matching_body(body_matcher)
        @body_matcher = body_matcher
        self
      end

      def description
        result = "send a matching email"
        result
      end

      def failure_message
        result = "Expected email to be sent "
        result += explain_expectations
        result += dump_deliveries
        result
      end

      def failure_message_when_negated
        result = "Expected no email to be sent "
        result += explain_expectations
        result += dump_deliveries
        result
      end

      protected

      def filter_matched_deliveries(deliveries)
        candidate_deliveries = deliveries
        modifiers =
          %w(sender recipients copy_recipients blind_copy_recipients subject
          subject_matcher body body_matcher having_attachments attachments)
        modifiers.each do |modifier_name|
          next unless instance_variable_defined?("@#{modifier_name}")
          candidate_deliveries = candidate_deliveries.select{|matching_delivery| self.send("matches_on_#{modifier_name}?", matching_delivery)}
        end

        candidate_deliveries
      end

      def matches_on_sender?(delivery)
        delivery.from.include?(@sender)
      end

      def matches_on_recipients?(delivery)
        @recipients.all? {|recipient| delivery.to.include?(recipient) }
      end

      def matches_on_copy_recipients?(delivery)
        @copy_recipients.all? {|recipient| delivery.cc.include?(recipient) }
      end

      def matches_on_blind_copy_recipients?(delivery)
        @blind_copy_recipients.all? {|recipient| delivery.bcc.include?(recipient) }
      end

      def matches_on_subject?(delivery)
        delivery.subject == @subject
      end

      def matches_on_subject_matcher?(delivery)
        @subject_matcher.match delivery.subject
      end

      def matches_on_having_attachments?(delivery)
        @having_attachments && delivery.attachments.any? ||
          (!@having_attachments && delivery.attachments.none?)
      end

      def matches_on_attachments?(delivery)
        @attachments.each_with_index.inject( true ) do |sent_attachments, (attachment, index)|
          sent_attachments &&= (attachment === delivery.attachments[index])
        end
      end

      def matches_on_body?(delivery)
        delivery.body == @body
      end

      def matches_on_body_matcher?(delivery)
        @body_matcher.match delivery.body.raw_source
      end

      def explain_expectations
        result = ''
        result += "from #{@sender} " if instance_variable_defined?('@sender')
        result += "to #{@recipients.inspect} " if instance_variable_defined?('@recipients')
        result += "cc #{@copy_recipients.inspect} " if instance_variable_defined?('@copy_recipients')
        result += "bcc #{@blind_copy_recipients.inspect} " if instance_variable_defined?('@blind_copy_recipients')
        result += "with subject \"#{@subject}\" " if instance_variable_defined?('@subject')
        result += "with subject matching \"#{@subject_matcher}\" " if instance_variable_defined?('@subject_matcher')
        result += "with body \"#{@body}\" " if instance_variable_defined?('@body')
        result += "with body matching \"#{@body_matcher}\" " if instance_variable_defined?('@body_matcher')
        result
      end

      def dump_deliveries
        "(actual deliveries: " + Mail::TestMailer.deliveries.inspect + ")"
      end
    end
  end
end