;;; custom-tests.el --- tests for custom.el -*- lexical-binding: t -*- ;; Copyright (C) 2018-2020 Free Software Foundation, Inc. ;; This file is part of GNU Emacs. ;; GNU Emacs is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;;; Code: (require 'ert) (require 'wid-edit) (require 'cus-edit) (require 'seq) ; For `seq-find'. (ert-deftest custom-theme--load-path () "Test `custom-theme--load-path' behavior." (let ((tmpdir (file-name-as-directory (make-temp-file "custom-tests-" t)))) (unwind-protect ;; Create all temporary files under the same deletable parent. (let ((temporary-file-directory tmpdir)) ;; Path is empty. (let ((custom-theme-load-path ())) (should (null (custom-theme--load-path)))) ;; Path comprises non-existent file. (let* ((name (make-temp-name tmpdir)) (custom-theme-load-path (list name))) (should (not (file-exists-p name))) (should (null (custom-theme--load-path)))) ;; Path comprises existing file. (let* ((file (make-temp-file "file")) (custom-theme-load-path (list file))) (should (file-exists-p file)) (should (not (file-directory-p file))) (should (null (custom-theme--load-path)))) ;; Path comprises existing directory. (let* ((dir (make-temp-file "dir" t)) (custom-theme-load-path (list dir))) (should (file-directory-p dir)) (should (equal (custom-theme--load-path) custom-theme-load-path))) ;; Expand `custom-theme-directory' path element. (let ((custom-theme-load-path '(custom-theme-directory))) (let ((custom-theme-directory (make-temp-name tmpdir))) (should (not (file-exists-p custom-theme-directory))) (should (null (custom-theme--load-path)))) (let ((custom-theme-directory (make-temp-file "file"))) (should (file-exists-p custom-theme-directory)) (should (not (file-directory-p custom-theme-directory))) (should (null (custom-theme--load-path)))) (let ((custom-theme-directory (make-temp-file "dir" t))) (should (file-directory-p custom-theme-directory)) (should (equal (custom-theme--load-path) (list custom-theme-directory))))) ;; Expand t path element. (let ((custom-theme-load-path '(t))) (let ((data-directory (make-temp-name tmpdir))) (should (not (file-exists-p data-directory))) (should (null (custom-theme--load-path)))) (let ((data-directory tmpdir) (themedir (expand-file-name "themes" tmpdir))) (should (not (file-exists-p themedir))) (should (null (custom-theme--load-path))) (with-temp-file themedir) (should (file-exists-p themedir)) (should (not (file-directory-p themedir))) (should (null (custom-theme--load-path))) (delete-file themedir) (make-directory themedir) (should (file-directory-p themedir)) (should (equal (custom-theme--load-path) (list themedir)))))) (when (file-directory-p tmpdir) (delete-directory tmpdir t))))) (defcustom custom--test-user-option 'foo "User option for test." :group 'emacs :type 'symbol) (defvar custom--test-variable 'foo "Variable for test.") ;; This is demonstrating bug#34027. (ert-deftest custom--test-theme-variables () "Test variables setting with enabling / disabling a custom theme." ;; We load custom-resources/custom--test-theme.el. (let ((custom-theme-load-path `(,(expand-file-name "custom-resources" (expand-file-name "lisp" (getenv "EMACS_TEST_DIRECTORY")))))) (load-theme 'custom--test 'no-confirm 'no-enable) ;; The variables have still their initial values. (should (equal custom--test-user-option 'foo)) (should (equal custom--test-variable 'foo)) (custom-set-variables '(custom--test-user-option 'baz) '(custom--test-variable 'baz)) ;; The initial values have been changed. (should (equal custom--test-user-option 'baz)) (should (equal custom--test-variable 'baz)) ;; Enable and then disable. (enable-theme 'custom--test) (disable-theme 'custom--test) ;; The variables should have the changed values, by reverting. (should (equal custom--test-user-option 'baz)) (should (equal custom--test-variable 'baz)))) ;; This tests Bug#5358. (ert-deftest custom-test-show-comment-preserves-changes () "Test that adding a comment doesn't discard modifications in progress." (customize-option 'custom--test-user-option) (let* ((field (seq-find (lambda (widget) (eq custom--test-user-option (widget-value widget))) widget-field-list)) (parent (widget-get field :parent)) (origvalue (widget-value field))) ;; Move to the end of the text of the widget, and modify it. This ;; modification should be preserved after showing the comment field. (goto-char (widget-field-text-end field)) (insert "bar") (custom-comment-show parent) ;; From now on, must use `widget-at' to get the value of the widget. (should-not (eq origvalue (widget-value (widget-at)))) (should (eq (widget-get parent :custom-state) 'modified)) (should (eq (widget-value (widget-at)) (widget-apply field :value-to-external (concat (widget-apply field :value-to-internal origvalue) "bar")))))) ;; The following three tests demonstrate Bug#21355. ;; In this one, we set an user option for the current session, ;; then we enable a theme that doesn't have a setting for it, and we end up ;; with a 'saved-value property, and the caar of the 'theme-value property ;; is 'user, which means we would end up saving a setting that was meant ;; for the current session only. (ert-deftest custom-test-no-saved-value-after-enabling-theme () "Test that we don't record a saved-value property when we shouldn't." :expected-result :failed (let ((custom-theme-load-path `(,(expand-file-name "custom-resources" (expand-file-name "lisp" (getenv "EMACS_TEST_DIRECTORY")))))) (customize-option 'mark-ring-max) (let* ((field (seq-find (lambda (widget) (eq mark-ring-max (widget-value widget))) widget-field-list)) (parent (widget-get field :parent))) ;; We move to the editable widget, modify the value and save it. (goto-char (widget-field-text-end field)) (insert "0") (widget-apply parent :custom-set) ;; Just setting for the current session should not store a 'saved-value ;; property. (should-not (get 'mark-ring-max 'saved-value)) ;; Now we enable and disable our test theme. (load-theme 'custom--test 'no-confirm) (disable-theme 'custom--test) ;; Since the user customized the option, this happens. (should (eq (caar (get 'mark-ring-max 'theme-value)) 'user)) ;; But this should not happen: the 'saved-value property should still ;; be nil. (should-not (get 'mark-ring-max 'saved-value))))) ;; In this second test, we load a theme that has a setting for the user option ;; above. Regardless, the same happens: we end up with a non-nil saved-value ;; property, and a user setting active in the 'theme-value property, which ;; means we could inadvertently save the session setting in the custom-file. (defcustom custom--test-bug-21355-before 'foo "User option for `custom-test-no-saved-value-after-enabling-theme-2'." :type 'symbol :group 'emacs) (ert-deftest custom-test-no-saved-value-after-enabling-theme-2 () "Test that we don't record a saved-value property when we shouldn't." :expected-result :failed (let ((custom-theme-load-path `(,(file-name-as-directory (expand-file-name "custom-resources" (expand-file-name "lisp" (getenv "EMACS_TEST_DIRECTORY"))))))) (customize-option 'custom--test-bug-21355-before) (let* ((field (seq-find (lambda (widget) (eq custom--test-bug-21355-before (widget-value widget))) widget-field-list)) (parent (widget-get field :parent))) ;; We move to the editable widget, modify the value and save it. (goto-char (widget-field-text-end field)) ;; Modify the value and save it. (insert "bar") (widget-apply parent :custom-set) ;; Just setting for the current session should not store a 'saved-value ;; property. (should-not (get 'custom--test-bug-21355-before 'saved-value)) ;; Now we load our test theme, which has a setting for ;; `custom--test-user-option'. (load-theme 'custom--test-saved-value 'no-confirm) (enable-theme 'custom--test-saved-value) ;; We still shouldn't have a non-nil 'saved-value property, even if ;; the theme has a setting for the variable. ;; Since the user customized the option, this happens. (should (eq (caar (get 'custom--test-bug-21355-before 'theme-value)) 'user)) ;; But this should not happen. (should-not (get 'custom--test-bug-21355-before 'saved-value))))) ;; And in this test we check that stashing a theme value for a not yet defined ;; option works, but that later on if the user customizes the option for the ;; current session, we might save the theme setting in the custom file. (ert-deftest custom-test-no-saved-value-after-customizing-option () "Test that we don't have a non-nil saved-value after customizing an option." :expected-result :failed (let ((custom-theme-load-path `(,(file-name-as-directory (expand-file-name "custom-resources" (expand-file-name "lisp" (getenv "EMACS_TEST_DIRECTORY"))))))) ;; Check that we correctly stashed the value. (should (and (not (boundp 'custom--test-bug-21355-after)) (eq (eval (car (get 'custom--test-bug-21355-after 'saved-value))) 'after))) ;; Now Emacs finds the defcustom. (defcustom custom--test-bug-21355-after 'initially "..." :type 'symbol :group 'emacs) ;; And we used the stashed value correctly. (should (and (boundp 'custom--test-bug-21355-after) (eq custom--test-bug-21355-after 'after))) ;; Now we customize it. (customize-option 'custom--test-bug-21355-after) (let* ((field (seq-find (lambda (widget) (eq custom--test-bug-21355-after (widget-value widget))) widget-field-list)) (parent (widget-get field :parent))) ;; We move to the editable widget, modify the value and save it. (goto-char (widget-field-text-end field)) (insert "bar") (widget-apply parent :custom-set) ;; The user customized the variable, so this should happen. (should (eq (caar (get 'custom--test-bug-21355-after 'theme-value)) 'user)) ;; But it was only for the current session, so this should not happen. (should-not (get 'custom--test-bug-21355-after 'saved-value))))) ;;; custom-tests.el ends here