test_mbox.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. # test_mbox.py -- tests for porcelain mbox (mailsplit)
  2. # Copyright (C) 2020 Jelmer Vernooij <jelmer@jelmer.uk>
  3. #
  4. # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  5. # Dulwich is dual-licensed under the Apache License, Version 2.0 and the GNU
  6. # General Public License as published by the Free Software Foundation; version 2.0
  7. # or (at your option) any later version. You can redistribute it and/or
  8. # modify it under the terms of either of these two licenses.
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. #
  16. # You should have received a copy of the licenses; if not, see
  17. # <http://www.gnu.org/licenses/> for a copy of the GNU General Public License
  18. # and <http://www.apache.org/licenses/LICENSE-2.0> for a copy of the Apache
  19. # License, Version 2.0.
  20. #
  21. """Tests for porcelain mbox (mailsplit) functions."""
  22. import mailbox
  23. import os
  24. import tempfile
  25. from dulwich import porcelain
  26. from .. import TestCase
  27. class PorcelainMailsplitTests(TestCase):
  28. """Tests for porcelain.mailsplit function."""
  29. def test_mailsplit_mbox(self) -> None:
  30. """Test porcelain mailsplit with mbox file."""
  31. mbox_content = b"""\
  32. From alice@example.com Mon Jan 01 00:00:00 2025
  33. From: Alice <alice@example.com>
  34. Subject: Test
  35. Test message.
  36. """
  37. with tempfile.TemporaryDirectory() as tmpdir:
  38. mbox_path = os.path.join(tmpdir, "test.mbox")
  39. with open(mbox_path, "wb") as f:
  40. f.write(mbox_content)
  41. output_dir = os.path.join(tmpdir, "output")
  42. os.makedirs(output_dir)
  43. # Split using porcelain function
  44. output_files = porcelain.mailsplit(
  45. input_path=mbox_path, output_dir=output_dir
  46. )
  47. self.assertEqual(len(output_files), 1)
  48. self.assertEqual(output_files[0], os.path.join(output_dir, "0001"))
  49. def test_mailsplit_maildir(self) -> None:
  50. """Test porcelain mailsplit with Maildir."""
  51. with tempfile.TemporaryDirectory() as tmpdir:
  52. # Create a Maildir
  53. maildir_path = os.path.join(tmpdir, "maildir")
  54. md = mailbox.Maildir(maildir_path)
  55. msg = mailbox.MaildirMessage()
  56. msg.set_payload(b"Test message")
  57. msg["From"] = "test@example.com"
  58. md.add(msg)
  59. output_dir = os.path.join(tmpdir, "output")
  60. os.makedirs(output_dir)
  61. # Split using porcelain function with is_maildir=True
  62. output_files = porcelain.mailsplit(
  63. input_path=maildir_path, output_dir=output_dir, is_maildir=True
  64. )
  65. self.assertEqual(len(output_files), 1)
  66. self.assertTrue(os.path.exists(output_files[0]))
  67. def test_mailsplit_with_options(self) -> None:
  68. """Test porcelain mailsplit with various options."""
  69. mbox_content = b"""\
  70. From test@example.com Mon Jan 01 00:00:00 2025
  71. From: Test <test@example.com>
  72. Subject: Test
  73. Test message.
  74. """
  75. with tempfile.TemporaryDirectory() as tmpdir:
  76. mbox_path = os.path.join(tmpdir, "test.mbox")
  77. with open(mbox_path, "wb") as f:
  78. f.write(mbox_content)
  79. output_dir = os.path.join(tmpdir, "output")
  80. os.makedirs(output_dir)
  81. # Split with custom options
  82. output_files = porcelain.mailsplit(
  83. input_path=mbox_path,
  84. output_dir=output_dir,
  85. start_number=5,
  86. precision=3,
  87. keep_cr=True,
  88. )
  89. self.assertEqual(len(output_files), 1)
  90. self.assertEqual(output_files[0], os.path.join(output_dir, "005"))
  91. def test_mailsplit_mboxrd(self) -> None:
  92. """Test porcelain mailsplit with mboxrd format."""
  93. mbox_content = b"""\
  94. From test@example.com Mon Jan 01 00:00:00 2025
  95. From: Test <test@example.com>
  96. Subject: Test
  97. >From quoted text
  98. """
  99. with tempfile.TemporaryDirectory() as tmpdir:
  100. mbox_path = os.path.join(tmpdir, "test.mbox")
  101. with open(mbox_path, "wb") as f:
  102. f.write(mbox_content)
  103. output_dir = os.path.join(tmpdir, "output")
  104. os.makedirs(output_dir)
  105. # Split with mboxrd=True
  106. output_files = porcelain.mailsplit(
  107. input_path=mbox_path, output_dir=output_dir, mboxrd=True
  108. )
  109. self.assertEqual(len(output_files), 1)
  110. # Verify >From escaping was reversed
  111. with open(output_files[0], "rb") as f:
  112. content = f.read()
  113. expected = b"""\
  114. From: Test <test@example.com>
  115. Subject: Test
  116. From quoted text
  117. """
  118. self.assertEqual(content, expected)
  119. def test_mailsplit_maildir_requires_path(self) -> None:
  120. """Test that mailsplit raises ValueError when is_maildir=True but no input_path."""
  121. with tempfile.TemporaryDirectory() as tmpdir:
  122. output_dir = os.path.join(tmpdir, "output")
  123. os.makedirs(output_dir)
  124. with self.assertRaises(ValueError) as cm:
  125. porcelain.mailsplit(
  126. input_path=None, output_dir=output_dir, is_maildir=True
  127. )
  128. self.assertIn("required", str(cm.exception).lower())