From aba0b5fd3a073fea1806eb3ac2aaf640941f7362 Mon Sep 17 00:00:00 2001
From: Leslie Hoare <iam@lesleh.co.uk>
Date: Tue, 18 Jun 2019 22:14:49 +0100
Subject: [PATCH] Fix YAML round-tripping message parts (#1347)

* Add init_with method to Mail::Body
* Add spec for PartsList deserialisation
* Add specs for ensuring empty body does not break
---
 lib/mail/body.rb             | 5 +++++
 spec/mail/body_spec.rb       | 8 ++++++++
 spec/mail/message_spec.rb    | 7 +++++++
 spec/mail/parts_list_spec.rb | 6 ++++++
 4 files changed, 26 insertions(+)

diff --git a/lib/mail/body.rb b/lib/mail/body.rb
index 203f26e83..cf659a1cc 100644
--- a/lib/mail/body.rb
+++ b/lib/mail/body.rb
@@ -50,6 +50,11 @@ def initialize(string = '')
       set_charset
     end
 
+    def init_with(coder)
+      coder.map.each { |k, v| instance_variable_set(:"@#{k}", v) }
+      @parts = Mail::PartsList.new(coder['parts'])
+    end
+
     # Matches this body with another body.  Also matches the decoded value of this
     # body with a string.
     # 
diff --git a/spec/mail/body_spec.rb b/spec/mail/body_spec.rb
index 3ee168590..048010f19 100644
--- a/spec/mail/body_spec.rb
+++ b/spec/mail/body_spec.rb
@@ -457,4 +457,12 @@ def assert_split_into(body, pre, epi, parts)
       expect(body.encoded).to eq 'The Body'
     end
   end
+
+  describe "Partslist empty" do
+    it "should not break on empty PartsList on body" do
+      body = Mail::Body.new('The Body')
+      body.sort_parts!
+      expect(body.parts.count).to eq 0
+    end
+  end
 end
diff --git a/spec/mail/message_spec.rb b/spec/mail/message_spec.rb
index 1432b360b..a72fafd80 100644
--- a/spec/mail/message_spec.rb
+++ b/spec/mail/message_spec.rb
@@ -231,6 +231,13 @@ def create_mail_with_splat_args
         expect(deserialized.delivery_handler).to be_nil
       end
 
+      it "should deserialize parts as an instance of Mail::PartsList" do
+        yaml = @yaml_mail.to_yaml
+        yaml_hash = YAML.load(yaml)
+        deserialized = Mail::Message.from_yaml(yaml_hash.to_yaml)
+        expect(deserialized.parts).to be_kind_of(Mail::PartsList)
+      end
+
       it "should handle multipart mail" do
         @yaml_mail.add_part Mail::Part.new(:content_type => 'text/html', :body => '<b>body</b>')
         deserialized = Mail::Message.from_yaml(@yaml_mail.to_yaml)
diff --git a/spec/mail/parts_list_spec.rb b/spec/mail/parts_list_spec.rb
index b5c877dd8..30dc7d7c8 100644
--- a/spec/mail/parts_list_spec.rb
+++ b/spec/mail/parts_list_spec.rb
@@ -36,6 +36,12 @@
     expect(p.sort!(order)).to eq [plain_text_part, html_text_part, no_content_type_part]
   end
 
+  it "should not fail on empty PartsList" do
+    p = Mail::PartsList.new
+    order = ['text/plain']
+    p.sort!(order)
+  end
+
   it "should sort attachments to end" do
     p = Mail::PartsList.new
     order = ['text/plain', 'text/html']