actionmailer_csi 2.3.5.p6

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 (109) hide show
  1. data/CHANGELOG +370 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +149 -0
  4. data/Rakefile +99 -0
  5. data/install.rb +30 -0
  6. data/lib/action_mailer/adv_attr_accessor.rb +30 -0
  7. data/lib/action_mailer/base.rb +706 -0
  8. data/lib/action_mailer/helpers.rb +113 -0
  9. data/lib/action_mailer/mail_helper.rb +17 -0
  10. data/lib/action_mailer/part.rb +107 -0
  11. data/lib/action_mailer/part_container.rb +55 -0
  12. data/lib/action_mailer/quoting.rb +61 -0
  13. data/lib/action_mailer/test_case.rb +64 -0
  14. data/lib/action_mailer/test_helper.rb +68 -0
  15. data/lib/action_mailer/utils.rb +7 -0
  16. data/lib/action_mailer/vendor/text-format-0.6.3/text/format.rb +1466 -0
  17. data/lib/action_mailer/vendor/text_format.rb +10 -0
  18. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/address.rb +426 -0
  19. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/attachments.rb +46 -0
  20. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/base64.rb +46 -0
  21. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/compat.rb +41 -0
  22. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/config.rb +67 -0
  23. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/core_extensions.rb +63 -0
  24. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/encode.rb +581 -0
  25. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/header.rb +960 -0
  26. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/index.rb +9 -0
  27. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/interface.rb +1130 -0
  28. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/loader.rb +3 -0
  29. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb +578 -0
  30. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/mailbox.rb +495 -0
  31. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/main.rb +6 -0
  32. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/mbox.rb +3 -0
  33. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/net.rb +248 -0
  34. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/obsolete.rb +132 -0
  35. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/parser.rb +1478 -0
  36. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/port.rb +379 -0
  37. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/quoting.rb +118 -0
  38. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/require_arch.rb +58 -0
  39. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner.rb +49 -0
  40. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner_r.rb +261 -0
  41. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/stringio.rb +280 -0
  42. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/utils.rb +337 -0
  43. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/version.rb +39 -0
  44. data/lib/action_mailer/vendor/tmail-1.2.3/tmail.rb +5 -0
  45. data/lib/action_mailer/vendor/tmail.rb +17 -0
  46. data/lib/action_mailer/version.rb +9 -0
  47. data/lib/action_mailer.rb +62 -0
  48. data/lib/actionmailer.rb +2 -0
  49. data/test/abstract_unit.rb +62 -0
  50. data/test/asset_host_test.rb +54 -0
  51. data/test/delivery_method_test.rb +51 -0
  52. data/test/fixtures/asset_host_mailer/email_with_asset.html.erb +1 -0
  53. data/test/fixtures/auto_layout_mailer/hello.html.erb +1 -0
  54. data/test/fixtures/auto_layout_mailer/multipart.text.html.erb +1 -0
  55. data/test/fixtures/auto_layout_mailer/multipart.text.plain.erb +1 -0
  56. data/test/fixtures/explicit_layout_mailer/logout.html.erb +1 -0
  57. data/test/fixtures/explicit_layout_mailer/signup.html.erb +1 -0
  58. data/test/fixtures/first_mailer/share.erb +1 -0
  59. data/test/fixtures/helper_mailer/use_example_helper.erb +1 -0
  60. data/test/fixtures/helper_mailer/use_helper.erb +1 -0
  61. data/test/fixtures/helper_mailer/use_helper_method.erb +1 -0
  62. data/test/fixtures/helper_mailer/use_mail_helper.erb +5 -0
  63. data/test/fixtures/helpers/example_helper.rb +5 -0
  64. data/test/fixtures/layouts/auto_layout_mailer.html.erb +1 -0
  65. data/test/fixtures/layouts/auto_layout_mailer.text.erb +1 -0
  66. data/test/fixtures/layouts/spam.html.erb +1 -0
  67. data/test/fixtures/path.with.dots/funky_path_mailer/multipart_with_template_path_with_dots.erb +1 -0
  68. data/test/fixtures/raw_email +14 -0
  69. data/test/fixtures/raw_email10 +20 -0
  70. data/test/fixtures/raw_email12 +32 -0
  71. data/test/fixtures/raw_email13 +29 -0
  72. data/test/fixtures/raw_email2 +114 -0
  73. data/test/fixtures/raw_email3 +70 -0
  74. data/test/fixtures/raw_email4 +59 -0
  75. data/test/fixtures/raw_email5 +19 -0
  76. data/test/fixtures/raw_email6 +20 -0
  77. data/test/fixtures/raw_email7 +66 -0
  78. data/test/fixtures/raw_email8 +47 -0
  79. data/test/fixtures/raw_email9 +28 -0
  80. data/test/fixtures/raw_email_quoted_with_0d0a +14 -0
  81. data/test/fixtures/raw_email_with_invalid_characters_in_content_type +104 -0
  82. data/test/fixtures/raw_email_with_nested_attachment +100 -0
  83. data/test/fixtures/raw_email_with_partially_quoted_subject +14 -0
  84. data/test/fixtures/second_mailer/share.erb +1 -0
  85. data/test/fixtures/templates/signed_up.erb +3 -0
  86. data/test/fixtures/test_mailer/_subtemplate.text.plain.erb +1 -0
  87. data/test/fixtures/test_mailer/body_ivar.erb +2 -0
  88. data/test/fixtures/test_mailer/custom_templating_extension.text.html.haml +6 -0
  89. data/test/fixtures/test_mailer/custom_templating_extension.text.plain.haml +6 -0
  90. data/test/fixtures/test_mailer/implicitly_multipart_example.ignored.erb +1 -0
  91. data/test/fixtures/test_mailer/implicitly_multipart_example.rhtml.bak +1 -0
  92. data/test/fixtures/test_mailer/implicitly_multipart_example.text.html.erb +10 -0
  93. data/test/fixtures/test_mailer/implicitly_multipart_example.text.html.erb~ +10 -0
  94. data/test/fixtures/test_mailer/implicitly_multipart_example.text.plain.erb +2 -0
  95. data/test/fixtures/test_mailer/implicitly_multipart_example.text.yaml.erb +1 -0
  96. data/test/fixtures/test_mailer/included_subtemplate.text.plain.erb +1 -0
  97. data/test/fixtures/test_mailer/rxml_template.builder +2 -0
  98. data/test/fixtures/test_mailer/rxml_template.rxml +2 -0
  99. data/test/fixtures/test_mailer/signed_up.html.erb +3 -0
  100. data/test/fixtures/test_mailer/signed_up_with_url.erb +5 -0
  101. data/test/mail_helper_test.rb +95 -0
  102. data/test/mail_layout_test.rb +123 -0
  103. data/test/mail_render_test.rb +116 -0
  104. data/test/mail_service_test.rb +1081 -0
  105. data/test/quoting_test.rb +99 -0
  106. data/test/test_helper_test.rb +129 -0
  107. data/test/tmail_test.rb +22 -0
  108. data/test/url_test.rb +76 -0
  109. metadata +195 -0
@@ -0,0 +1,113 @@
1
+ require 'active_support/dependencies'
2
+
3
+ module ActionMailer
4
+ module Helpers #:nodoc:
5
+ def self.included(base) #:nodoc:
6
+ # Initialize the base module to aggregate its helpers.
7
+ base.class_inheritable_accessor :master_helper_module
8
+ base.master_helper_module = Module.new
9
+
10
+ # Extend base with class methods to declare helpers.
11
+ base.extend(ClassMethods)
12
+
13
+ base.class_eval do
14
+ # Wrap inherited to create a new master helper module for subclasses.
15
+ class << self
16
+ alias_method_chain :inherited, :helper
17
+ end
18
+
19
+ # Wrap initialize_template_class to extend new template class
20
+ # instances with the master helper module.
21
+ alias_method_chain :initialize_template_class, :helper
22
+ end
23
+ end
24
+
25
+ module ClassMethods
26
+ # Makes all the (instance) methods in the helper module available to templates rendered through this controller.
27
+ # See ActionView::Helpers (link:classes/ActionView/Helpers.html) for more about making your own helper modules
28
+ # available to the templates.
29
+ def add_template_helper(helper_module) #:nodoc:
30
+ master_helper_module.module_eval "include #{helper_module}"
31
+ end
32
+
33
+ # Declare a helper:
34
+ # helper :foo
35
+ # requires 'foo_helper' and includes FooHelper in the template class.
36
+ # helper FooHelper
37
+ # includes FooHelper in the template class.
38
+ # helper { def foo() "#{bar} is the very best" end }
39
+ # evaluates the block in the template class, adding method +foo+.
40
+ # helper(:three, BlindHelper) { def mice() 'mice' end }
41
+ # does all three.
42
+ def helper(*args, &block)
43
+ args.flatten.each do |arg|
44
+ case arg
45
+ when Module
46
+ add_template_helper(arg)
47
+ when String, Symbol
48
+ file_name = arg.to_s.underscore + '_helper'
49
+ class_name = file_name.camelize
50
+
51
+ begin
52
+ require_dependency(file_name)
53
+ rescue LoadError => load_error
54
+ requiree = / -- (.*?)(\.rb)?$/.match(load_error.message).to_a[1]
55
+ msg = (requiree == file_name) ? "Missing helper file helpers/#{file_name}.rb" : "Can't load file: #{requiree}"
56
+ raise LoadError.new(msg).copy_blame!(load_error)
57
+ end
58
+
59
+ add_template_helper(class_name.constantize)
60
+ else
61
+ raise ArgumentError, 'helper expects String, Symbol, or Module argument'
62
+ end
63
+ end
64
+
65
+ # Evaluate block in template class if given.
66
+ master_helper_module.module_eval(&block) if block_given?
67
+ end
68
+
69
+ # Declare a controller method as a helper. For example,
70
+ # helper_method :link_to
71
+ # def link_to(name, options) ... end
72
+ # makes the link_to controller method available in the view.
73
+ def helper_method(*methods)
74
+ methods.flatten.each do |method|
75
+ master_helper_module.module_eval <<-end_eval
76
+ def #{method}(*args, &block)
77
+ controller.__send__(%(#{method}), *args, &block)
78
+ end
79
+ end_eval
80
+ end
81
+ end
82
+
83
+ # Declare a controller attribute as a helper. For example,
84
+ # helper_attr :name
85
+ # attr_accessor :name
86
+ # makes the name and name= controller methods available in the view.
87
+ # The is a convenience wrapper for helper_method.
88
+ def helper_attr(*attrs)
89
+ attrs.flatten.each { |attr| helper_method(attr, "#{attr}=") }
90
+ end
91
+
92
+ private
93
+ def inherited_with_helper(child)
94
+ inherited_without_helper(child)
95
+ begin
96
+ child.master_helper_module = Module.new
97
+ child.master_helper_module.__send__(:include, master_helper_module)
98
+ child.helper child.name.to_s.underscore
99
+ rescue MissingSourceFile => e
100
+ raise unless e.is_missing?("helpers/#{child.name.to_s.underscore}_helper")
101
+ end
102
+ end
103
+ end
104
+
105
+ private
106
+ # Extend the template class instance with our controller's helper module.
107
+ def initialize_template_class_with_helper(assigns)
108
+ returning(template = initialize_template_class_without_helper(assigns)) do
109
+ template.extend self.class.master_helper_module
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,17 @@
1
+ module MailHelper
2
+ # Uses Text::Format to take the text and format it, indented two spaces for
3
+ # each line, and wrapped at 72 columns.
4
+ def block_format(text)
5
+ formatted = text.split(/\n\r\n/).collect { |paragraph|
6
+ Text::Format.new(
7
+ :columns => 72, :first_indent => 2, :body_indent => 2, :text => paragraph
8
+ ).format
9
+ }.join("\n")
10
+
11
+ # Make list points stand on their own line
12
+ formatted.gsub!(/[ ]*([*]+) ([^*]*)/) { |s| " #{$1} #{$2.strip}\n" }
13
+ formatted.gsub!(/[ ]*([#]+) ([^#]*)/) { |s| " #{$1} #{$2.strip}\n" }
14
+
15
+ formatted
16
+ end
17
+ end
@@ -0,0 +1,107 @@
1
+ module ActionMailer
2
+ # Represents a subpart of an email message. It shares many similar
3
+ # attributes of ActionMailer::Base. Although you can create parts manually
4
+ # and add them to the +parts+ list of the mailer, it is easier
5
+ # to use the helper methods in ActionMailer::PartContainer.
6
+ class Part
7
+ include AdvAttrAccessor, PartContainer, Utils
8
+
9
+ # Represents the body of the part, as a string. This should not be a
10
+ # Hash (like ActionMailer::Base), but if you want a template to be rendered
11
+ # into the body of a subpart you can do it with the mailer's +render+ method
12
+ # and assign the result here.
13
+ adv_attr_accessor :body
14
+
15
+ # Specify the charset for this subpart. By default, it will be the charset
16
+ # of the containing part or mailer.
17
+ adv_attr_accessor :charset
18
+
19
+ # The content disposition of this part, typically either "inline" or
20
+ # "attachment".
21
+ adv_attr_accessor :content_disposition
22
+
23
+ # The content type of the part.
24
+ adv_attr_accessor :content_type
25
+
26
+ # The filename to use for this subpart (usually for attachments).
27
+ adv_attr_accessor :filename
28
+
29
+ # Accessor for specifying additional headers to include with this part.
30
+ adv_attr_accessor :headers
31
+
32
+ # The transfer encoding to use for this subpart, like "base64" or
33
+ # "quoted-printable".
34
+ adv_attr_accessor :transfer_encoding
35
+
36
+ # Create a new part from the given +params+ hash. The valid params keys
37
+ # correspond to the accessors.
38
+ def initialize(params)
39
+ @content_type = params[:content_type]
40
+ @content_disposition = params[:disposition] || "inline"
41
+ @charset = params[:charset]
42
+ @body = params[:body]
43
+ @filename = params[:filename]
44
+ @transfer_encoding = params[:transfer_encoding] || "quoted-printable"
45
+ @headers = params[:headers] || {}
46
+ @parts = []
47
+ end
48
+
49
+ # Convert the part to a mail object which can be included in the parts
50
+ # list of another mail object.
51
+ def to_mail(defaults)
52
+ part = TMail::Mail.new
53
+
54
+ real_content_type, ctype_attrs = parse_content_type(defaults)
55
+
56
+ if @parts.empty?
57
+ part.content_transfer_encoding = transfer_encoding || "quoted-printable"
58
+ case (transfer_encoding || "").downcase
59
+ when "base64" then
60
+ part.body = TMail::Base64.folding_encode(body)
61
+ when "quoted-printable"
62
+ part.body = [normalize_new_lines(body)].pack("M*")
63
+ else
64
+ part.body = body
65
+ end
66
+
67
+ # Always set the content_type after setting the body and or parts!
68
+ # Also don't set filename and name when there is none (like in
69
+ # non-attachment parts)
70
+ if content_disposition == "attachment"
71
+ ctype_attrs.delete "charset"
72
+ part.set_content_type(real_content_type, nil,
73
+ squish("name" => filename).merge(ctype_attrs))
74
+ part.set_content_disposition(content_disposition,
75
+ squish("filename" => filename).merge(ctype_attrs))
76
+ else
77
+ part.set_content_type(real_content_type, nil, ctype_attrs)
78
+ part.set_content_disposition(content_disposition)
79
+ end
80
+ else
81
+ if String === body
82
+ @parts.unshift Part.new(:charset => charset, :body => @body, :content_type => 'text/plain')
83
+ @body = nil
84
+ end
85
+
86
+ @parts.each do |p|
87
+ prt = (TMail::Mail === p ? p : p.to_mail(defaults))
88
+ part.parts << prt
89
+ end
90
+
91
+ if real_content_type =~ /multipart/
92
+ ctype_attrs.delete 'charset'
93
+ part.set_content_type(real_content_type, nil, ctype_attrs)
94
+ end
95
+ end
96
+
97
+ headers.each { |k,v| part[k] = v }
98
+
99
+ part
100
+ end
101
+
102
+ private
103
+ def squish(values={})
104
+ values.delete_if { |k,v| v.nil? }
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,55 @@
1
+ module ActionMailer
2
+ # Accessors and helpers that ActionMailer::Base and ActionMailer::Part have
3
+ # in common. Using these helpers you can easily add subparts or attachments
4
+ # to your message:
5
+ #
6
+ # def my_mail_message(...)
7
+ # ...
8
+ # part "text/plain" do |p|
9
+ # p.body "hello, world"
10
+ # p.transfer_encoding "base64"
11
+ # end
12
+ #
13
+ # attachment "image/jpg" do |a|
14
+ # a.body = File.read("hello.jpg")
15
+ # a.filename = "hello.jpg"
16
+ # end
17
+ # end
18
+ module PartContainer
19
+ # The list of subparts of this container
20
+ attr_reader :parts
21
+
22
+ # Add a part to a multipart message, with the given content-type. The
23
+ # part itself is yielded to the block so that other properties (charset,
24
+ # body, headers, etc.) can be set on it.
25
+ def part(params)
26
+ params = {:content_type => params} if String === params
27
+ part = Part.new(params)
28
+ yield part if block_given?
29
+ @parts << part
30
+ end
31
+
32
+ # Add an attachment to a multipart message. This is simply a part with the
33
+ # content-disposition set to "attachment".
34
+ def attachment(params, &block)
35
+ params = { :content_type => params } if String === params
36
+ params = { :disposition => "attachment",
37
+ :transfer_encoding => "base64" }.merge(params)
38
+ part(params, &block)
39
+ end
40
+
41
+ private
42
+
43
+ def parse_content_type(defaults=nil)
44
+ if content_type.blank?
45
+ return defaults ?
46
+ [ defaults.content_type, { 'charset' => defaults.charset } ] :
47
+ [ nil, {} ]
48
+ end
49
+ ctype, *attrs = content_type.split(/;\s*/)
50
+ attrs = attrs.inject({}) { |h,s| k,v = s.split(/=/, 2); h[k] = v; h }
51
+ [ctype, {"charset" => charset || defaults && defaults.charset}.merge(attrs)]
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,61 @@
1
+ module ActionMailer
2
+ module Quoting #:nodoc:
3
+ # Convert the given text into quoted printable format, with an instruction
4
+ # that the text be eventually interpreted in the given charset.
5
+ def quoted_printable(text, charset)
6
+ text = text.gsub( /[^a-z ]/i ) { quoted_printable_encode($&) }.
7
+ gsub( / /, "_" )
8
+ "=?#{charset}?Q?#{text}?="
9
+ end
10
+
11
+ # Convert the given character to quoted printable format, taking into
12
+ # account multi-byte characters (if executing with $KCODE="u", for instance)
13
+ def quoted_printable_encode(character)
14
+ result = ""
15
+ character.each_byte { |b| result << "=%02X" % b }
16
+ result
17
+ end
18
+
19
+ # A quick-and-dirty regexp for determining whether a string contains any
20
+ # characters that need escaping.
21
+ if !defined?(CHARS_NEEDING_QUOTING)
22
+ CHARS_NEEDING_QUOTING = /[\000-\011\013\014\016-\037\177-\377]/
23
+ end
24
+
25
+ # Quote the given text if it contains any "illegal" characters
26
+ def quote_if_necessary(text, charset)
27
+ text = text.dup.force_encoding(Encoding::ASCII_8BIT) if text.respond_to?(:force_encoding)
28
+
29
+ (text =~ CHARS_NEEDING_QUOTING) ?
30
+ quoted_printable(text, charset) :
31
+ text
32
+ end
33
+
34
+ # Quote any of the given strings if they contain any "illegal" characters
35
+ def quote_any_if_necessary(charset, *args)
36
+ args.map { |v| quote_if_necessary(v, charset) }
37
+ end
38
+
39
+ # Quote the given address if it needs to be. The address may be a
40
+ # regular email address, or it can be a phrase followed by an address in
41
+ # brackets. The phrase is the only part that will be quoted, and only if
42
+ # it needs to be. This allows extended characters to be used in the
43
+ # "to", "from", "cc", "bcc" and "reply-to" headers.
44
+ def quote_address_if_necessary(address, charset)
45
+ if Array === address
46
+ address.map { |a| quote_address_if_necessary(a, charset) }
47
+ elsif address =~ /^(\S.*)\s+(<.*>)$/
48
+ address = $2
49
+ phrase = quote_if_necessary($1.gsub(/^['"](.*)['"]$/, '\1'), charset)
50
+ "\"#{phrase}\" #{address}"
51
+ else
52
+ address
53
+ end
54
+ end
55
+
56
+ # Quote any of the given addresses, if they need to be.
57
+ def quote_any_address_if_necessary(charset, *args)
58
+ args.map { |v| quote_address_if_necessary(v, charset) }
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,64 @@
1
+ require 'active_support/test_case'
2
+
3
+ module ActionMailer
4
+ class NonInferrableMailerError < ::StandardError
5
+ def initialize(name)
6
+ super "Unable to determine the mailer to test from #{name}. " +
7
+ "You'll need to specify it using tests YourMailer in your " +
8
+ "test case definition"
9
+ end
10
+ end
11
+
12
+ class TestCase < ActiveSupport::TestCase
13
+ include Quoting, TestHelper
14
+
15
+ setup :initialize_test_deliveries
16
+ setup :set_expected_mail
17
+
18
+ class << self
19
+ def tests(mailer)
20
+ write_inheritable_attribute(:mailer_class, mailer)
21
+ end
22
+
23
+ def mailer_class
24
+ if mailer = read_inheritable_attribute(:mailer_class)
25
+ mailer
26
+ else
27
+ tests determine_default_mailer(name)
28
+ end
29
+ end
30
+
31
+ def determine_default_mailer(name)
32
+ name.sub(/Test$/, '').constantize
33
+ rescue NameError => e
34
+ raise NonInferrableMailerError.new(name)
35
+ end
36
+ end
37
+
38
+ protected
39
+ def initialize_test_deliveries
40
+ ActionMailer::Base.delivery_method = :test
41
+ ActionMailer::Base.perform_deliveries = true
42
+ ActionMailer::Base.deliveries = []
43
+ end
44
+
45
+ def set_expected_mail
46
+ @expected = TMail::Mail.new
47
+ @expected.set_content_type "text", "plain", { "charset" => charset }
48
+ @expected.mime_version = '1.0'
49
+ end
50
+
51
+ private
52
+ def charset
53
+ "utf-8"
54
+ end
55
+
56
+ def encode(subject)
57
+ quoted_printable(subject, charset)
58
+ end
59
+
60
+ def read_fixture(action)
61
+ IO.readlines(File.join(RAILS_ROOT, 'test', 'fixtures', self.class.mailer_class.name.underscore, action))
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,68 @@
1
+ module ActionMailer
2
+ module TestHelper
3
+ # Asserts that the number of emails sent matches the given number.
4
+ #
5
+ # def test_emails
6
+ # assert_emails 0
7
+ # ContactMailer.deliver_contact
8
+ # assert_emails 1
9
+ # ContactMailer.deliver_contact
10
+ # assert_emails 2
11
+ # end
12
+ #
13
+ # If a block is passed, that block should cause the specified number of emails to be sent.
14
+ #
15
+ # def test_emails_again
16
+ # assert_emails 1 do
17
+ # ContactMailer.deliver_contact
18
+ # end
19
+ #
20
+ # assert_emails 2 do
21
+ # ContactMailer.deliver_contact
22
+ # ContactMailer.deliver_contact
23
+ # end
24
+ # end
25
+ def assert_emails(number)
26
+ if block_given?
27
+ original_count = ActionMailer::Base.deliveries.size
28
+ yield
29
+ new_count = ActionMailer::Base.deliveries.size
30
+ assert_equal original_count + number, new_count, "#{number} emails expected, but #{new_count - original_count} were sent"
31
+ else
32
+ assert_equal number, ActionMailer::Base.deliveries.size
33
+ end
34
+ end
35
+
36
+ # Assert that no emails have been sent.
37
+ #
38
+ # def test_emails
39
+ # assert_no_emails
40
+ # ContactMailer.deliver_contact
41
+ # assert_emails 1
42
+ # end
43
+ #
44
+ # If a block is passed, that block should not cause any emails to be sent.
45
+ #
46
+ # def test_emails_again
47
+ # assert_no_emails do
48
+ # # No emails should be sent from this block
49
+ # end
50
+ # end
51
+ #
52
+ # Note: This assertion is simply a shortcut for:
53
+ #
54
+ # assert_emails 0
55
+ def assert_no_emails(&block)
56
+ assert_emails 0, &block
57
+ end
58
+ end
59
+ end
60
+
61
+ # TODO: Deprecate this
62
+ module Test
63
+ module Unit
64
+ class TestCase
65
+ include ActionMailer::TestHelper
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,7 @@
1
+ module ActionMailer
2
+ module Utils #:nodoc:
3
+ def normalize_new_lines(text)
4
+ text.to_s.gsub(/\r\n?/, "\n")
5
+ end
6
+ end
7
+ end