;;; test-custom-buffer-file--view-email-in-buffer.el --- Tests for email viewer -*- lexical-binding: t; -*- ;;; Commentary: ;; Unit tests for `cj/view-email-in-buffer' function. ;; ;; Tests cover: ;; - Normal: HTML emails, plain text emails, multipart preference ;; - Boundary: UTF-8 content, empty bodies, fallback behavior ;; - Error: Non-file buffers, missing displayable content ;; ;; Uses real MIME parsing via mm-decode to test actual integration behavior. ;;; Code: (require 'ert) (require 'testutil-general) (require 'custom-buffer-file) ;;; Test Data - Sample Email Content (defconst test-email--html-only "MIME-Version: 1.0 Content-Type: text/html; charset=\"utf-8\"

Hello World

This is a test.

" "Simple HTML-only email.") (defconst test-email--plain-only "MIME-Version: 1.0 Content-Type: text/plain; charset=\"utf-8\" Hello World This is a plain text email. " "Simple plain text email.") (defconst test-email--multipart-alternative "MIME-Version: 1.0 Content-Type: multipart/alternative; boundary=\"boundary123\" --boundary123 Content-Type: text/plain; charset=\"utf-8\" Plain text version of the email. --boundary123 Content-Type: text/html; charset=\"utf-8\"

HTML Version

Rich content here.

--boundary123-- " "Multipart email with both plain and HTML parts.") (defconst test-email--utf8-content "MIME-Version: 1.0 Content-Type: text/html; charset=\"utf-8\"

Caf\303\251 \342\230\225 \360\237\215\225 \344\270\255\346\226\207

" "Email with UTF-8 characters (cafe, coffee emoji, pizza emoji, Chinese).") (defconst test-email--empty-body "MIME-Version: 1.0 Content-Type: text/plain; charset=\"utf-8\" " "Email with empty body.") (defconst test-email--image-only "MIME-Version: 1.0 Content-Type: image/png Content-Transfer-Encoding: base64 iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg== " "Email with only an image attachment, no text content.") ;;; Setup and Teardown (defun test-email--setup () "Create test base directory." (cj/create-test-base-dir)) (defun test-email--teardown () "Clean up test files and buffers." ;; Kill any *Email:* buffers created during tests (dolist (buf (buffer-list)) (when (string-prefix-p "*Email:" (buffer-name buf)) (kill-buffer buf))) ;; Clean up test directory (cj/delete-test-base-dir)) (defun test-email--create-eml-file (content) "Create a temporary .eml file with CONTENT and return its path." (let ((file (cj/create-temp-test-file "test-email-")) (coding-system-for-write 'utf-8-unix)) (with-temp-file file (insert content)) (rename-file file (concat file ".eml")) (concat file ".eml"))) (defun test-email--get-rendered-content (eml-file) "Open EML-FILE, run view-email-in-buffer, return rendered buffer content." (let ((result nil)) (with-current-buffer (find-file-noselect eml-file) (cj/view-email-in-buffer) (let ((email-buf (format "*Email: %s*" (file-name-nondirectory eml-file)))) (when (get-buffer email-buf) (with-current-buffer email-buf (setq result (buffer-string))))) (kill-buffer)) result)) ;;; Normal Cases (ert-deftest test-custom-buffer-file--view-email-normal-html-renders () "Test that HTML email content is rendered. The HTML should be processed by shr and display readable text. Note: shr may insert newlines between words for wrapping." (test-email--setup) (unwind-protect (let* ((eml-file (test-email--create-eml-file test-email--html-only)) (content (test-email--get-rendered-content eml-file))) (should content) ;; shr may insert newlines for wrapping, so check words separately (should (string-match-p "Hello" content)) (should (string-match-p "World" content)) (should (string-match-p "test" content)) ;; HTML tags should be rendered, not visible as raw text (should-not (string-match-p "

" content))) (test-email--teardown))) (ert-deftest test-custom-buffer-file--view-email-normal-plain-text-displays () "Test that plain text email content is displayed." (test-email--setup) (unwind-protect (let* ((eml-file (test-email--create-eml-file test-email--plain-only)) (content (test-email--get-rendered-content eml-file))) (should content) (should (string-match-p "Hello World" content)) (should (string-match-p "plain text email" content))) (test-email--teardown))) (ert-deftest test-custom-buffer-file--view-email-normal-multipart-prefers-html () "Test that multipart/alternative email prefers HTML over plain text. Note: shr may insert newlines between words for wrapping." (test-email--setup) (unwind-protect (let* ((eml-file (test-email--create-eml-file test-email--multipart-alternative)) (content (test-email--get-rendered-content eml-file))) (should content) ;; Should contain HTML version content (words may be on separate lines) (should (string-match-p "HTML" content)) (should (string-match-p "Version" content)) (should (string-match-p "Rich" content)) ;; Should NOT contain plain text version marker (should-not (string-match-p "Plain text version" content)) ;; HTML should be rendered, not raw (should-not (string-match-p "

" content))) (test-email--teardown))) ;;; Boundary Cases (ert-deftest test-custom-buffer-file--view-email-boundary-utf8-content () "Test that UTF-8 characters are displayed correctly." (test-email--setup) (unwind-protect (let* ((eml-file (test-email--create-eml-file test-email--utf8-content)) (content (test-email--get-rendered-content eml-file))) (should content) ;; Should contain the UTF-8 content (café with accented e) (should (string-match-p "Caf" content))) (test-email--teardown))) (ert-deftest test-custom-buffer-file--view-email-boundary-empty-body () "Test that email with empty body creates buffer without error." (test-email--setup) (unwind-protect (let* ((eml-file (test-email--create-eml-file test-email--empty-body)) (content (test-email--get-rendered-content eml-file))) ;; Should succeed and return content (possibly empty string) (should (stringp content))) (test-email--teardown))) (ert-deftest test-custom-buffer-file--view-email-boundary-buffer-name-format () "Test that output buffer is named correctly with filename." (test-email--setup) (unwind-protect (let* ((eml-file (test-email--create-eml-file test-email--plain-only)) (expected-buf-name (format "*Email: %s*" (file-name-nondirectory eml-file)))) (with-current-buffer (find-file-noselect eml-file) (cj/view-email-in-buffer) (should (get-buffer expected-buf-name)) (kill-buffer)) (when (get-buffer expected-buf-name) (kill-buffer expected-buf-name))) (test-email--teardown))) (ert-deftest test-custom-buffer-file--view-email-boundary-special-mode () "Test that output buffer is in special-mode for easy dismissal." (test-email--setup) (unwind-protect (let* ((eml-file (test-email--create-eml-file test-email--plain-only)) (buf-name (format "*Email: %s*" (file-name-nondirectory eml-file)))) (with-current-buffer (find-file-noselect eml-file) (cj/view-email-in-buffer) (when (get-buffer buf-name) (with-current-buffer buf-name (should (derived-mode-p 'special-mode)))) (kill-buffer)) (when (get-buffer buf-name) (kill-buffer buf-name))) (test-email--teardown))) ;;; Error Cases (ert-deftest test-custom-buffer-file--view-email-error-not-visiting-file () "Test that error is signaled when buffer is not visiting a file." (with-temp-buffer (insert "some content") (should-error (cj/view-email-in-buffer) :type 'user-error))) (ert-deftest test-custom-buffer-file--view-email-error-no-displayable-content () "Test that error is signaled when email has no text/html or text/plain part." (test-email--setup) (unwind-protect (let ((eml-file (test-email--create-eml-file test-email--image-only))) (with-current-buffer (find-file-noselect eml-file) (should-error (cj/view-email-in-buffer) :type 'user-error) (kill-buffer))) (test-email--teardown))) (provide 'test-custom-buffer-file--view-email-in-buffer) ;;; test-custom-buffer-file--view-email-in-buffer.el ends here