summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/ChangeLog.12
-rw-r--r--test/Makefile.in17
-rw-r--r--test/README13
-rw-r--r--test/lib-src/emacsclient-tests.el2
-rw-r--r--test/lisp/abbrev-tests.el5
-rw-r--r--test/lisp/align-resources/align-post.c3
-rw-r--r--test/lisp/align-resources/align-post.java9
-rw-r--r--test/lisp/align-resources/align-pre.c3
-rw-r--r--test/lisp/align-resources/align-pre.java9
-rw-r--r--test/lisp/align-tests.el47
-rw-r--r--test/lisp/allout-tests.el148
-rw-r--r--test/lisp/allout-widgets-tests.el87
-rw-r--r--test/lisp/ansi-color-tests.el49
-rw-r--r--test/lisp/apropos-tests.el133
-rw-r--r--test/lisp/arc-mode-tests.el4
-rw-r--r--test/lisp/auth-source-pass-tests.el4
-rw-r--r--test/lisp/autoinsert-tests.el8
-rw-r--r--test/lisp/autorevert-tests.el749
-rw-r--r--test/lisp/battery-tests.el106
-rw-r--r--test/lisp/bookmark-resources/test-list.bmk20
-rw-r--r--test/lisp/bookmark-tests.el308
-rw-r--r--test/lisp/button-tests.el35
-rw-r--r--test/lisp/calc/calc-tests.el414
-rw-r--r--test/lisp/calendar/cal-julian-tests.el72
-rw-r--r--test/lisp/calendar/icalendar-resources/import-bug-11473.diary-european10
-rw-r--r--test/lisp/calendar/icalendar-resources/import-bug-11473.ics54
-rw-r--r--test/lisp/calendar/icalendar-resources/import-bug-22092.diary-american6
-rw-r--r--test/lisp/calendar/icalendar-resources/import-bug-22092.diary-european6
-rw-r--r--test/lisp/calendar/icalendar-resources/import-bug-22092.diary-iso6
-rw-r--r--test/lisp/calendar/icalendar-resources/import-bug-22092.ics30
-rw-r--r--test/lisp/calendar/icalendar-resources/import-bug-24199.diary-american5
-rw-r--r--test/lisp/calendar/icalendar-resources/import-bug-24199.diary-european5
-rw-r--r--test/lisp/calendar/icalendar-resources/import-bug-24199.diary-iso5
-rw-r--r--test/lisp/calendar/icalendar-resources/import-bug-24199.ics25
-rw-r--r--test/lisp/calendar/icalendar-resources/import-bug-33277.diary-american1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-bug-33277.diary-european1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-bug-33277.diary-iso1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-bug-33277.ics15
-rw-r--r--test/lisp/calendar/icalendar-resources/import-bug-6766.diary-american7
-rw-r--r--test/lisp/calendar/icalendar-resources/import-bug-6766.diary-european7
-rw-r--r--test/lisp/calendar/icalendar-resources/import-bug-6766.diary-iso7
-rw-r--r--test/lisp/calendar/icalendar-resources/import-bug-6766.ics28
-rw-r--r--test/lisp/calendar/icalendar-resources/import-duration-2.diary-american3
-rw-r--r--test/lisp/calendar/icalendar-resources/import-duration-2.diary-european3
-rw-r--r--test/lisp/calendar/icalendar-resources/import-duration-2.diary-iso3
-rw-r--r--test/lisp/calendar/icalendar-resources/import-duration-2.ics17
-rw-r--r--test/lisp/calendar/icalendar-resources/import-duration.diary-american1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-duration.diary-european1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-duration.diary-iso1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-duration.ics10
-rw-r--r--test/lisp/calendar/icalendar-resources/import-multiple-vcalendars.diary-american4
-rw-r--r--test/lisp/calendar/icalendar-resources/import-multiple-vcalendars.diary-european4
-rw-r--r--test/lisp/calendar/icalendar-resources/import-multiple-vcalendars.diary-iso4
-rw-r--r--test/lisp/calendar/icalendar-resources/import-multiple-vcalendars.ics21
-rw-r--r--test/lisp/calendar/icalendar-resources/import-non-recurring-1.diary-american1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-non-recurring-1.diary-european1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-non-recurring-1.diary-iso1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-non-recurring-1.ics10
-rw-r--r--test/lisp/calendar/icalendar-resources/import-non-recurring-all-day.diary-american1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-non-recurring-all-day.diary-european1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-non-recurring-all-day.diary-iso1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-non-recurring-all-day.ics9
-rw-r--r--test/lisp/calendar/icalendar-resources/import-non-recurring-another-example.diary-american4
-rw-r--r--test/lisp/calendar/icalendar-resources/import-non-recurring-another-example.diary-european4
-rw-r--r--test/lisp/calendar/icalendar-resources/import-non-recurring-another-example.diary-iso4
-rw-r--r--test/lisp/calendar/icalendar-resources/import-non-recurring-another-example.ics23
-rw-r--r--test/lisp/calendar/icalendar-resources/import-non-recurring-block.diary-american4
-rw-r--r--test/lisp/calendar/icalendar-resources/import-non-recurring-block.diary-european4
-rw-r--r--test/lisp/calendar/icalendar-resources/import-non-recurring-block.diary-iso4
-rw-r--r--test/lisp/calendar/icalendar-resources/import-non-recurring-block.ics16
-rw-r--r--test/lisp/calendar/icalendar-resources/import-non-recurring-folded-summary.diary-american4
-rw-r--r--test/lisp/calendar/icalendar-resources/import-non-recurring-folded-summary.diary-european4
-rw-r--r--test/lisp/calendar/icalendar-resources/import-non-recurring-folded-summary.diary-iso4
-rw-r--r--test/lisp/calendar/icalendar-resources/import-non-recurring-folded-summary.ics25
-rw-r--r--test/lisp/calendar/icalendar-resources/import-non-recurring-long-summary.diary-american1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-non-recurring-long-summary.diary-european1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-non-recurring-long-summary.diary-iso1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-non-recurring-long-summary.ics10
-rw-r--r--test/lisp/calendar/icalendar-resources/import-real-world-2003-05-29.diary-american6
-rw-r--r--test/lisp/calendar/icalendar-resources/import-real-world-2003-05-29.diary-european6
-rw-r--r--test/lisp/calendar/icalendar-resources/import-real-world-2003-05-29.ics54
-rw-r--r--test/lisp/calendar/icalendar-resources/import-real-world-2003-06-18a.diary-american6
-rw-r--r--test/lisp/calendar/icalendar-resources/import-real-world-2003-06-18a.diary-european6
-rw-r--r--test/lisp/calendar/icalendar-resources/import-real-world-2003-06-18a.ics36
-rw-r--r--test/lisp/calendar/icalendar-resources/import-real-world-2003-06-18b.diary-american6
-rw-r--r--test/lisp/calendar/icalendar-resources/import-real-world-2003-06-18b.diary-european6
-rw-r--r--test/lisp/calendar/icalendar-resources/import-real-world-2003-06-18b.ics55
-rw-r--r--test/lisp/calendar/icalendar-resources/import-real-world-2004-11-19.diary-american19
-rw-r--r--test/lisp/calendar/icalendar-resources/import-real-world-2004-11-19.diary-european19
-rw-r--r--test/lisp/calendar/icalendar-resources/import-real-world-2004-11-19.ics120
-rw-r--r--test/lisp/calendar/icalendar-resources/import-real-world-2005-02-07.diary-american5
-rw-r--r--test/lisp/calendar/icalendar-resources/import-real-world-2005-02-07.diary-european5
-rw-r--r--test/lisp/calendar/icalendar-resources/import-real-world-2005-02-07.ics26
-rw-r--r--test/lisp/calendar/icalendar-resources/import-real-world-2005-03-01.diary-american2
-rw-r--r--test/lisp/calendar/icalendar-resources/import-real-world-2005-03-01.diary-european2
-rw-r--r--test/lisp/calendar/icalendar-resources/import-real-world-2005-03-01.ics11
-rw-r--r--test/lisp/calendar/icalendar-resources/import-real-world-no-dst.diary-american4
-rw-r--r--test/lisp/calendar/icalendar-resources/import-real-world-no-dst.diary-european4
-rw-r--r--test/lisp/calendar/icalendar-resources/import-real-world-no-dst.ics26
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-anniversary.diary-american1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-anniversary.diary-european1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-anniversary.diary-iso1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-anniversary.ics11
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-bi-weekly.diary-american1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-bi-weekly.diary-european1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-bi-weekly.diary-iso1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-bi-weekly.ics11
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-daily-long.diary-american1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-daily-long.diary-european1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-daily-long.diary-iso1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-daily-long.ics11
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-daily-short.diary-american1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-daily-short.diary-european1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-daily-short.diary-iso1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-daily-short.ics11
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-month.diary-american1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-month.diary-european1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-month.diary-iso1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-month.ics11
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-year.diary-american1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-year.diary-european1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-year.diary-iso1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-year.ics10
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-monthly.diary-american1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-monthly.diary-european1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-monthly.diary-iso1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-monthly.ics11
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-yearly.diary-american1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-yearly.diary-european1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-yearly.diary-iso1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-count-yearly.ics11
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-daily-two-day.diary-american1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-daily-two-day.diary-european1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-daily-two-day.diary-iso1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-daily-two-day.ics10
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-daily-with-exceptions.diary-american1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-daily-with-exceptions.diary-european1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-daily-with-exceptions.diary-iso1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-daily-with-exceptions.ics12
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-daily.diary-american1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-daily.diary-european1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-daily.diary-iso1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-daily.ics11
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-monthly-no-end.diary-american1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-monthly-no-end.diary-european1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-monthly-no-end.diary-iso1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-monthly-no-end.ics11
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-monthly-with-end.diary-american1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-monthly-with-end.diary-european1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-monthly-with-end.diary-iso1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-monthly-with-end.ics11
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-weekly.diary-american1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-weekly.diary-european1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-weekly.diary-iso1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-weekly.ics11
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-yearly.diary-american1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-yearly.diary-european1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-yearly.diary-iso1
-rw-r--r--test/lisp/calendar/icalendar-resources/import-rrule-yearly.ics11
-rw-r--r--test/lisp/calendar/icalendar-resources/import-with-timezone.diary-iso2
-rw-r--r--test/lisp/calendar/icalendar-resources/import-with-timezone.ics27
-rw-r--r--test/lisp/calendar/icalendar-resources/import-with-uid.diary-american2
-rw-r--r--test/lisp/calendar/icalendar-resources/import-with-uid.diary-european2
-rw-r--r--test/lisp/calendar/icalendar-resources/import-with-uid.diary-iso2
-rw-r--r--test/lisp/calendar/icalendar-resources/import-with-uid.ics10
-rw-r--r--test/lisp/calendar/icalendar-tests.el1364
-rw-r--r--test/lisp/calendar/iso8601-tests.el185
-rw-r--r--test/lisp/calendar/lunar-tests.el75
-rw-r--r--test/lisp/calendar/parse-time-tests.el2
-rw-r--r--test/lisp/calendar/solar-tests.el42
-rw-r--r--test/lisp/calendar/time-date-tests.el97
-rw-r--r--test/lisp/calendar/todo-mode-resources/todo-test-1.todo10
-rw-r--r--test/lisp/calendar/todo-mode-tests.el116
-rw-r--r--test/lisp/cedet/semantic-utest-c.el59
-rw-r--r--test/lisp/cedet/semantic-utest-fmt.el4
-rw-r--r--test/lisp/cedet/semantic-utest-ia.el9
-rw-r--r--test/lisp/cedet/semantic-utest.el39
-rw-r--r--test/lisp/cedet/srecode-utest-getset.el4
-rw-r--r--test/lisp/cedet/srecode-utest-template.el7
-rw-r--r--test/lisp/char-fold-tests.el8
-rw-r--r--test/lisp/comint-tests.el81
-rw-r--r--test/lisp/completion-tests.el170
-rw-r--r--test/lisp/cus-edit-tests.el80
-rw-r--r--test/lisp/custom-resources/custom--test-theme.el2
-rw-r--r--test/lisp/custom-tests.el32
-rw-r--r--test/lisp/dabbrev-tests.el2
-rw-r--r--test/lisp/descr-text-tests.el6
-rw-r--r--test/lisp/dired-aux-tests.el47
-rw-r--r--test/lisp/dired-tests.el80
-rw-r--r--test/lisp/dom-tests.el7
-rw-r--r--test/lisp/electric-tests.el26
-rw-r--r--test/lisp/elide-head-tests.el62
-rw-r--r--test/lisp/emacs-lisp/bindat-tests.el26
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/error-lexical-var-with-add-hook.el4
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/error-lexical-var-with-remove-hook.el4
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/error-lexical-var-with-run-hook-with-args-until-failure.el3
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/error-lexical-var-with-run-hook-with-args-until-success.el3
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/error-lexical-var-with-run-hook-with-args.el3
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/error-lexical-var-with-symbol-value.el4
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-autoload-not-on-top-level.el3
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-callargs.el5
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-defcustom-nogroup.el3
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-defcustom-notype.el3
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-defvar-lacks-prefix.el2
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-format.el2
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-free-setq.el2
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-free-variable-reference.el4
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-interactive-only.el3
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-lambda-malformed-interactive-spec.el4
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-make-variable-buffer-local.el4
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-obsolete-defun.el8
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-obsolete-hook.el3
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-obsolete-variable-same-file.el13
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-obsolete-variable.el4
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-redefine-defun-as-macro.el3
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-redefine-defun.el3
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-redefine-macro-as-defun.el3
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-save-excursion.el5
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-variable-let-bind-constant.el3
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-variable-let-bind-nonvariable.el3
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-variable-set-constant.el3
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-variable-set-nonvariable.el3
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-autoload.el3
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-custom-declare-variable.el4
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-defalias.el3
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-defconst.el3
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-define-abbrev-table.el3
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-define-obsolete-function-alias.el3
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-define-obsolete-variable-alias.el3
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-defun.el3
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-defvar.el6
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-defvaralias.el3
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-ignore-fill-column.el7
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-ignore-override.el8
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-ignore.el7
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-multiline-first.el5
-rw-r--r--test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-multiline.el6
-rw-r--r--test/lisp/emacs-lisp/bytecomp-tests.el368
-rw-r--r--test/lisp/emacs-lisp/cconv-tests.el160
-rw-r--r--test/lisp/emacs-lisp/check-declare-tests.el116
-rw-r--r--test/lisp/emacs-lisp/cl-generic-tests.el40
-rw-r--r--test/lisp/emacs-lisp/cl-lib-tests.el16
-rw-r--r--test/lisp/emacs-lisp/cl-macs-tests.el24
-rw-r--r--test/lisp/emacs-lisp/cl-seq-tests.el1
-rw-r--r--test/lisp/emacs-lisp/copyright-tests.el50
-rw-r--r--test/lisp/emacs-lisp/easy-mmode-tests.el65
-rw-r--r--test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el2
-rw-r--r--test/lisp/emacs-lisp/edebug-tests.el116
-rw-r--r--test/lisp/emacs-lisp/eieio-tests/eieio-test-methodinvoke.el58
-rw-r--r--test/lisp/emacs-lisp/eieio-tests/eieio-test-persist.el2
-rw-r--r--test/lisp/emacs-lisp/eieio-tests/eieio-tests.el5
-rw-r--r--test/lisp/emacs-lisp/ert-tests.el15
-rw-r--r--test/lisp/emacs-lisp/ert-x-tests.el23
-rw-r--r--test/lisp/emacs-lisp/faceup-resources/faceup-test-mode.el8
-rw-r--r--test/lisp/emacs-lisp/faceup-resources/faceup-test-this-file-directory.el2
-rw-r--r--test/lisp/emacs-lisp/faceup-resources/files/test1.txt.faceup2
-rw-r--r--test/lisp/emacs-lisp/faceup-tests/faceup-test-basics.el2
-rw-r--r--test/lisp/emacs-lisp/faceup-tests/faceup-test-files.el2
-rw-r--r--test/lisp/emacs-lisp/find-func-tests.el120
-rw-r--r--test/lisp/emacs-lisp/float-sup-tests.el33
-rw-r--r--test/lisp/emacs-lisp/generator-tests.el11
-rw-r--r--test/lisp/emacs-lisp/gv-tests.el75
-rw-r--r--test/lisp/emacs-lisp/hierarchy-tests.el556
-rw-r--r--test/lisp/emacs-lisp/lisp-mode-tests.el14
-rw-r--r--test/lisp/emacs-lisp/lisp-tests.el60
-rw-r--r--test/lisp/emacs-lisp/map-tests.el6
-rw-r--r--test/lisp/emacs-lisp/memory-report-tests.el57
-rw-r--r--test/lisp/emacs-lisp/nadvice-tests.el2
-rw-r--r--test/lisp/emacs-lisp/package-resources/key.pub32
-rw-r--r--test/lisp/emacs-lisp/package-resources/key.sec62
-rw-r--r--test/lisp/emacs-lisp/package-resources/newer-versions/new-pkg-1.0.el2
-rw-r--r--test/lisp/emacs-lisp/package-resources/newer-versions/simple-single-1.4.el2
-rw-r--r--test/lisp/emacs-lisp/package-resources/signed/archive-contents.sigbin287 -> 181 bytes
-rw-r--r--test/lisp/emacs-lisp/package-resources/signed/signed-bad-1.0.el2
-rw-r--r--test/lisp/emacs-lisp/package-resources/signed/signed-good-1.0.el2
-rw-r--r--test/lisp/emacs-lisp/package-resources/signed/signed-good-1.0.el.sigbin287 -> 181 bytes
-rwxr-xr-xtest/lisp/emacs-lisp/package-resources/signed/update-signatures.sh32
-rw-r--r--test/lisp/emacs-lisp/package-resources/simple-depend-1.0.el2
-rw-r--r--test/lisp/emacs-lisp/package-resources/simple-single-1.3.el2
-rw-r--r--test/lisp/emacs-lisp/package-resources/simple-two-depend-1.1.el2
-rw-r--r--test/lisp/emacs-lisp/package-tests.el197
-rw-r--r--test/lisp/emacs-lisp/pcase-tests.el2
-rw-r--r--test/lisp/emacs-lisp/regexp-opt-tests.el29
-rw-r--r--test/lisp/emacs-lisp/rmc-tests.el8
-rw-r--r--test/lisp/emacs-lisp/rx-tests.el24
-rw-r--r--test/lisp/emacs-lisp/seq-tests.el10
-rw-r--r--test/lisp/emacs-lisp/shadow-resources/p1/foo.el2
-rw-r--r--test/lisp/emacs-lisp/shadow-resources/p2/FOO.el2
-rw-r--r--test/lisp/emacs-lisp/shadow-tests.el21
-rw-r--r--test/lisp/emacs-lisp/subr-x-tests.el63
-rw-r--r--test/lisp/emacs-lisp/syntax-tests.el67
-rw-r--r--test/lisp/emacs-lisp/testcover-tests.el24
-rw-r--r--test/lisp/emacs-lisp/text-property-search-tests.el28
-rw-r--r--test/lisp/emacs-lisp/unsafep-tests.el154
-rw-r--r--test/lisp/emacs-lisp/warnings-tests.el60
-rw-r--r--test/lisp/emulation/viper-tests.el2
-rwxr-xr-xtest/lisp/epg-resources/dummy-pinentry (renamed from test/data/epg/dummy-pinentry)0
-rw-r--r--test/lisp/epg-resources/pubkey.asc (renamed from test/data/epg/pubkey.asc)0
-rw-r--r--test/lisp/epg-resources/seckey.asc (renamed from test/data/epg/seckey.asc)0
-rw-r--r--test/lisp/epg-tests.el15
-rw-r--r--test/lisp/erc/erc-tests.el47
-rw-r--r--test/lisp/erc/erc-track-tests.el7
-rw-r--r--test/lisp/eshell/em-hist-tests.el2
-rw-r--r--test/lisp/eshell/em-ls-tests.el2
-rw-r--r--test/lisp/eshell/esh-opt-tests.el2
-rw-r--r--test/lisp/eshell/eshell-tests.el11
-rw-r--r--test/lisp/faces-resources/faces-test-dark-theme.el (renamed from test/data/themes/faces-test-dark-theme.el)8
-rw-r--r--test/lisp/faces-resources/faces-test-light-theme.el (renamed from test/data/themes/faces-test-light-theme.el)8
-rw-r--r--test/lisp/faces-tests.el17
-rw-r--r--test/lisp/ffap-tests.el48
-rw-r--r--test/lisp/filenotify-tests.el152
-rw-r--r--test/lisp/files-resources/files-bug18141.el.gz (renamed from test/data/files-bug18141.el.gz)bin77 -> 77 bytes
-rw-r--r--test/lisp/files-tests.el114
-rw-r--r--test/lisp/files-x-tests.el11
-rw-r--r--test/lisp/format-spec-tests.el145
-rw-r--r--test/lisp/gnus/gnus-icalendar-tests.el259
-rw-r--r--test/lisp/gnus/gnus-search-tests.el96
-rw-r--r--test/lisp/gnus/gnus-tests.el2
-rw-r--r--test/lisp/gnus/gnus-util-tests.el172
-rw-r--r--test/lisp/gnus/mml-sec-resources/.gpg-v21-migrated (renamed from test/data/minibuffer-test-cttq$tion)0
-rw-r--r--test/lisp/gnus/mml-sec-resources/gpg-agent.conf5
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/02089CDDC6DFE93B8EA10D9E876F983E61FEC476.keybin0 -> 797 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/171B444DE92BEF997229000D9784118A94EEC1C9.keybin0 -> 526 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/19FFEBC04DF3E037E16F6A4474DCB7984406975D.keybin0 -> 841 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/1E36D27DF9DAB96302D35268DADC5CE73EF45A2A.keybin0 -> 797 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/293109315BE584AB2EFEFCFCAD64666221D8B36C.keybin0 -> 526 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/335689599E1C0F66D73ADCF51E03EE36C97D121F.keybin0 -> 797 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/40BF94E540E3726CB150A1ADF7C1B514444B3FA6.keybin0 -> 797 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/515D4637EFC6C09DB1F78BE8C2F2A3D63E7756C3.keybin0 -> 798 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/5A11B1935C46D0B227A73978DCA1293A85604F1D.keybin0 -> 798 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/62643CEBC7AEBE6817577A34399483700D76BD64.keybin0 -> 526 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/680D01F368916A0021C14E3453B27B3C5F900683.keybin0 -> 710 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/6DF2D9DF7AED06F0524BEB642DF0FB48EFDBDB93.keybin0 -> 798 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/78C17E134E86E691297F7B719B2F2CDF41976234.keybin0 -> 527 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/7F714F4D9D9676638214991E96D45704E4FFC409.keybin0 -> 798 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/854752F5D8090CA36EFBDD79C72BDFF6FA2D1FF0.keybin0 -> 526 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/93FF37C268FDBF0767F5FFDC49409DDAC9388B2C.keybin0 -> 709 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/A3BA94EAE83509CC90DB1B77B54A51959D8DABEA.keybin0 -> 797 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/A73E9D01F0465B518E8E7D5AD529077AAC1603B4.keybin0 -> 710 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/AE6A24B17A8D0CAF9B7E000AA77F0B41D7BFFFCF.keybin0 -> 841 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/C072AF82DCCCB9A7F1B85FFA10B802DC4ED16703.keybin0 -> 841 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/C43E1A079B28DFAEBB39CBA01793BDE11EF4B490.keybin0 -> 527 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/C67DAD345455EAD6D51368008FC3A53B8D195B5A.keybin0 -> 710 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/CB5E00CE582C2645D2573FC16B2F14F85A7F47AA.keybin0 -> 797 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/CC68630A06B048F5A91136C162C7A3273E20DE6F.keybin0 -> 710 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/E7E73903E1BF93481DE0E7C9769D6C31E1863CFF.keybin0 -> 797 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/F0117468BE801ED4B81972E159A98FDD4814DCEC.keybin0 -> 797 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/private-keys-v1.d/F4C5EFD5779BE892CAFD5B721D68DED677C9B151.keybin0 -> 841 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/pubring.gpgbin0 -> 13883 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/pubring.kbxbin0 -> 3076 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/secring.gpgbin0 -> 17362 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/trustdb.gpgbin0 -> 1880 bytes
-rw-r--r--test/lisp/gnus/mml-sec-resources/trustlist.txt26
-rw-r--r--test/lisp/gnus/mml-sec-tests.el896
-rw-r--r--test/lisp/help-fns-tests.el64
-rw-r--r--test/lisp/help-mode-tests.el169
-rw-r--r--test/lisp/help-tests.el347
-rw-r--r--test/lisp/hfy-cmap-resources/rgb.txt4
-rw-r--r--test/lisp/hfy-cmap-tests.el55
-rw-r--r--test/lisp/hi-lock-tests.el164
-rw-r--r--test/lisp/ibuffer-tests.el2
-rw-r--r--test/lisp/image/gravatar-tests.el9
-rw-r--r--test/lisp/imenu-tests.el17
-rw-r--r--test/lisp/info-xref-tests.el2
-rw-r--r--test/lisp/international/ccl-tests.el16
-rw-r--r--test/lisp/international/mule-tests.el32
-rw-r--r--test/lisp/international/mule-util-tests.el9
-rw-r--r--test/lisp/international/ucs-normalize-tests.el13
-rw-r--r--test/lisp/isearch-tests.el8
-rw-r--r--test/lisp/jit-lock-tests.el2
-rw-r--r--test/lisp/json-tests.el875
-rw-r--r--test/lisp/jsonrpc-tests.el10
-rw-r--r--test/lisp/mail/flow-fill-tests.el3
-rw-r--r--test/lisp/mail/footnote-tests.el8
-rw-r--r--test/lisp/mail/qp-tests.el74
-rw-r--r--test/lisp/mail/rfc2045-tests.el37
-rw-r--r--test/lisp/mail/rfc2368-tests.el39
-rw-r--r--test/lisp/mail/rfc822-tests.el83
-rw-r--r--test/lisp/mail/rmailmm-tests.el (renamed from test/manual/rmailmm.el)60
-rw-r--r--test/lisp/mail/uudecode-tests.el14
-rw-r--r--test/lisp/man-tests.el8
-rw-r--r--test/lisp/minibuffer-resources/data/minibuffer-test-cttq$tion0
-rw-r--r--test/lisp/minibuffer-resources/lisp/cedet/semantic-utest-c.test0
-rw-r--r--test/lisp/minibuffer-resources/lisp/cedet/semantic-utest.test0
-rw-r--r--test/lisp/minibuffer-tests.el13
-rw-r--r--test/lisp/misc-tests.el77
-rw-r--r--test/lisp/mwheel-tests.el46
-rw-r--r--test/lisp/net/browse-url-tests.el119
-rw-r--r--test/lisp/net/dbus-resources/org.gnu.Emacs.TestDBus.xml49
-rw-r--r--test/lisp/net/dbus-tests.el1891
-rw-r--r--test/lisp/net/dig-tests.el56
-rw-r--r--test/lisp/net/gnutls-tests.el3
-rw-r--r--test/lisp/net/hmac-md5-tests.el80
-rw-r--r--test/lisp/net/mailcap-resources/mime.types (renamed from test/data/mailcap/mime.types)0
-rw-r--r--test/lisp/net/mailcap-tests.el7
-rw-r--r--test/lisp/net/netrc-resources/authinfo2
-rw-r--r--test/lisp/net/netrc-resources/services6
-rw-r--r--test/lisp/net/netrc-tests.el53
-rw-r--r--test/lisp/net/network-stream-resources/cert.pem (renamed from test/data/net/cert.pem)0
-rw-r--r--test/lisp/net/network-stream-resources/key.pem (renamed from test/data/net/key.pem)0
-rw-r--r--test/lisp/net/network-stream-tests.el74
-rw-r--r--test/lisp/net/newsticker-tests.el2
-rw-r--r--test/lisp/net/ntlm-tests.el52
-rw-r--r--test/lisp/net/puny-tests.el23
-rw-r--r--test/lisp/net/rcirc-tests.el20
-rw-r--r--test/lisp/net/rfc2104-tests.el10
-rw-r--r--test/lisp/net/sasl-scram-rfc-tests.el26
-rw-r--r--test/lisp/net/secrets-tests.el8
-rw-r--r--test/lisp/net/shr-resources/div-div.html (renamed from test/data/shr/div-div.html)0
-rw-r--r--test/lisp/net/shr-resources/div-div.txt (renamed from test/data/shr/div-div.txt)0
-rw-r--r--test/lisp/net/shr-resources/div-p.html (renamed from test/data/shr/div-p.html)0
-rw-r--r--test/lisp/net/shr-resources/div-p.txt (renamed from test/data/shr/div-p.txt)0
-rw-r--r--test/lisp/net/shr-resources/li-div.html (renamed from test/data/shr/li-div.html)0
-rw-r--r--test/lisp/net/shr-resources/li-div.txt (renamed from test/data/shr/li-div.txt)0
-rw-r--r--test/lisp/net/shr-resources/li-empty.html (renamed from test/data/shr/li-empty.html)0
-rw-r--r--test/lisp/net/shr-resources/li-empty.txt (renamed from test/data/shr/li-empty.txt)0
-rw-r--r--test/lisp/net/shr-resources/nonbr.html (renamed from test/data/shr/nonbr.html)0
-rw-r--r--test/lisp/net/shr-resources/nonbr.txt (renamed from test/data/shr/nonbr.txt)0
-rw-r--r--test/lisp/net/shr-resources/ol.html (renamed from test/data/shr/ol.html)0
-rw-r--r--test/lisp/net/shr-resources/ol.txt (renamed from test/data/shr/ol.txt)0
-rw-r--r--test/lisp/net/shr-resources/ul-empty.html (renamed from test/data/shr/ul-empty.html)0
-rw-r--r--test/lisp/net/shr-resources/ul-empty.txt (renamed from test/data/shr/ul-empty.txt)0
-rw-r--r--test/lisp/net/shr-tests.el11
-rw-r--r--test/lisp/net/tramp-archive-tests.el88
-rw-r--r--test/lisp/net/tramp-tests.el891
-rw-r--r--test/lisp/net/webjump-tests.el73
-rw-r--r--test/lisp/nxml/nxml-mode-tests.el21
-rw-r--r--test/lisp/nxml/xsd-regexp-tests.el30
-rw-r--r--test/lisp/obsolete/cl-tests.el3
-rw-r--r--test/lisp/org/org-tests.el2
-rw-r--r--test/lisp/password-cache-tests.el14
-rw-r--r--test/lisp/pcmpl-linux-resources/fs/ext4/.keep0
-rw-r--r--test/lisp/pcmpl-linux-resources/mtab11
-rw-r--r--test/lisp/pcmpl-linux-tests.el43
-rw-r--r--test/lisp/play/animate-tests.el56
-rw-r--r--test/lisp/play/dissociate-tests.el38
-rw-r--r--test/lisp/play/fortune-resources/fortunes11
-rw-r--r--test/lisp/play/fortune-tests.el41
-rw-r--r--test/lisp/play/life-tests.el80
-rw-r--r--test/lisp/progmodes/autoconf-tests.el55
-rw-r--r--test/lisp/progmodes/cc-mode-tests.el33
-rw-r--r--test/lisp/progmodes/compile-tests.el461
-rw-r--r--test/lisp/progmodes/cperl-mode-resources/cperl-bug-19709.pl25
-rw-r--r--test/lisp/progmodes/cperl-mode-resources/cperl-bug-26850.pl16
-rw-r--r--test/lisp/progmodes/cperl-mode-resources/cperl-bug-30393.pl19
-rw-r--r--test/lisp/progmodes/cperl-mode-resources/cperl-indent-exp.pl52
-rw-r--r--test/lisp/progmodes/cperl-mode-resources/cperl-indent-styles.pl54
-rw-r--r--test/lisp/progmodes/cperl-mode-resources/fontify-punctuation-vars.pl20
-rw-r--r--test/lisp/progmodes/cperl-mode-tests.el323
-rw-r--r--test/lisp/progmodes/elisp-mode-tests.el18
-rw-r--r--test/lisp/progmodes/etags-tests.el2
-rw-r--r--test/lisp/progmodes/f90-tests.el3
-rw-r--r--test/lisp/progmodes/gdb-mi-tests.el46
-rw-r--r--test/lisp/progmodes/glasses-tests.el101
-rw-r--r--test/lisp/progmodes/js-resources/js-chain.js (renamed from test/manual/indent/js-chain.js)0
-rw-r--r--test/lisp/progmodes/js-resources/js-indent-align-list-continuation-nil.js (renamed from test/manual/indent/js-indent-align-list-continuation-nil.js)0
-rw-r--r--test/lisp/progmodes/js-resources/js-indent-init-dynamic.js (renamed from test/manual/indent/js-indent-init-dynamic.js)0
-rw-r--r--test/lisp/progmodes/js-resources/js-indent-init-t.js (renamed from test/manual/indent/js-indent-init-t.js)0
-rw-r--r--test/lisp/progmodes/js-resources/js.js (renamed from test/manual/indent/js.js)0
-rw-r--r--test/lisp/progmodes/js-resources/jsx-align-gt-with-lt.jsx (renamed from test/manual/indent/jsx-align-gt-with-lt.jsx)0
-rw-r--r--test/lisp/progmodes/js-resources/jsx-comment-string.jsx (renamed from test/manual/indent/jsx-comment-string.jsx)0
-rw-r--r--test/lisp/progmodes/js-resources/jsx-indent-level.jsx (renamed from test/manual/indent/jsx-indent-level.jsx)0
-rw-r--r--test/lisp/progmodes/js-resources/jsx-quote.jsx (renamed from test/manual/indent/jsx-quote.jsx)0
-rw-r--r--test/lisp/progmodes/js-resources/jsx-self-closing.jsx (renamed from test/manual/indent/jsx-self-closing.jsx)0
-rw-r--r--test/lisp/progmodes/js-resources/jsx-unclosed-1.jsx (renamed from test/manual/indent/jsx-unclosed-1.jsx)0
-rw-r--r--test/lisp/progmodes/js-resources/jsx-unclosed-2.jsx (renamed from test/manual/indent/jsx-unclosed-2.jsx)0
-rw-r--r--test/lisp/progmodes/js-resources/jsx.jsx (renamed from test/manual/indent/jsx.jsx)0
-rw-r--r--test/lisp/progmodes/js-tests.el43
-rw-r--r--test/lisp/progmodes/opascal-tests.el45
-rw-r--r--test/lisp/progmodes/pascal-tests.el63
-rw-r--r--test/lisp/progmodes/perl-mode-tests.el33
-rw-r--r--test/lisp/progmodes/ps-mode-tests.el26
-rw-r--r--test/lisp/progmodes/python-tests.el17
-rw-r--r--test/lisp/progmodes/ruby-mode-resources/ruby.rb (renamed from test/manual/indent/ruby.rb)12
-rw-r--r--test/lisp/progmodes/ruby-mode-tests.el37
-rw-r--r--test/lisp/progmodes/scheme-tests.el50
-rw-r--r--test/lisp/progmodes/subword-tests.el10
-rw-r--r--test/lisp/progmodes/tcl-tests.el2
-rw-r--r--test/lisp/progmodes/xref-resources/file1.txt (renamed from test/data/xref/file1.txt)0
-rw-r--r--test/lisp/progmodes/xref-resources/file2.txt (renamed from test/data/xref/file2.txt)0
-rw-r--r--test/lisp/progmodes/xref-tests.el84
-rw-r--r--test/lisp/replace-tests.el44
-rw-r--r--test/lisp/saveplace-resources/saveplace4
-rw-r--r--test/lisp/saveplace-tests.el99
-rw-r--r--test/lisp/shadowfile-tests.el31
-rw-r--r--test/lisp/simple-tests.el59
-rw-r--r--test/lisp/so-long-tests/so-long-tests.el2
-rw-r--r--test/lisp/sort-tests.el8
-rw-r--r--test/lisp/subr-tests.el281
-rw-r--r--test/lisp/tar-mode-tests.el3
-rw-r--r--test/lisp/tempo-tests.el39
-rw-r--r--test/lisp/textmodes/bibtex-tests.el57
-rw-r--r--test/lisp/textmodes/conf-mode-tests.el8
-rw-r--r--test/lisp/textmodes/css-mode-resources/test-indent.css (renamed from test/manual/indent/css-mode.css)4
-rw-r--r--test/lisp/textmodes/css-mode-tests.el16
-rw-r--r--test/lisp/textmodes/mhtml-mode-tests.el2
-rw-r--r--test/lisp/textmodes/paragraphs-tests.el4
-rw-r--r--test/lisp/textmodes/po-tests.el68
-rw-r--r--test/lisp/textmodes/reftex-tests.el35
-rw-r--r--test/lisp/textmodes/sgml-mode-tests.el2
-rw-r--r--test/lisp/thingatpt-tests.el2
-rw-r--r--test/lisp/time-resources/non-empty1
-rw-r--r--test/lisp/time-stamp-tests.el110
-rw-r--r--test/lisp/time-tests.el79
-rw-r--r--test/lisp/url/url-auth-tests.el2
-rw-r--r--test/lisp/url/url-domsuf-tests.el51
-rw-r--r--test/lisp/url/url-expand-tests.el9
-rw-r--r--test/lisp/url/url-file-tests.el11
-rw-r--r--test/lisp/url/url-future-tests.el24
-rw-r--r--test/lisp/url/url-handlers-test.el8
-rw-r--r--test/lisp/url/url-parse-tests.el2
-rw-r--r--test/lisp/url/url-tramp-tests.el2
-rw-r--r--test/lisp/url/url-util-tests.el2
-rw-r--r--test/lisp/vc/add-log-tests.el12
-rw-r--r--test/lisp/vc/diff-mode-resources/hello_emacs.c (renamed from test/data/vc/diff-mode/hello_emacs.c)0
-rw-r--r--test/lisp/vc/diff-mode-resources/hello_emacs_1.c (renamed from test/data/vc/diff-mode/hello_emacs_1.c)0
-rw-r--r--test/lisp/vc/diff-mode-resources/hello_world.c (renamed from test/data/vc/diff-mode/hello_world.c)0
-rw-r--r--test/lisp/vc/diff-mode-resources/hello_world_1.c (renamed from test/data/vc/diff-mode/hello_world_1.c)0
-rw-r--r--test/lisp/vc/diff-mode-tests.el20
-rw-r--r--test/lisp/vc/ediff-ptch-tests.el10
-rw-r--r--test/lisp/vc/smerge-mode-tests.el2
-rw-r--r--test/lisp/vc/vc-bzr-tests.el9
-rw-r--r--test/lisp/vc/vc-hg-tests.el2
-rw-r--r--test/lisp/vc/vc-tests.el25
-rw-r--r--test/lisp/version-tests.el31
-rw-r--r--test/lisp/wdired-tests.el24
-rw-r--r--test/lisp/wid-edit-tests.el188
-rw-r--r--test/lisp/xdg-resources/l10n.desktop (renamed from test/data/xdg/l10n.desktop)0
-rw-r--r--test/lisp/xdg-resources/malformed.desktop (renamed from test/data/xdg/malformed.desktop)0
-rw-r--r--test/lisp/xdg-resources/mimeapps.list (renamed from test/data/xdg/mimeapps.list)0
-rw-r--r--test/lisp/xdg-resources/mimeinfo.cache (renamed from test/data/xdg/mimeinfo.cache)0
-rw-r--r--test/lisp/xdg-resources/test.desktop (renamed from test/data/xdg/test.desktop)0
-rw-r--r--test/lisp/xdg-resources/wrong.desktop (renamed from test/data/xdg/wrong.desktop)0
-rw-r--r--test/lisp/xdg-tests.el20
-rw-r--r--test/lisp/xml-tests.el33
-rw-r--r--test/lisp/xt-mouse-tests.el8
-rw-r--r--test/manual/biditest.el6
-rw-r--r--test/manual/cedet/cedet-utests.el12
-rw-r--r--test/manual/cedet/semantic-tests.el4
-rw-r--r--test/manual/cedet/tests/testnsp.cpp2
-rw-r--r--test/manual/etags/CTAGS.good2
-rw-r--r--test/manual/etags/c-src/abbrev.c14
-rw-r--r--test/manual/etags/c-src/emacs/src/keyboard.c2
-rw-r--r--test/manual/etags/cp-src/functions.cpp2
-rw-r--r--test/manual/etags/prol-src/ordsets.prolog4
-rw-r--r--test/manual/etags/tex-src/texinfo.tex4
-rw-r--r--test/manual/etags/y-src/parse.c2
-rw-r--r--test/manual/etags/y-src/parse.y2
-rw-r--r--test/manual/image-circular-tests.el144
-rw-r--r--test/manual/image-size-tests.el6
-rw-r--r--test/manual/image-transforms-tests.el52
-rw-r--r--test/manual/indent/less-css-mode.less10
-rw-r--r--test/manual/indent/nxml.xml10
-rw-r--r--test/manual/indent/opascal.pas12
-rwxr-xr-xtest/manual/indent/perl.perl14
-rw-r--r--test/manual/indent/ps-mode.ps14
-rw-r--r--test/manual/indent/scheme.scm9
-rw-r--r--test/manual/indent/scss-mode.scss4
-rw-r--r--test/manual/indent/tcl.tcl26
-rw-r--r--test/manual/scroll-tests.el6
-rw-r--r--test/src/alloc-tests.el7
-rw-r--r--test/src/buffer-tests.el53
-rw-r--r--test/src/callint-tests.el3
-rw-r--r--test/src/callproc-tests.el17
-rw-r--r--test/src/casefiddle-tests.el3
-rw-r--r--test/src/charset-tests.el10
-rw-r--r--test/src/chartab-tests.el30
-rw-r--r--test/src/cmds-tests.el10
-rw-r--r--test/src/coding-tests.el64
-rw-r--r--test/src/data-tests.el52
-rw-r--r--test/src/decompress-tests.el2
-rw-r--r--test/src/doc-tests.el96
-rw-r--r--test/src/editfns-tests.el12
-rw-r--r--test/src/emacs-module-resources/mod-test.c (renamed from test/data/emacs-module/mod-test.c)232
-rw-r--r--test/src/emacs-module-tests.el205
-rw-r--r--test/src/eval-tests.el50
-rw-r--r--test/src/fileio-tests.el11
-rw-r--r--test/src/floatfns-tests.el2
-rw-r--r--test/src/fns-tests.el209
-rw-r--r--test/src/font-tests.el2
-rw-r--r--test/src/indent-tests.el59
-rw-r--r--test/src/keyboard-tests.el15
-rw-r--r--test/src/keymap-tests.el207
-rw-r--r--test/src/lread-resources/somelib.el (renamed from test/data/somelib.el)0
-rw-r--r--test/src/lread-resources/somelib2.el (renamed from test/data/somelib2.el)0
-rw-r--r--test/src/lread-tests.el30
-rw-r--r--test/src/print-tests.el57
-rw-r--r--test/src/process-tests.el462
-rw-r--r--test/src/regex-emacs-tests.el70
-rw-r--r--test/src/regex-resources/BOOST.tests4
-rw-r--r--test/src/syntax-resources/syntax-comments.txt94
-rw-r--r--test/src/syntax-tests.el407
-rw-r--r--test/src/textprop-tests.el2
-rw-r--r--test/src/thread-tests.el2
-rw-r--r--test/src/timefns-tests.el59
-rw-r--r--test/src/undo-tests.el12
-rw-r--r--test/src/xdisp-tests.el75
-rw-r--r--test/src/xfaces-tests.el50
-rw-r--r--test/src/xml-tests.el23
599 files changed, 19741 insertions, 3639 deletions
diff --git a/test/ChangeLog.1 b/test/ChangeLog.1
index 9fd81ea75fd..7085b9ea10c 100644
--- a/test/ChangeLog.1
+++ b/test/ChangeLog.1
@@ -1754,7 +1754,7 @@
* indent/prolog.prolog: Test alignment of ->; with operator at bol.
- * indent/css-mode.css (.x2): Test alignement inside braces.
+ * indent/css-mode.css (.x2): Test alignment inside braces.
2013-10-26 Dmitry Gutov <dgutov@yandex.ru>
diff --git a/test/Makefile.in b/test/Makefile.in
index b9e8288591d..8aa37ca7854 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -89,11 +89,6 @@ unexport EMACSDATA EMACSDOC EMACSPATH GREP_OPTIONS
## To run tests under a debugger, set this to eg: "gdb --args".
GDB =
-# The locale to run tests under. Tests should work if this is set to
-# any supported locale. Use the C locale by default, as it should be
-# supported everywhere.
-TEST_LOCALE = C
-
# Set this to 'yes' to run the tests in an interactive instance.
TEST_INTERACTIVE ?= no
@@ -128,7 +123,7 @@ endif
# The actual Emacs command run in the targets below.
# Prevent any setting of EMACSLOADPATH in user environment causing problems.
-emacs = EMACSLOADPATH= LC_ALL=$(TEST_LOCALE) \
+emacs = EMACSLOADPATH= \
EMACS_TEST_DIRECTORY=$(abspath $(srcdir)) \
$(GDB) "$(EMACS)" $(MODULES_EMACSOPT) $(EMACSOPT)
@@ -137,7 +132,7 @@ emacs = EMACSLOADPATH= LC_ALL=$(TEST_LOCALE) \
# exists, or writing to ~/.bzr.log when running bzr commands).
TEST_HOME = /nonexistent
-test_module_dir := data/emacs-module
+test_module_dir := src/emacs-module-resources
.PHONY: all check
@@ -255,8 +250,8 @@ else
FPIC_CFLAGS = -fPIC
endif
-GMP_LIB = @GMP_LIB@
-GMP_OBJ = $(if @GMP_OBJ@, ../src/@GMP_OBJ@)
+GMP_H = @GMP_H@
+LIBGMP = @LIBGMP@
MODULE_CFLAGS = -I../src -I$(srcdir)/../src -I../lib -I$(srcdir)/../lib \
$(FPIC_CFLAGS) $(PROFILING_CFLAGS) \
@@ -271,7 +266,9 @@ src/emacs-module-tests.log src/emacs-module-tests.elc: $(test_module)
$(test_module): $(test_module:${SO}=.c) ../src/emacs-module.h
$(AM_V_at)${MKDIR_P} $(dir $@)
$(AM_V_CCLD)$(CC) -shared $(CPPFLAGS) $(MODULE_CFLAGS) $(LDFLAGS) \
- -o $@ $< $(GMP_LIB) $(GMP_OBJ:.o=.c) \
+ -o $@ $< $(LIBGMP) \
+ $(and $(GMP_H),$(srcdir)/../lib/mini-gmp-gnulib.c) \
+ $(if $(OMIT_GNULIB_MODULE_free-posix),,$(srcdir)/../lib/free.c) \
$(srcdir)/../lib/timespec.c $(srcdir)/../lib/gettime.c
endif
diff --git a/test/README b/test/README
index eee23402508..ec566cb58dc 100644
--- a/test/README
+++ b/test/README
@@ -64,6 +64,11 @@ protect against "make" variable expansion):
make <filename> SELECTOR='"foo$$"'
+In case you want to use the symbol name of a test as selector, you can
+use it directly:
+
+ make <filename> SELECTOR='test-foo-remote'
+
Note that although the test files are always compiled (unless they set
no-byte-compile), the source files will be run when expensive or
unstable tests are involved, to give nicer backtraces. To run the
@@ -76,6 +81,11 @@ Some tests might take long time to run. In order to summarize the
make SUMMARIZE_TESTS=<nn> ...
+The backtrace of failing tests are truncated to the default value of
+'ert-batch-backtrace-right-margin'. To see more of the backtrace, use
+
+ make TEST_BACKTRACE_LINE_LENGTH=<nn> ...
+
The tests are run in batch mode by default; sometimes it's useful to
get precisely the same environment but run in interactive mode for
debugging. To do that, use
@@ -103,7 +113,8 @@ $EMACS_HYDRA_CI indicates the hydra environment, and $EMACS_EMBA_CI
indicates the emba environment, respectively.
-(Also, see etc/compilation.txt for compilation mode font lock tests.)
+(Also, see etc/compilation.txt for compilation mode font lock tests
+and etc/grep.txt for grep mode font lock tests.)
This file is part of GNU Emacs.
diff --git a/test/lib-src/emacsclient-tests.el b/test/lib-src/emacsclient-tests.el
index f783482b550..8bad9c04e00 100644
--- a/test/lib-src/emacsclient-tests.el
+++ b/test/lib-src/emacsclient-tests.el
@@ -1,4 +1,4 @@
-;;; emacsclient-tests.el --- Test emacsclient
+;;; emacsclient-tests.el --- Test emacsclient -*- lexical-binding:t -*-
;; Copyright (C) 2016-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/abbrev-tests.el b/test/lisp/abbrev-tests.el
index a942e041dfe..2a42d5636d3 100644
--- a/test/lisp/abbrev-tests.el
+++ b/test/lisp/abbrev-tests.el
@@ -69,8 +69,9 @@
(define-abbrev ert-test-abbrevs "sys" "system abbrev" nil :system t)
(should (equal (mapcar #'symbol-name (abbrev--table-symbols 'ert-test-abbrevs))
'("a-e-t")))
- (should (equal (mapcar #'symbol-name (abbrev--table-symbols 'ert-test-abbrevs t))
- '("a-e-t" "sys")))))
+ (let ((syms (abbrev--table-symbols 'ert-test-abbrevs t)))
+ (should (equal (sort (mapcar #'symbol-name syms) #'string<)
+ '("a-e-t" "sys"))))))
(ert-deftest abbrev-table-get-put-test ()
(let ((table (make-abbrev-table)))
diff --git a/test/lisp/align-resources/align-post.c b/test/lisp/align-resources/align-post.c
new file mode 100644
index 00000000000..157e1d6242a
--- /dev/null
+++ b/test/lisp/align-resources/align-post.c
@@ -0,0 +1,3 @@
+int
+main (int argc,
+ char *argv[]);
diff --git a/test/lisp/align-resources/align-post.java b/test/lisp/align-resources/align-post.java
new file mode 100644
index 00000000000..e0ea8e727f1
--- /dev/null
+++ b/test/lisp/align-resources/align-post.java
@@ -0,0 +1,9 @@
+class X
+{
+ String field1;
+ String[] field2;
+ int field3;
+ int[] field4;
+ X field5;
+ X[] field6;
+}
diff --git a/test/lisp/align-resources/align-pre.c b/test/lisp/align-resources/align-pre.c
new file mode 100644
index 00000000000..b1774181a40
--- /dev/null
+++ b/test/lisp/align-resources/align-pre.c
@@ -0,0 +1,3 @@
+int
+main (int argc,
+ char *argv[]);
diff --git a/test/lisp/align-resources/align-pre.java b/test/lisp/align-resources/align-pre.java
new file mode 100644
index 00000000000..fe7a87a9393
--- /dev/null
+++ b/test/lisp/align-resources/align-pre.java
@@ -0,0 +1,9 @@
+class X
+{
+ String field1;
+ String[] field2;
+ int field3;
+ int[] field4;
+ X field5;
+ X[] field6;
+}
diff --git a/test/lisp/align-tests.el b/test/lisp/align-tests.el
new file mode 100644
index 00000000000..a9c36e30e19
--- /dev/null
+++ b/test/lisp/align-tests.el
@@ -0,0 +1,47 @@
+;;; align-tests.el --- Test suite for aligns -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2015-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+(require 'ert-x)
+(require 'align)
+
+(defun test-align-compare (file function)
+ (should (equal
+ (with-temp-buffer
+ (insert-file-contents (ert-resource-file (format file "pre")))
+ (funcall function)
+ (align (point-min) (point-max))
+ (buffer-substring-no-properties (point-min) (point-max)))
+ (with-temp-buffer
+ (insert-file-contents (ert-resource-file (format file "post")))
+ (buffer-string)))))
+
+(ert-deftest align-java ()
+ (test-align-compare "align-%s.java" #'java-mode))
+
+(ert-deftest align-c ()
+ (test-align-compare "align-%s.c" #'c-mode))
+
+(provide 'align-tests)
+
+;;; align-tests.el ends here
diff --git a/test/lisp/allout-tests.el b/test/lisp/allout-tests.el
new file mode 100644
index 00000000000..3a346fd1e2d
--- /dev/null
+++ b/test/lisp/allout-tests.el
@@ -0,0 +1,148 @@
+;;; allout-tests.el --- Tests for allout.el -*- lexical-binding: t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+(require 'allout)
+
+(require 'cl-lib)
+
+(defun allout-tests-obliterate-variable (name)
+ "Completely unbind variable with NAME."
+ (if (local-variable-p name (current-buffer)) (kill-local-variable name))
+ (while (boundp name) (makunbound name)))
+
+(defvar allout-tests-globally-unbound nil
+ "Fodder for allout resumptions tests -- defvar just for byte compiler.")
+(defvar allout-tests-globally-true nil
+ "Fodder for allout resumptions tests -- defvar just for byte compiler.")
+(defvar allout-tests-locally-true nil
+ "Fodder for allout resumptions tests -- defvar just for byte compiler.")
+
+;; For each resumption case, we also test that the right local/global
+;; scopes are affected during resumption effects.
+
+(ert-deftest allout-test-resumption-unbound-return-to-unbound ()
+ "Previously unbound variables return to the unbound state."
+ (with-temp-buffer
+ (allout-tests-obliterate-variable 'allout-tests-globally-unbound)
+ (allout-add-resumptions '(allout-tests-globally-unbound t))
+ (should (not (default-boundp 'allout-tests-globally-unbound)))
+ (should (local-variable-p 'allout-tests-globally-unbound (current-buffer)))
+ (should (boundp 'allout-tests-globally-unbound))
+ (should (equal allout-tests-globally-unbound t))
+ (allout-do-resumptions)
+ (should (not (local-variable-p 'allout-tests-globally-unbound
+ (current-buffer))))
+ (should (not (boundp 'allout-tests-globally-unbound)))))
+
+(ert-deftest allout-test-resumption-variable-resumed ()
+ "Ensure that variable with prior global value is resumed."
+ (with-temp-buffer
+ (allout-tests-obliterate-variable 'allout-tests-globally-true)
+ (setq allout-tests-globally-true t)
+ (allout-add-resumptions '(allout-tests-globally-true nil))
+ (should (equal (default-value 'allout-tests-globally-true) t))
+ (should (local-variable-p 'allout-tests-globally-true (current-buffer)))
+ (should (equal allout-tests-globally-true nil))
+ (allout-do-resumptions)
+ (should (not (local-variable-p 'allout-tests-globally-true
+ (current-buffer))))
+ (should (boundp 'allout-tests-globally-true))
+ (should (equal allout-tests-globally-true t))))
+
+(ert-deftest allout-test-resumption-prior-value-resumed ()
+ "Ensure that prior local value is resumed."
+ (with-temp-buffer
+ (allout-tests-obliterate-variable 'allout-tests-locally-true)
+ (setq-local allout-tests-locally-true t)
+ (cl-assert (not (default-boundp 'allout-tests-locally-true))
+ nil (concat "Test setup mistake -- variable supposed to"
+ " not have global binding, but it does."))
+ (cl-assert (local-variable-p 'allout-tests-locally-true (current-buffer))
+ nil (concat "Test setup mistake -- variable supposed to have"
+ " local binding, but it lacks one."))
+ (allout-add-resumptions '(allout-tests-locally-true nil))
+ (should (not (default-boundp 'allout-tests-locally-true)))
+ (should (local-variable-p 'allout-tests-locally-true (current-buffer)))
+ (should (equal allout-tests-locally-true nil))
+ (allout-do-resumptions)
+ (should (boundp 'allout-tests-locally-true))
+ (should (local-variable-p 'allout-tests-locally-true (current-buffer)))
+ (should (equal allout-tests-locally-true t))
+ (should (not (default-boundp 'allout-tests-locally-true)))))
+
+(ert-deftest allout-test-resumption-multiple-holds ()
+ "Ensure that last of multiple resumptions holds, for various scopes."
+ (with-temp-buffer
+ (allout-tests-obliterate-variable 'allout-tests-globally-unbound)
+ (allout-tests-obliterate-variable 'allout-tests-globally-true)
+ (setq allout-tests-globally-true t)
+ (allout-tests-obliterate-variable 'allout-tests-locally-true)
+ (setq-local allout-tests-locally-true t)
+ (allout-add-resumptions '(allout-tests-globally-unbound t)
+ '(allout-tests-globally-true nil)
+ '(allout-tests-locally-true nil))
+ (allout-add-resumptions '(allout-tests-globally-unbound 2)
+ '(allout-tests-globally-true 3)
+ '(allout-tests-locally-true 4))
+ ;; reestablish many of the basic conditions are maintained after re-add:
+ (should (not (default-boundp 'allout-tests-globally-unbound)))
+ (should (local-variable-p 'allout-tests-globally-unbound (current-buffer)))
+ (should (equal allout-tests-globally-unbound 2))
+ (should (default-boundp 'allout-tests-globally-true))
+ (should (local-variable-p 'allout-tests-globally-true (current-buffer)))
+ (should (equal allout-tests-globally-true 3))
+ (should (not (default-boundp 'allout-tests-locally-true)))
+ (should (local-variable-p 'allout-tests-locally-true (current-buffer)))
+ (should (equal allout-tests-locally-true 4))
+ (allout-do-resumptions)
+ (should (not (local-variable-p 'allout-tests-globally-unbound
+ (current-buffer))))
+ (should (not (boundp 'allout-tests-globally-unbound)))
+ (should (not (local-variable-p 'allout-tests-globally-true
+ (current-buffer))))
+ (should (boundp 'allout-tests-globally-true))
+ (should (equal allout-tests-globally-true t))
+ (should (boundp 'allout-tests-locally-true))
+ (should (local-variable-p 'allout-tests-locally-true (current-buffer)))
+ (should (equal allout-tests-locally-true t))
+ (should (not (default-boundp 'allout-tests-locally-true)))))
+
+(ert-deftest allout-test-resumption-unbinding ()
+ "Ensure that deliberately unbinding registered variables doesn't foul things."
+ (with-temp-buffer
+ (allout-tests-obliterate-variable 'allout-tests-globally-unbound)
+ (allout-tests-obliterate-variable 'allout-tests-globally-true)
+ (setq allout-tests-globally-true t)
+ (allout-tests-obliterate-variable 'allout-tests-locally-true)
+ (setq-local allout-tests-locally-true t)
+ (allout-add-resumptions '(allout-tests-globally-unbound t)
+ '(allout-tests-globally-true nil)
+ '(allout-tests-locally-true nil))
+ (allout-tests-obliterate-variable 'allout-tests-globally-unbound)
+ (allout-tests-obliterate-variable 'allout-tests-globally-true)
+ (allout-tests-obliterate-variable 'allout-tests-locally-true)
+ (allout-do-resumptions)))
+
+(provide 'allout-tests)
+;;; allout-tests.el ends here
diff --git a/test/lisp/allout-widgets-tests.el b/test/lisp/allout-widgets-tests.el
new file mode 100644
index 00000000000..59ff6783697
--- /dev/null
+++ b/test/lisp/allout-widgets-tests.el
@@ -0,0 +1,87 @@
+;;; allout-widgets-tests.el --- Tests for allout-widgets.el -*- lexical-binding: t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+(require 'allout-widgets)
+
+(require 'cl-lib)
+
+(ert-deftest allout-test-range-overlaps ()
+ "`allout-range-overlaps' unit tests."
+ (let* (ranges
+ got
+ (try (lambda (from to)
+ (setq got (allout-range-overlaps from to ranges))
+ (setq ranges (cadr got))
+ got)))
+;; ;; biggie:
+;; (setq ranges nil)
+;; ;; ~ .02 to .1 seconds for just repeated listing args instead of funcall
+;; ;; ~ 13 seconds for doing repeated funcall
+;; (message "time-trial: %s, resulting size %s"
+;; (time-trial
+;; '(let ((size 10000)
+;; doing)
+;; (dotimes (count size)
+;; (setq doing (random size))
+;; (funcall try doing (+ doing (random 5)))
+;; ;;(list doing (+ doing (random 5)))
+;; )))
+;; (length ranges))
+;; (sit-for 2)
+
+ ;; fresh:
+ (setq ranges nil)
+ (should (equal (funcall try 3 5) '(nil ((3 5)))))
+ ;; add range at end:
+ (should (equal (funcall try 10 12) '(nil ((3 5) (10 12)))))
+ ;; add range at beginning:
+ (should (equal (funcall try 1 2) '(nil ((1 2) (3 5) (10 12)))))
+ ;; insert range somewhere in the middle:
+ (should (equal (funcall try 7 9) '(nil ((1 2) (3 5) (7 9) (10 12)))))
+ ;; consolidate some:
+ (should (equal (funcall try 5 8) '(t ((1 2) (3 9) (10 12)))))
+ ;; add more:
+ (should (equal (funcall try 15 17) '(nil ((1 2) (3 9) (10 12) (15 17)))))
+ ;; add more:
+ (should (equal (funcall try 20 22)
+ '(nil ((1 2) (3 9) (10 12) (15 17) (20 22)))))
+ ;; encompass more:
+ (should (equal (funcall try 4 11) '(t ((1 2) (3 12) (15 17) (20 22)))))
+ ;; encompass all:
+ (should (equal (funcall try 2 25) '(t ((1 25)))))
+
+ ;; fresh slate:
+ (setq ranges nil)
+ (should (equal (funcall try 20 25) '(nil ((20 25)))))
+ (should (equal (funcall try 30 35) '(nil ((20 25) (30 35)))))
+ (should (equal (funcall try 26 28) '(nil ((20 25) (26 28) (30 35)))))
+ (should (equal (funcall try 15 20) '(t ((15 25) (26 28) (30 35)))))
+ (should (equal (funcall try 10 30) '(t ((10 35)))))
+ (should (equal (funcall try 5 6) '(nil ((5 6) (10 35)))))
+ (should (equal (funcall try 2 100) '(t ((2 100)))))
+
+ (setq ranges nil)))
+
+(provide 'allout-widgets-tests)
+;;; allout-widgets-tests.el ends here
diff --git a/test/lisp/ansi-color-tests.el b/test/lisp/ansi-color-tests.el
new file mode 100644
index 00000000000..107dc8e400b
--- /dev/null
+++ b/test/lisp/ansi-color-tests.el
@@ -0,0 +1,49 @@
+;;; ansi-color-tests.el --- Test suite for ansi-color -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+;; Author: Pablo Barbáchano <pablob@amazon.com>
+;; Keywords: ansi
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ansi-color)
+
+(defvar test-strings '(("\e[33mHello World\e[0m" . "Hello World")
+ ("\e[1m\e[3m\e[5mbold italics blink\e[0m" . "bold italics blink")))
+
+(ert-deftest ansi-color-apply-on-region-test ()
+ (dolist (pair test-strings)
+ (with-temp-buffer
+ (insert (car pair))
+ (ansi-color-apply-on-region (point-min) (point-max))
+ (should (equal (buffer-string) (cdr pair)))
+ (should (not (equal (overlays-at (point-min)) nil))))))
+
+(ert-deftest ansi-color-apply-on-region-preserving-test ()
+ (dolist (pair test-strings)
+ (with-temp-buffer
+ (insert (car pair))
+ (ansi-color-apply-on-region (point-min) (point-max) t)
+ (should (equal (buffer-string) (car pair))))))
+
+(provide 'ansi-color-tests)
+
+;;; ansi-color-tests.el ends here
diff --git a/test/lisp/apropos-tests.el b/test/lisp/apropos-tests.el
new file mode 100644
index 00000000000..7eaa64207f1
--- /dev/null
+++ b/test/lisp/apropos-tests.el
@@ -0,0 +1,133 @@
+;;; apropos-tests.el --- Tests for apropos.el -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+;; Author: Simen Heggestøyl <simenheg@gmail.com>
+;; Keywords:
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'apropos)
+(require 'ert)
+
+(ert-deftest apropos-tests-words-to-regexp-1 ()
+ (let ((re (apropos-words-to-regexp '("foo" "bar") "baz")))
+ (should (string-match-p re "foobazbar"))
+ (should (string-match-p re "barbazfoo"))
+ (should-not (string-match-p re "foo-bar"))
+ (should-not (string-match-p re "foobazbazbar"))))
+
+(ert-deftest apropos-tests-words-to-regexp-2 ()
+ (let ((re (apropos-words-to-regexp '("foo" "bar" "baz") "-")))
+ (should-not (string-match-p re "foo"))
+ (should-not (string-match-p re "foobar"))
+ (should (string-match-p re "foo-bar"))
+ (should (string-match-p re "foo-baz"))))
+
+(ert-deftest apropos-tests-parse-pattern-1 ()
+ (apropos-parse-pattern '("foo"))
+ (should (string-match-p apropos-regexp "foo"))
+ (should (string-match-p apropos-regexp "foo-bar"))
+ (should (string-match-p apropos-regexp "bar-foo"))
+ (should (string-match-p apropos-regexp "foo-foo"))
+ (should-not (string-match-p apropos-regexp "bar")))
+
+(ert-deftest apropos-tests-parse-pattern-2 ()
+ (apropos-parse-pattern '("foo" "bar"))
+ (should (string-match-p apropos-regexp "foo-bar"))
+ (should (string-match-p apropos-regexp "bar-foo"))
+ (should-not (string-match-p apropos-regexp "foo"))
+ (should-not (string-match-p apropos-regexp "bar"))
+ (should-not (string-match-p apropos-regexp "baz"))
+ (should-not (string-match-p apropos-regexp "foo-foo"))
+ (should-not (string-match-p apropos-regexp "bar-bar")))
+
+(ert-deftest apropos-tests-parse-pattern-3 ()
+ (apropos-parse-pattern '("foo" "bar" "baz"))
+ (should (string-match-p apropos-regexp "foo-bar"))
+ (should (string-match-p apropos-regexp "foo-baz"))
+ (should (string-match-p apropos-regexp "bar-foo"))
+ (should (string-match-p apropos-regexp "bar-baz"))
+ (should (string-match-p apropos-regexp "baz-foo"))
+ (should (string-match-p apropos-regexp "baz-bar"))
+ (should-not (string-match-p apropos-regexp "foo"))
+ (should-not (string-match-p apropos-regexp "bar"))
+ (should-not (string-match-p apropos-regexp "baz"))
+ (should-not (string-match-p apropos-regexp "foo-foo"))
+ (should-not (string-match-p apropos-regexp "bar-bar"))
+ (should-not (string-match-p apropos-regexp "baz-baz")))
+
+(ert-deftest apropos-tests-parse-pattern-single-regexp ()
+ (apropos-parse-pattern "foo+bar")
+ (should-not (string-match-p apropos-regexp "fobar"))
+ (should (string-match-p apropos-regexp "foobar"))
+ (should (string-match-p apropos-regexp "fooobar")))
+
+(ert-deftest apropos-tests-parse-pattern-synonyms ()
+ (let ((apropos-synonyms '(("find" "open" "edit"))))
+ (apropos-parse-pattern '("open"))
+ (should (string-match-p apropos-regexp "find-file"))
+ (should (string-match-p apropos-regexp "open-file"))
+ (should (string-match-p apropos-regexp "edit-file"))))
+
+(ert-deftest apropos-tests-calc-scores ()
+ (let ((str "Return apropos score for string STR."))
+ (should (equal (apropos-calc-scores str '("apr")) '(7)))
+ (should (equal (apropos-calc-scores str '("apr" "str")) '(25 7)))
+ (should (equal (apropos-calc-scores str '("appr" "str")) '(25)))
+ (should-not (apropos-calc-scores str '("appr" "strr")))))
+
+(ert-deftest apropos-tests-score-str ()
+ (apropos-parse-pattern '("foo" "bar"))
+ (should (< (apropos-score-str "baz")
+ (apropos-score-str "foo baz")
+ (apropos-score-str "foo bar baz"))))
+
+(ert-deftest apropos-tests-score-doc ()
+ (apropos-parse-pattern '("foo" "bar"))
+ (should (< (apropos-score-doc "baz")
+ (apropos-score-doc "foo baz")
+ (apropos-score-doc "foo bar baz"))))
+
+(ert-deftest apropos-tests-score-symbol ()
+ (apropos-parse-pattern '("foo" "bar"))
+ (should (< (apropos-score-symbol 'baz)
+ (apropos-score-symbol 'foo-baz)
+ (apropos-score-symbol 'foo-bar-baz))))
+
+(ert-deftest apropos-tests-true-hit ()
+ (should-not (apropos-true-hit "foo" '("foo" "bar")))
+ (should (apropos-true-hit "foo bar" '("foo" "bar")))
+ (should (apropos-true-hit "foo bar baz" '("foo" "bar"))))
+
+(ert-deftest apropos-tests-format-plist ()
+ (setplist 'foo '(a 1 b (2 3) c nil))
+ (apropos-parse-pattern '("b"))
+ (should (equal (apropos-format-plist 'foo ", ")
+ "a 1, b (2 3), c nil"))
+ (should (equal (apropos-format-plist 'foo ", " t)
+ "b (2 3)"))
+ (apropos-parse-pattern '("d"))
+ (should-not (apropos-format-plist 'foo ", " t)))
+
+(provide 'apropos-tests)
+;;; apropos-tests.el ends here
diff --git a/test/lisp/arc-mode-tests.el b/test/lisp/arc-mode-tests.el
index 96fcffc7c97..5c6af9b45cf 100644
--- a/test/lisp/arc-mode-tests.el
+++ b/test/lisp/arc-mode-tests.el
@@ -28,11 +28,11 @@
(let ((alist (list (cons 448 "-rwx------")
(cons 420 "-rw-r--r--")
(cons 292 "-r--r--r--")
- (cons 512 "----------")
+ (cons 512 "---------T")
(cons 1024 "------S---") ; Bug#28092
(cons 2048 "---S------"))))
(dolist (x alist)
- (should (equal (cdr x) (archive-int-to-mode (car x)))))))
+ (should (equal (cdr x) (file-modes-number-to-symbolic (car x)))))))
(ert-deftest arc-mode-test-zip-extract-gz ()
(skip-unless (and archive-zip-extract (executable-find (car archive-zip-extract))))
diff --git a/test/lisp/auth-source-pass-tests.el b/test/lisp/auth-source-pass-tests.el
index f1c6881b3b7..bfbef53db97 100644
--- a/test/lisp/auth-source-pass-tests.el
+++ b/test/lisp/auth-source-pass-tests.el
@@ -353,6 +353,10 @@ HOSTNAME, USER and PORT are passed unchanged to
(auth-source-pass--with-store '(("bar.com:8080"))
(should (auth-source-pass-match-entry-p "bar.com:8080" "bar.com" nil "8080"))))
+(ert-deftest auth-source-pass--matching-entries-find-entries-with-a-port-when-passed-multiple-ports ()
+ (auth-source-pass--with-store '(("bar.com:8080"))
+ (should (auth-source-pass-match-entry-p "bar.com:8080" "bar.com" nil '("http" "https" "80" "8080")))))
+
(ert-deftest auth-source-pass--matching-entries-find-entries-with-slash ()
;; match if entry filename matches user
(auth-source-pass--with-store '(("foo.com/user"))
diff --git a/test/lisp/autoinsert-tests.el b/test/lisp/autoinsert-tests.el
index 86f9c0734a0..7ec4bf63791 100644
--- a/test/lisp/autoinsert-tests.el
+++ b/test/lisp/autoinsert-tests.el
@@ -79,10 +79,10 @@
(ert-deftest autoinsert-tests-define-auto-insert-before ()
(let ((auto-insert-alist
- (list (cons 'text-mode '(lambda () (insert "foo")))))
+ (list (cons 'text-mode (lambda () (insert "foo")))))
(auto-insert-query nil))
(define-auto-insert 'text-mode
- '(lambda () (insert "bar")))
+ (lambda () (insert "bar")))
(with-temp-buffer
(text-mode)
(auto-insert)
@@ -90,10 +90,10 @@
(ert-deftest autoinsert-tests-define-auto-insert-after ()
(let ((auto-insert-alist
- (list (cons 'text-mode '(lambda () (insert "foo")))))
+ (list (cons 'text-mode (lambda () (insert "foo")))))
(auto-insert-query nil))
(define-auto-insert 'text-mode
- '(lambda () (insert "bar"))
+ (lambda () (insert "bar"))
t)
(with-temp-buffer
(text-mode)
diff --git a/test/lisp/autorevert-tests.el b/test/lisp/autorevert-tests.el
index 6ced9a1ac8f..6da515bb2c8 100644
--- a/test/lisp/autorevert-tests.el
+++ b/test/lisp/autorevert-tests.el
@@ -4,18 +4,20 @@
;; Author: Michael Albinus <michael.albinus@gmx.de>
-;; This program is free software: you can redistribute it and/or
+;; 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.
;;
-;; This program is distributed in the hope that it will be useful, but
+;; 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 `https://www.gnu.org/licenses/'.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
@@ -59,11 +61,11 @@
auto-revert-notify-exclude-dir-regexp "nothing-to-be-excluded"
auto-revert-stop-on-user-input nil
file-notify-debug nil
- tramp-verbose 0
- tramp-message-show-message nil)
+ tramp-verbose 0)
-(defconst auto-revert--timeout (1+ auto-revert-interval)
- "Time to wait for a message.")
+(defun auto-revert--timeout ()
+ "Time to wait for a message."
+ (+ auto-revert-interval 0.1))
(defvar auto-revert--messages nil
"Used to collect messages issued during a section of a test.")
@@ -126,14 +128,14 @@ This expects `auto-revert--messages' to be bound by
;; Remote files do not cooperate well with timers. So we count ourselves.
(let ((ct (current-time)))
(while (and (< (float-time (time-subtract (current-time) ct))
- auto-revert--timeout)
+ (auto-revert--timeout))
(null (string-match
(format-message
"Reverting buffer `%s'\\." (buffer-name buffer))
- auto-revert--messages)))
+ (or auto-revert--messages ""))))
(if (with-current-buffer buffer auto-revert-use-notify)
- (read-event nil nil 0.1)
- (sleep-for 0.1)))))
+ (read-event nil nil 0.05)
+ (sleep-for 0.05)))))
(defmacro auto-revert--deftest-remote (test docstring)
"Define ert `TEST-remote' for remote files."
@@ -153,50 +155,59 @@ This expects `auto-revert--messages' to be bound by
(funcall (ert-test-body ert-test))
(error (message "%s" err) (signal (car err) (cdr err)))))))
+(defmacro with-auto-revert-test (&rest body)
+ `(let ((auto-revert-interval-orig auto-revert-interval))
+ (unwind-protect
+ (progn
+ (customize-set-variable 'auto-revert-interval 0.1)
+ ,@body)
+ (customize-set-variable 'auto-revert-interval auto-revert-interval-orig))))
+
+(defun auto-revert-tests--write-file (text file time-delta &optional append)
+ (write-region text nil file append 'no-message)
+ (set-file-times file (time-subtract (current-time) time-delta)))
+
(ert-deftest auto-revert-test00-auto-revert-mode ()
"Check autorevert for a file."
;; `auto-revert-buffers' runs every 5". And we must wait, until the
;; file has been reverted.
- (let ((tmpfile (make-temp-file "auto-revert-test"))
- buf)
- (unwind-protect
- (progn
- (write-region "any text" nil tmpfile nil 'no-message)
- (setq buf (find-file-noselect tmpfile))
- (with-current-buffer buf
- (ert-with-message-capture auto-revert--messages
- (should (string-equal (buffer-string) "any text"))
- ;; `buffer-stale--default-function' checks for
- ;; `verify-visited-file-modtime'. We must ensure that it
- ;; returns nil.
- (sleep-for 1)
- (auto-revert-mode 1)
- (should auto-revert-mode)
-
- ;; Modify file. We wait for a second, in order to have
- ;; another timestamp.
- (sleep-for 1)
- (write-region "another text" nil tmpfile nil 'no-message)
-
- ;; Check, that the buffer has been reverted.
- (auto-revert--wait-for-revert buf))
- (should (string-match "another text" (buffer-string)))
-
- ;; When the buffer is modified, it shall not be reverted.
- (ert-with-message-capture auto-revert--messages
- (set-buffer-modified-p t)
- (sleep-for 1)
- (write-region "any text" nil tmpfile nil 'no-message)
-
- ;; Check, that the buffer hasn't been reverted.
- (auto-revert--wait-for-revert buf))
- (should-not (string-match "any text" (buffer-string)))))
-
- ;; Exit.
- (ignore-errors
- (with-current-buffer buf (set-buffer-modified-p nil))
- (kill-buffer buf))
- (ignore-errors (delete-file tmpfile)))))
+ (with-auto-revert-test
+ (let ((tmpfile (make-temp-file "auto-revert-test"))
+ (times '(60 30 15))
+ buf)
+ (unwind-protect
+ (progn
+ (auto-revert-tests--write-file "any text" tmpfile (pop times))
+ (setq buf (find-file-noselect tmpfile))
+ (with-current-buffer buf
+ (ert-with-message-capture auto-revert--messages
+ (should (string-equal (buffer-string) "any text"))
+ ;; `buffer-stale--default-function' checks for
+ ;; `verify-visited-file-modtime'. We must ensure that it
+ ;; returns nil.
+ (auto-revert-mode 1)
+ (should auto-revert-mode)
+
+ (auto-revert-tests--write-file "another text" tmpfile (pop times))
+
+ ;; Check, that the buffer has been reverted.
+ (auto-revert--wait-for-revert buf))
+ (should (string-match "another text" (buffer-string)))
+
+ ;; When the buffer is modified, it shall not be reverted.
+ (ert-with-message-capture auto-revert--messages
+ (set-buffer-modified-p t)
+ (auto-revert-tests--write-file "any text" tmpfile (pop times))
+
+ ;; Check, that the buffer hasn't been reverted.
+ (auto-revert--wait-for-revert buf))
+ (should-not (string-match "any text" (buffer-string)))))
+
+ ;; Exit.
+ (ignore-errors
+ (with-current-buffer buf (set-buffer-modified-p nil))
+ (kill-buffer buf))
+ (ignore-errors (delete-file tmpfile))))))
(auto-revert--deftest-remote auto-revert-test00-auto-revert-mode
"Check autorevert for a remote file.")
@@ -204,66 +215,65 @@ This expects `auto-revert--messages' to be bound by
;; This is inspired by Bug#21841.
(ert-deftest auto-revert-test01-auto-revert-several-files ()
"Check autorevert for several files at once."
- :tags '(:expensive-test)
(skip-unless (executable-find "cp" (file-remote-p temporary-file-directory)))
- (let* ((cp (executable-find "cp" (file-remote-p temporary-file-directory)))
- (tmpdir1 (make-temp-file "auto-revert-test" 'dir))
- (tmpdir2 (make-temp-file "auto-revert-test" 'dir))
- (tmpfile1
- (make-temp-file (expand-file-name "auto-revert-test" tmpdir1)))
- (tmpfile2
- (make-temp-file (expand-file-name "auto-revert-test" tmpdir1)))
- buf1 buf2)
- (unwind-protect
- (ert-with-message-capture auto-revert--messages
- (write-region "any text" nil tmpfile1 nil 'no-message)
- (setq buf1 (find-file-noselect tmpfile1))
- (write-region "any text" nil tmpfile2 nil 'no-message)
- (setq buf2 (find-file-noselect tmpfile2))
-
- (dolist (buf (list buf1 buf2))
- (with-current-buffer buf
- (should (string-equal (buffer-string) "any text"))
- ;; `buffer-stale--default-function' checks for
- ;; `verify-visited-file-modtime'. We must ensure that
- ;; it returns nil.
- (sleep-for 1)
- (auto-revert-mode 1)
- (should auto-revert-mode)))
-
- ;; Modify files. We wait for a second, in order to have
- ;; another timestamp.
- (sleep-for 1)
- (write-region
- "another text" nil
- (expand-file-name (file-name-nondirectory tmpfile1) tmpdir2)
- nil 'no-message)
- (write-region
- "another text" nil
- (expand-file-name (file-name-nondirectory tmpfile2) tmpdir2)
- nil 'no-message)
- ;;(copy-directory tmpdir2 tmpdir1 nil 'copy-contents)
- ;; Strange, that `copy-directory' does not work as expected.
- ;; The following shell command is not portable on all
- ;; platforms, unfortunately.
- (shell-command
- (format "%s -f %s/* %s"
- cp (file-local-name tmpdir2) (file-local-name tmpdir1)))
-
- ;; Check, that the buffers have been reverted.
- (dolist (buf (list buf1 buf2))
- (with-current-buffer buf
- (auto-revert--wait-for-revert buf)
- (should (string-match "another text" (buffer-string))))))
-
- ;; Exit.
- (ignore-errors
- (dolist (buf (list buf1 buf2))
- (with-current-buffer buf (set-buffer-modified-p nil))
- (kill-buffer buf)))
- (ignore-errors (delete-directory tmpdir1 'recursive))
- (ignore-errors (delete-directory tmpdir2 'recursive)))))
+ (with-auto-revert-test
+ (let* ((cp (executable-find "cp" (file-remote-p temporary-file-directory)))
+ (tmpdir1 (make-temp-file "auto-revert-test" 'dir))
+ (tmpdir2 (make-temp-file "auto-revert-test" 'dir))
+ (tmpfile1
+ (make-temp-file (expand-file-name "auto-revert-test" tmpdir1)))
+ (tmpfile2
+ (make-temp-file (expand-file-name "auto-revert-test" tmpdir1)))
+ (times '(120 60 30 15))
+ buf1 buf2)
+ (unwind-protect
+ (ert-with-message-capture auto-revert--messages
+ (auto-revert-tests--write-file "any text" tmpfile1 (pop times))
+ (setq buf1 (find-file-noselect tmpfile1))
+ (auto-revert-tests--write-file "any text" tmpfile2 (pop times))
+ (setq buf2 (find-file-noselect tmpfile2))
+
+ (dolist (buf (list buf1 buf2))
+ (with-current-buffer buf
+ (should (string-equal (buffer-string) "any text"))
+ ;; `buffer-stale--default-function' checks for
+ ;; `verify-visited-file-modtime'. We must ensure that
+ ;; it returns nil.
+ (auto-revert-mode 1)
+ (should auto-revert-mode)))
+
+ ;; Modify files. We wait for a second, in order to have
+ ;; another timestamp.
+ (auto-revert-tests--write-file
+ "another text"
+ (expand-file-name (file-name-nondirectory tmpfile1) tmpdir2)
+ (pop times))
+ (auto-revert-tests--write-file
+ "another text"
+ (expand-file-name (file-name-nondirectory tmpfile2) tmpdir2)
+ (pop times))
+ ;;(copy-directory tmpdir2 tmpdir1 nil 'copy-contents)
+ ;; Strange, that `copy-directory' does not work as expected.
+ ;; The following shell command is not portable on all
+ ;; platforms, unfortunately.
+ (shell-command
+ (format "%s -f %s/* %s"
+ cp (file-local-name tmpdir2) (file-local-name tmpdir1)))
+
+ ;; Check, that the buffers have been reverted.
+ (dolist (buf (list buf1 buf2))
+ (with-current-buffer buf
+ (auto-revert--wait-for-revert buf)
+ (should (string-match "another text" (buffer-string))))))
+
+ ;; Exit.
+ (ignore-errors
+ (dolist (buf (list buf1 buf2))
+ (with-current-buffer buf (set-buffer-modified-p nil))
+ (kill-buffer buf)))
+ (ignore-errors (delete-directory tmpdir1 'recursive))
+ (ignore-errors (delete-directory tmpdir2 'recursive))))))
(auto-revert--deftest-remote auto-revert-test01-auto-revert-several-files
"Check autorevert for several remote files at once.")
@@ -271,84 +281,81 @@ This expects `auto-revert--messages' to be bound by
;; This is inspired by Bug#23276.
(ert-deftest auto-revert-test02-auto-revert-deleted-file ()
"Check autorevert for a deleted file."
- :tags '(:expensive-test)
;; Repeated unpredictable failures, bug#32645.
;; Unlikely to be hydra-specific?
; (skip-unless (not (getenv "EMACS_HYDRA_CI")))
- (let ((tmpfile (make-temp-file "auto-revert-test"))
- ;; Try to catch bug#32645.
- (auto-revert-debug (getenv "EMACS_HYDRA_CI"))
- (file-notify-debug (getenv "EMACS_HYDRA_CI"))
- buf desc)
- (unwind-protect
- (progn
- (write-region "any text" nil tmpfile nil 'no-message)
- (setq buf (find-file-noselect tmpfile))
- (with-current-buffer buf
- (should-not
- (file-notify-valid-p auto-revert-notify-watch-descriptor))
- (should (string-equal (buffer-string) "any text"))
- ;; `buffer-stale--default-function' checks for
- ;; `verify-visited-file-modtime'. We must ensure that
- ;; it returns nil.
- (sleep-for 1)
- (auto-revert-mode 1)
- (should auto-revert-mode)
- (setq desc auto-revert-notify-watch-descriptor)
-
- ;; Remove file while reverting. We simulate this by
- ;; modifying `before-revert-hook'.
- (add-hook
- 'before-revert-hook
- (lambda ()
- (when auto-revert-debug
- (message "%s deleted" buffer-file-name))
- (delete-file buffer-file-name))
- nil t)
-
- (ert-with-message-capture auto-revert--messages
- (sleep-for 1)
- (write-region "another text" nil tmpfile nil 'no-message)
- (auto-revert--wait-for-revert buf))
- ;; Check, that the buffer hasn't been reverted. File
- ;; notification should be disabled, falling back to
- ;; polling.
- (should (string-match "any text" (buffer-string)))
- ;; With w32notify, and on emba, the `stopped' events are not sent.
- (or (eq file-notify--library 'w32notify)
- (getenv "EMACS_EMBA_CI")
- (should-not
- (file-notify-valid-p auto-revert-notify-watch-descriptor)))
-
- ;; Once the file has been recreated, the buffer shall be
- ;; reverted.
- (kill-local-variable 'before-revert-hook)
- (ert-with-message-capture auto-revert--messages
- (sleep-for 1)
- (write-region "another text" nil tmpfile nil 'no-message)
- (auto-revert--wait-for-revert buf))
- ;; Check, that the buffer has been reverted.
- (should (string-match "another text" (buffer-string)))
- ;; When file notification is used, it must be reenabled
- ;; after recreation of the file. We cannot expect that
- ;; the descriptor is the same, so we just check the
- ;; existence.
- (should (eq (null desc) (null auto-revert-notify-watch-descriptor)))
-
- ;; An empty file shall still be reverted.
- (ert-with-message-capture auto-revert--messages
- (sleep-for 1)
- (write-region "" nil tmpfile nil 'no-message)
- (auto-revert--wait-for-revert buf))
- ;; Check, that the buffer has been reverted.
- (should (string-equal "" (buffer-string)))))
-
- ;; Exit.
- (ignore-errors
- (with-current-buffer buf (set-buffer-modified-p nil))
- (kill-buffer buf))
- (ignore-errors (delete-file tmpfile)))))
+ (with-auto-revert-test
+ (let ((tmpfile (make-temp-file "auto-revert-test"))
+ ;; Try to catch bug#32645.
+ (auto-revert-debug (getenv "EMACS_HYDRA_CI"))
+ (file-notify-debug (getenv "EMACS_HYDRA_CI"))
+ (times '(120 60 30 15))
+ buf desc)
+ (unwind-protect
+ (progn
+ (auto-revert-tests--write-file "any text" tmpfile (pop times))
+ (setq buf (find-file-noselect tmpfile))
+ (with-current-buffer buf
+ (should-not
+ (file-notify-valid-p auto-revert-notify-watch-descriptor))
+ (should (string-equal (buffer-string) "any text"))
+ ;; `buffer-stale--default-function' checks for
+ ;; `verify-visited-file-modtime'. We must ensure that
+ ;; it returns nil.
+ (auto-revert-mode 1)
+ (should auto-revert-mode)
+ (setq desc auto-revert-notify-watch-descriptor)
+
+ ;; Remove file while reverting. We simulate this by
+ ;; modifying `before-revert-hook'.
+ (add-hook
+ 'before-revert-hook
+ (lambda ()
+ (when auto-revert-debug
+ (message "%s deleted" buffer-file-name))
+ (delete-file buffer-file-name))
+ nil t)
+
+ (ert-with-message-capture auto-revert--messages
+ (auto-revert-tests--write-file "another text" tmpfile (pop times))
+ (auto-revert--wait-for-revert buf))
+ ;; Check, that the buffer hasn't been reverted. File
+ ;; notification should be disabled, falling back to
+ ;; polling.
+ (should (string-match "any text" (buffer-string)))
+ ;; With w32notify, and on emba, the `stopped' events are not sent.
+ (or (eq file-notify--library 'w32notify)
+ (getenv "EMACS_EMBA_CI")
+ (should-not
+ (file-notify-valid-p auto-revert-notify-watch-descriptor)))
+
+ ;; Once the file has been recreated, the buffer shall be
+ ;; reverted.
+ (kill-local-variable 'before-revert-hook)
+ (ert-with-message-capture auto-revert--messages
+ (auto-revert-tests--write-file "another text" tmpfile (pop times))
+ (auto-revert--wait-for-revert buf))
+ ;; Check, that the buffer has been reverted.
+ (should (string-match "another text" (buffer-string)))
+ ;; When file notification is used, it must be reenabled
+ ;; after recreation of the file. We cannot expect that
+ ;; the descriptor is the same, so we just check the
+ ;; existence.
+ (should (eq (null desc) (null auto-revert-notify-watch-descriptor)))
+
+ ;; An empty file shall still be reverted.
+ (ert-with-message-capture auto-revert--messages
+ (auto-revert-tests--write-file "" tmpfile (pop times))
+ (auto-revert--wait-for-revert buf))
+ ;; Check, that the buffer has been reverted.
+ (should (string-equal "" (buffer-string)))))
+
+ ;; Exit.
+ (ignore-errors
+ (with-current-buffer buf (set-buffer-modified-p nil))
+ (kill-buffer buf))
+ (ignore-errors (delete-file tmpfile))))))
(auto-revert--deftest-remote auto-revert-test02-auto-revert-deleted-file
"Check autorevert for a deleted remote file.")
@@ -358,26 +365,24 @@ This expects `auto-revert--messages' to be bound by
;; `auto-revert-buffers' runs every 5". And we must wait, until the
;; file has been reverted.
(let ((tmpfile (make-temp-file "auto-revert-test"))
+ (times '(30 15))
buf)
(unwind-protect
(ert-with-message-capture auto-revert--messages
- (write-region "any text" nil tmpfile nil 'no-message)
+ (auto-revert-tests--write-file "any text" tmpfile (pop times))
(setq buf (find-file-noselect tmpfile))
(with-current-buffer buf
;; `buffer-stale--default-function' checks for
;; `verify-visited-file-modtime'. We must ensure that it
;; returns nil.
- (sleep-for 1)
(auto-revert-tail-mode 1)
(should auto-revert-tail-mode)
(erase-buffer)
(insert "modified text\n")
(set-buffer-modified-p nil)
- ;; Modify file. We wait for a second, in order to have
- ;; another timestamp.
- (sleep-for 1)
- (write-region "another text" nil tmpfile 'append 'no-message)
+ ;; Modify file.
+ (auto-revert-tests--write-file "another text" tmpfile (pop times) 'append)
;; Check, that the buffer has been reverted.
(auto-revert--wait-for-revert buf)
@@ -395,49 +400,47 @@ This expects `auto-revert--messages' to be bound by
"Check autorevert for dired."
;; `auto-revert-buffers' runs every 5". And we must wait, until the
;; file has been reverted.
- (let* ((tmpfile (make-temp-file "auto-revert-test"))
- (name (file-name-nondirectory tmpfile))
- buf)
- (unwind-protect
- (progn
- (setq buf (dired-noselect temporary-file-directory))
- (with-current-buffer buf
- ;; `buffer-stale--default-function' checks for
- ;; `verify-visited-file-modtime'. We must ensure that it
- ;; returns nil.
- (sleep-for 1)
- (auto-revert-mode 1)
- (should auto-revert-mode)
- (should
- (string-match name (substring-no-properties (buffer-string))))
-
- (ert-with-message-capture auto-revert--messages
- ;; Delete file. We wait for a second, in order to have
- ;; another timestamp.
- (sleep-for 1)
- (delete-file tmpfile)
- (auto-revert--wait-for-revert buf))
- ;; Check, that the buffer has been reverted.
- (should-not
- (string-match name (substring-no-properties (buffer-string))))
-
- (ert-with-message-capture auto-revert--messages
- ;; Make dired buffer modified. Check, that the buffer has
- ;; been still reverted.
- (set-buffer-modified-p t)
- (sleep-for 1)
- (write-region "any text" nil tmpfile nil 'no-message)
-
- (auto-revert--wait-for-revert buf))
- ;; Check, that the buffer has been reverted.
- (should
- (string-match name (substring-no-properties (buffer-string))))))
-
- ;; Exit.
- (ignore-errors
- (with-current-buffer buf (set-buffer-modified-p nil))
- (kill-buffer buf))
- (ignore-errors (delete-file tmpfile)))))
+ (with-auto-revert-test
+ (let* ((tmpfile (make-temp-file "auto-revert-test"))
+ (name (file-name-nondirectory tmpfile))
+ (times '(30))
+ buf)
+ (unwind-protect
+ (progn
+ (setq buf (dired-noselect temporary-file-directory))
+ (with-current-buffer buf
+ ;; `buffer-stale--default-function' checks for
+ ;; `verify-visited-file-modtime'. We must ensure that it
+ ;; returns nil.
+ (auto-revert-mode 1)
+ (should auto-revert-mode)
+ (should
+ (string-match name (substring-no-properties (buffer-string))))
+
+ (ert-with-message-capture auto-revert--messages
+ ;; Delete file.
+ (delete-file tmpfile)
+ (auto-revert--wait-for-revert buf))
+ ;; Check, that the buffer has been reverted.
+ (should-not
+ (string-match name (substring-no-properties (buffer-string))))
+
+ (ert-with-message-capture auto-revert--messages
+ ;; Make dired buffer modified. Check, that the buffer has
+ ;; been still reverted.
+ (set-buffer-modified-p t)
+ (auto-revert-tests--write-file "any text" tmpfile (pop times))
+
+ (auto-revert--wait-for-revert buf))
+ ;; Check, that the buffer has been reverted.
+ (should
+ (string-match name (substring-no-properties (buffer-string))))))
+
+ ;; Exit.
+ (ignore-errors
+ (with-current-buffer buf (set-buffer-modified-p nil))
+ (kill-buffer buf))
+ (ignore-errors (delete-file tmpfile))))))
(auto-revert--deftest-remote auto-revert-test04-auto-revert-mode-dired
"Check remote autorevert for dired.")
@@ -466,121 +469,203 @@ This expects `auto-revert--messages' to be bound by
(ert-deftest auto-revert-test05-global-notify ()
"Test `global-auto-revert-mode' without polling."
- :tags '(:expensive-test)
(skip-unless (or file-notify--library
(file-remote-p temporary-file-directory)))
- (let* ((auto-revert-use-notify t)
- (auto-revert-avoid-polling t)
- (was-in-global-auto-revert-mode global-auto-revert-mode)
- (file-1 (make-temp-file "global-auto-revert-test-1"))
- (file-2 (make-temp-file "global-auto-revert-test-2"))
- (file-3 (make-temp-file "global-auto-revert-test-3"))
- (file-2b (concat file-2 "-b"))
- require-final-newline buf-1 buf-2 buf-3)
- (unwind-protect
- (progn
- (setq buf-1 (find-file-noselect file-1))
- (setq buf-2 (find-file-noselect file-2))
- (auto-revert-test--write-file "1-a" file-1)
- (should (equal (auto-revert-test--buffer-string buf-1) ""))
-
- (global-auto-revert-mode 1) ; Turn it on.
-
- (should (buffer-local-value
- 'auto-revert-notify-watch-descriptor buf-1))
- (should (buffer-local-value
- 'auto-revert-notify-watch-descriptor buf-2))
-
- ;; buf-1 should have been reverted immediately when the mode
- ;; was enabled.
- (should (equal (auto-revert-test--buffer-string buf-1) "1-a"))
-
- ;; Alter a file.
- (auto-revert-test--write-file "2-a" file-2)
- ;; Allow for some time to handle notification events.
- (auto-revert-test--wait-for-buffer-text buf-2 "2-a" 1)
- (should (equal (auto-revert-test--buffer-string buf-2) "2-a"))
-
- ;; Visit a file, and modify it on disk.
- (setq buf-3 (find-file-noselect file-3))
- ;; Newly opened buffers won't be use notification until the
- ;; first poll cycle; wait for it.
- (auto-revert-test--wait-for
- (lambda () (buffer-local-value
- 'auto-revert-notify-watch-descriptor buf-3))
- auto-revert--timeout)
- (should (buffer-local-value
+ (with-auto-revert-test
+ (let* ((auto-revert-use-notify t)
+ (auto-revert-avoid-polling t)
+ (was-in-global-auto-revert-mode global-auto-revert-mode)
+ (file-1 (make-temp-file "global-auto-revert-test-1"))
+ (file-2 (make-temp-file "global-auto-revert-test-2"))
+ (file-3 (make-temp-file "global-auto-revert-test-3"))
+ (file-2b (concat file-2 "-b"))
+ require-final-newline buf-1 buf-2 buf-3)
+ (unwind-protect
+ (progn
+ (setq buf-1 (find-file-noselect file-1))
+ (setq buf-2 (find-file-noselect file-2))
+ (auto-revert-test--write-file "1-a" file-1)
+ (should (equal (auto-revert-test--buffer-string buf-1) ""))
+
+ (global-auto-revert-mode 1) ; Turn it on.
+
+ (should (buffer-local-value
+ 'auto-revert-notify-watch-descriptor buf-1))
+ (should (buffer-local-value
+ 'auto-revert-notify-watch-descriptor buf-2))
+
+ ;; buf-1 should have been reverted immediately when the mode
+ ;; was enabled.
+ (should (equal (auto-revert-test--buffer-string buf-1) "1-a"))
+
+ ;; Alter a file.
+ (auto-revert-test--write-file "2-a" file-2)
+ ;; Allow for some time to handle notification events.
+ (auto-revert-test--wait-for-buffer-text buf-2 "2-a" 1)
+ (should (equal (auto-revert-test--buffer-string buf-2) "2-a"))
+
+ ;; Visit a file, and modify it on disk.
+ (setq buf-3 (find-file-noselect file-3))
+ ;; Newly opened buffers won't be use notification until the
+ ;; first poll cycle; wait for it.
+ (auto-revert-test--wait-for
+ (lambda () (buffer-local-value
'auto-revert-notify-watch-descriptor buf-3))
- (auto-revert-test--write-file "3-a" file-3)
- (auto-revert-test--wait-for-buffer-text buf-3 "3-a" 1)
- (should (equal (auto-revert-test--buffer-string buf-3) "3-a"))
-
- ;; Delete a visited file, and re-create it with new contents.
- (delete-file file-1)
- (sleep-for 0.5)
- (should (equal (auto-revert-test--buffer-string buf-1) "1-a"))
- (auto-revert-test--write-file "1-b" file-1)
- (auto-revert-test--wait-for-buffer-text
- buf-1 "1-b" auto-revert--timeout)
- (should (buffer-local-value
- 'auto-revert-notify-watch-descriptor buf-1))
-
- ;; Write a buffer to a new file, then modify the new file on disk.
- (with-current-buffer buf-2
- (write-file file-2b))
- (should (equal (auto-revert-test--buffer-string buf-2) "2-a"))
- (auto-revert-test--write-file "2-b" file-2b)
- (auto-revert-test--wait-for-buffer-text
- buf-2 "2-b" auto-revert--timeout)
- (should (buffer-local-value
- 'auto-revert-notify-watch-descriptor buf-2)))
-
- ;; Clean up.
- (unless was-in-global-auto-revert-mode
- (global-auto-revert-mode 0)) ; Turn it off.
- (dolist (buf (list buf-1 buf-2 buf-3))
- (ignore-errors (kill-buffer buf)))
- (dolist (file (list file-1 file-2 file-2b file-3))
- (ignore-errors (delete-file file)))
- )))
+ (auto-revert--timeout))
+ (should (buffer-local-value
+ 'auto-revert-notify-watch-descriptor buf-3))
+ (auto-revert-test--write-file "3-a" file-3)
+ (auto-revert-test--wait-for-buffer-text buf-3 "3-a" 1)
+ (should (equal (auto-revert-test--buffer-string buf-3) "3-a"))
+
+ ;; Delete a visited file, and re-create it with new contents.
+ (delete-file file-1)
+ (should (equal (auto-revert-test--buffer-string buf-1) "1-a"))
+ (auto-revert-test--write-file "1-b" file-1)
+ (auto-revert-test--wait-for-buffer-text
+ buf-1 "1-b" (auto-revert--timeout))
+ (should (buffer-local-value
+ 'auto-revert-notify-watch-descriptor buf-1))
+
+ ;; Write a buffer to a new file, then modify the new file on disk.
+ (with-current-buffer buf-2
+ (write-file file-2b))
+ (should (equal (auto-revert-test--buffer-string buf-2) "2-a"))
+ (auto-revert-test--write-file "2-b" file-2b)
+ (auto-revert-test--wait-for-buffer-text
+ buf-2 "2-b" (auto-revert--timeout))
+ (should (buffer-local-value
+ 'auto-revert-notify-watch-descriptor buf-2)))
+
+ ;; Clean up.
+ (unless was-in-global-auto-revert-mode
+ (global-auto-revert-mode 0)) ; Turn it off.
+ (dolist (buf (list buf-1 buf-2 buf-3))
+ (ignore-errors (kill-buffer buf)))
+ (dolist (file (list file-1 file-2 file-2b file-3))
+ (ignore-errors (delete-file file)))
+ ))))
(auto-revert--deftest-remote auto-revert-test05-global-notify
"Test `global-auto-revert-mode' without polling for remote buffers.")
(ert-deftest auto-revert-test06-write-file ()
"Verify that notification follows `write-file' correctly."
- :tags '(:expensive-test)
(skip-unless (or file-notify--library
(file-remote-p temporary-file-directory)))
- (let* ((auto-revert-use-notify t)
- (file-1 (make-temp-file "auto-revert-test"))
- (file-2 (concat file-1 "-2"))
- require-final-newline buf)
- (unwind-protect
- (progn
- (setq buf (find-file-noselect file-1))
- (with-current-buffer buf
- (insert "A")
- (save-buffer)
-
- (auto-revert-mode 1)
-
- (insert "B")
- (write-file file-2)
-
- (auto-revert-test--write-file "C" file-2)
- (auto-revert-test--wait-for-buffer-text
- buf "C" auto-revert--timeout)
- (should (equal (buffer-string) "C"))))
-
- ;; Clean up.
- (ignore-errors (kill-buffer buf))
- (ignore-errors (delete-file file-1))
- (ignore-errors (delete-file file-2)))))
+ (with-auto-revert-test
+ (let* ((auto-revert-use-notify t)
+ (file-1 (make-temp-file "auto-revert-test"))
+ (file-2 (concat file-1 "-2"))
+ require-final-newline buf)
+ (unwind-protect
+ (progn
+ (setq buf (find-file-noselect file-1))
+ (with-current-buffer buf
+ (insert "A")
+ (save-buffer)
+
+ (auto-revert-mode 1)
+
+ (insert "B")
+ (write-file file-2)
+
+ (auto-revert-test--write-file "C" file-2)
+ (auto-revert-test--wait-for-buffer-text
+ buf "C" (auto-revert--timeout))
+ (should (equal (buffer-string) "C"))))
+
+ ;; Clean up.
+ (ignore-errors (kill-buffer buf))
+ (ignore-errors (delete-file file-1))
+ (ignore-errors (delete-file file-2))))))
(auto-revert--deftest-remote auto-revert-test06-write-file
"Test `write-file' in `auto-revert-mode' for remote buffers.")
+;; This is inspired by Bug#44638.
+(ert-deftest auto-revert-test07-auto-revert-several-buffers ()
+ "Check autorevert for several buffers visiting the same file."
+ ;; (with-auto-revert-test
+ (let ((auto-revert-use-notify t)
+ (tmpfile (make-temp-file "auto-revert-test"))
+ (times '(120 60 30 15))
+ (num-buffers 10)
+ require-final-newline buffers)
+
+ (unwind-protect
+ ;; Check indirect buffers.
+ (ert-with-message-capture auto-revert--messages
+ (auto-revert-tests--write-file "any text" tmpfile (pop times))
+ (push (find-file-noselect tmpfile) buffers)
+ (with-current-buffer (car buffers)
+ (should (string-equal (buffer-string) "any text"))
+ ;; `buffer-stale--default-function' checks for
+ ;; `verify-visited-file-modtime'. We must ensure that
+ ;; it returns nil.
+ (auto-revert-mode 1)
+ (should auto-revert-mode))
+
+ (dotimes (i num-buffers)
+ (add-to-list
+ 'buffers
+ (make-indirect-buffer
+ (car buffers) (format "%s-%d" (buffer-file-name (car buffers)) i) 'clone)
+ 'append))
+ (dolist (buf buffers)
+ (with-current-buffer buf
+ (should (string-equal (buffer-string) "any text"))
+ (should auto-revert-mode)))
+
+ (auto-revert-tests--write-file "another text" tmpfile (pop times))
+ ;; Check, that the buffer has been reverted.
+ (auto-revert--wait-for-revert (car buffers))
+ (dolist (buf buffers)
+ (with-current-buffer buf
+ (should (string-equal (buffer-string) "another text")))))
+
+ ;; Exit.
+ (ignore-errors
+ (dolist (buf buffers)
+ (with-current-buffer buf (set-buffer-modified-p nil))
+ (kill-buffer buf)))
+ (setq buffers nil)
+ (ignore-errors (delete-file tmpfile)))
+
+ ;; Check direct buffers.
+ (unwind-protect
+ (ert-with-message-capture auto-revert--messages
+ (auto-revert-tests--write-file "any text" tmpfile (pop times))
+
+ (dotimes (i num-buffers)
+ (add-to-list
+ 'buffers
+ (generate-new-buffer (format "%s-%d" (file-name-nondirectory tmpfile) i))
+ 'append))
+ (dolist (buf buffers)
+ (with-current-buffer buf
+ (insert-file-contents tmpfile 'visit)
+ (should (string-equal (buffer-string) "any text"))
+ (auto-revert-mode 1)
+ (should auto-revert-mode)))
+
+ (auto-revert-tests--write-file "another text" tmpfile (pop times))
+ ;; Check, that the buffers have been reverted.
+ (dolist (buf buffers)
+ (auto-revert--wait-for-revert buf)
+ (with-current-buffer buf
+ (should (string-equal (buffer-string) "another text")))))
+
+ ;; Exit.
+ (ignore-errors
+ (dolist (buf buffers)
+ (with-current-buffer buf (set-buffer-modified-p nil))
+ (kill-buffer buf)))
+ (ignore-errors (delete-file tmpfile)))));)
+
+(auto-revert--deftest-remote auto-revert-test07-auto-revert-several-buffers
+ "Check autorevert for several buffers visiting the same remote file.")
+
(defun auto-revert-test-all (&optional interactive)
"Run all tests for \\[auto-revert]."
(interactive "p")
diff --git a/test/lisp/battery-tests.el b/test/lisp/battery-tests.el
index 8286e772893..e34d59102bc 100644
--- a/test/lisp/battery-tests.el
+++ b/test/lisp/battery-tests.el
@@ -22,9 +22,9 @@
(require 'battery)
(ert-deftest battery-linux-proc-apm-regexp ()
- "Test `battery-linux-proc-apm-regexp'."
+ "Test `rx' definition `battery--linux-proc-apm'."
(let ((str "1.16 1.2 0x07 0x01 0xff 0x80 -1% -1 ?"))
- (should (string-match battery-linux-proc-apm-regexp str))
+ (should (string-match (rx battery--linux-proc-apm) str))
(should (equal (match-string 0 str) str))
(should (equal (match-string 1 str) "1.16"))
(should (equal (match-string 2 str) "1.2"))
@@ -36,7 +36,7 @@
(should (equal (match-string 8 str) "-1"))
(should (equal (match-string 9 str) "?")))
(let ((str "1.16 1.2 0x03 0x00 0x00 0x01 99% 1792 min"))
- (should (string-match battery-linux-proc-apm-regexp str))
+ (should (string-match (rx battery--linux-proc-apm) str))
(should (equal (match-string 0 str) str))
(should (equal (match-string 1 str) "1.16"))
(should (equal (match-string 2 str) "1.2"))
@@ -48,11 +48,107 @@
(should (equal (match-string 8 str) "1792"))
(should (equal (match-string 9 str) "min"))))
+(ert-deftest battery-acpi-rate-regexp ()
+ "Test `rx' definition `battery--acpi-rate'."
+ (let ((str "01 mA"))
+ (should (string-match (rx (battery--acpi-rate)) str))
+ (should (equal (match-string 0 str) str))
+ (should (equal (match-string 1 str) "01"))
+ (should (equal (match-string 2 str) "mA")))
+ (let ((str "23 mW"))
+ (should (string-match (rx (battery--acpi-rate)) str))
+ (should (equal (match-string 0 str) str))
+ (should (equal (match-string 1 str) "23"))
+ (should (equal (match-string 2 str) "mW")))
+ (let ((str "23 mWh"))
+ (should (string-match (rx (battery--acpi-rate)) str))
+ (should (equal (match-string 0 str) "23 mW"))
+ (should (equal (match-string 1 str) "23"))
+ (should (equal (match-string 2 str) "mW")))
+ (should-not (string-match (rx (battery--acpi-rate) eos) "45 mWh")))
+
+(ert-deftest battery-acpi-capacity-regexp ()
+ "Test `rx' definition `battery--acpi-capacity'."
+ (let ((str "01 mAh"))
+ (should (string-match (rx battery--acpi-capacity) str))
+ (should (equal (match-string 0 str) str))
+ (should (equal (match-string 1 str) "01"))
+ (should (equal (match-string 2 str) "mAh")))
+ (let ((str "23 mWh"))
+ (should (string-match (rx battery--acpi-capacity) str))
+ (should (equal (match-string 0 str) str))
+ (should (equal (match-string 1 str) "23"))
+ (should (equal (match-string 2 str) "mWh")))
+ (should-not (string-match (rx battery--acpi-capacity eos) "45 mW")))
+
+(ert-deftest battery-upower-state ()
+ "Test `battery--upower-state'."
+ ;; Charging.
+ (dolist (total '(nil charging discharging empty fully-charged
+ pending-charge pending-discharge))
+ (should (eq (battery--upower-state '(("State" . 1)) total) 'charging)))
+ (dolist (state '(nil 0 1 2 3 4 5 6))
+ (should (eq (battery--upower-state `(("State" . ,state)) 'charging)
+ 'charging)))
+ ;; Discharging.
+ (dolist (total '(nil discharging empty fully-charged
+ pending-charge pending-discharge))
+ (should (eq (battery--upower-state '(("State" . 2)) total) 'discharging)))
+ (dolist (state '(nil 0 2 3 4 5 6))
+ (should (eq (battery--upower-state `(("State" . ,state)) 'discharging)
+ 'discharging)))
+ ;; Pending charge.
+ (dolist (total '(nil empty fully-charged pending-charge pending-discharge))
+ (should (eq (battery--upower-state '(("State" . 5)) total)
+ 'pending-charge)))
+ (dolist (state '(nil 0 3 4 5 6))
+ (should (eq (battery--upower-state `(("State" . ,state)) 'pending-charge)
+ 'pending-charge)))
+ ;; Pending discharge.
+ (dolist (total '(nil empty fully-charged pending-discharge))
+ (should (eq (battery--upower-state '(("State" . 6)) total)
+ 'pending-discharge)))
+ (dolist (state '(nil 0 3 4 6))
+ (should (eq (battery--upower-state `(("State" . ,state)) 'pending-discharge)
+ 'pending-discharge)))
+ ;; Empty.
+ (dolist (total '(nil empty))
+ (should (eq (battery--upower-state '(("State" . 3)) total) 'empty)))
+ (dolist (state '(nil 0 3))
+ (should (eq (battery--upower-state `(("State" . ,state)) 'empty) 'empty)))
+ ;; Fully charged.
+ (dolist (total '(nil fully-charged))
+ (should (eq (battery--upower-state '(("State" . 4)) total) 'fully-charged)))
+ (dolist (state '(nil 0 4))
+ (should (eq (battery--upower-state `(("State" . ,state)) 'fully-charged)
+ 'fully-charged))))
+
+(ert-deftest battery-upower-state-unknown ()
+ "Test `battery--upower-state' with unknown states."
+ ;; Unknown running total retains new state.
+ (should-not (battery--upower-state () nil))
+ (should-not (battery--upower-state '(("State" . state)) nil))
+ (should-not (battery--upower-state '(("State" . 0)) nil))
+ (should (eq (battery--upower-state '(("State" . 1)) nil) 'charging))
+ (should (eq (battery--upower-state '(("State" . 2)) nil) 'discharging))
+ (should (eq (battery--upower-state '(("State" . 3)) nil) 'empty))
+ (should (eq (battery--upower-state '(("State" . 4)) nil) 'fully-charged))
+ (should (eq (battery--upower-state '(("State" . 5)) nil) 'pending-charge))
+ (should (eq (battery--upower-state '(("State" . 6)) nil) 'pending-discharge))
+ ;; Unknown new state retains running total.
+ (dolist (props '(() (("State" . state)) (("State" . 0))))
+ (dolist (total '(nil charging discharging empty fully-charged
+ pending-charge pending-discharge))
+ (should (eq (battery--upower-state props total) total))))
+ ;; Conflicting empty and fully-charged.
+ (should-not (battery--upower-state '(("State" . 3)) 'fully-charged))
+ (should-not (battery--upower-state '(("State" . 4)) 'empty)))
+
(ert-deftest battery-format ()
"Test `battery-format'."
(should (equal (battery-format "" ()) ""))
(should (equal (battery-format "" '((?b . "-"))) ""))
- (should (equal (battery-format "%a%b%p%%" '((?b . "-") (?p . "99")))
- "-99%")))
+ (should (equal (battery-format "%2a%-3b%.1p%%" '((?b . "-") (?p . "99")))
+ "- 9%")))
;;; battery-tests.el ends here
diff --git a/test/lisp/bookmark-resources/test-list.bmk b/test/lisp/bookmark-resources/test-list.bmk
new file mode 100644
index 00000000000..696d64979b8
--- /dev/null
+++ b/test/lisp/bookmark-resources/test-list.bmk
@@ -0,0 +1,20 @@
+;;;; Emacs Bookmark Format Version 1 ;;;; -*- coding: utf-8-emacs -*-
+;;; This format is meant to be slightly human-readable;
+;;; nevertheless, you probably don't want to edit it.
+;;; -*- End Of Bookmark File Format Version Stamp -*-
+(("name-0"
+ (filename . "/some/file-0")
+ (front-context-string . "abc")
+ (rear-context-string . "def")
+ (position . 3))
+("name-1"
+ (filename . "/some/file-1")
+ (front-context-string . "abc")
+ (rear-context-string . "def")
+ (position . 3))
+("name-2"
+ (filename . "/some/file-2")
+ (front-context-string . "abc")
+ (rear-context-string . "def")
+ (position . 3))
+)
diff --git a/test/lisp/bookmark-tests.el b/test/lisp/bookmark-tests.el
index 38e17bc0045..9c33a27288a 100644
--- a/test/lisp/bookmark-tests.el
+++ b/test/lisp/bookmark-tests.el
@@ -24,23 +24,17 @@
;;; Code:
(require 'ert)
+(require 'ert-x)
(require 'bookmark)
+(require 'cl-lib)
-(defvar bookmark-tests-data-dir
- (file-truename
- (expand-file-name "bookmark-resources/"
- (file-name-directory (or load-file-name
- buffer-file-name))))
- "Base directory of bookmark-tests.el data files.")
-
-(defvar bookmark-tests-bookmark-file
- (expand-file-name "test.bmk" bookmark-tests-data-dir)
+(defvar bookmark-tests-bookmark-file (ert-resource-file "test.bmk")
"Bookmark file used for testing.")
(defvar bookmark-tests-example-file
;; We use abbreviate-file-name here to match the behavior of
;; `bookmark-buffer-file-name'.
- (abbreviate-file-name (expand-file-name "example.txt" bookmark-tests-data-dir))
+ (abbreviate-file-name (ert-resource-file "example.txt"))
"Example file used for testing.")
;; The values below should match `bookmark-tests-bookmark-file'. We cache
@@ -82,6 +76,69 @@ the lexically-bound variable `buffer'."
,@body)
(kill-buffer buffer))))
+(defvar bookmark-tests-bookmark-file-list (ert-resource-file "test-list.bmk")
+ "Bookmark file used for testing a list of bookmarks.")
+
+;; The values below should match `bookmark-tests-bookmark-file-list'
+;; content. We cache these values to speed up tests.
+(eval-and-compile ; needed by `with-bookmark-test-list' macro
+ (defvar bookmark-tests-bookmark-list-0 '("name-0"
+ (filename . "/some/file-0")
+ (front-context-string . "ghi")
+ (rear-context-string . "jkl")
+ (position . 4))
+ "Cached value used in bookmark-tests.el."))
+
+;; The values below should match `bookmark-tests-bookmark-file-list'
+;; content. We cache these values to speed up tests.
+(eval-and-compile ; needed by `with-bookmark-test-list' macro
+ (defvar bookmark-tests-bookmark-list-1 '("name-1"
+ (filename . "/some/file-1")
+ (front-context-string . "mno")
+ (rear-context-string . "pqr")
+ (position . 5))
+ "Cached value used in bookmark-tests.el."))
+
+;; The values below should match `bookmark-tests-bookmark-file-list'
+;; content. We cache these values to speed up tests.
+(eval-and-compile ; needed by `with-bookmark-test-list' macro
+ (defvar bookmark-tests-bookmark-list-2 '("name-2"
+ (filename . "/some/file-2")
+ (front-context-string . "stu")
+ (rear-context-string . "vwx")
+ (position . 6))
+ "Cached value used in bookmark-tests.el."))
+
+(defvar bookmark-tests-cache-timestamp-list
+ (cons bookmark-tests-bookmark-file-list
+ (nth 5 (file-attributes
+ bookmark-tests-bookmark-file-list)))
+ "Cached value used in bookmark-tests.el.")
+
+(defmacro with-bookmark-test-list (&rest body)
+ "Create environment for testing bookmark.el and evaluate BODY.
+Ensure a clean environment for testing, and do not change user
+data when running tests interactively."
+ `(with-temp-buffer
+ (let ((bookmark-alist (quote (,(copy-sequence bookmark-tests-bookmark-list-0)
+ ,(copy-sequence bookmark-tests-bookmark-list-1)
+ ,(copy-sequence bookmark-tests-bookmark-list-2))))
+ (bookmark-default-file bookmark-tests-bookmark-file-list)
+ (bookmark-bookmarks-timestamp bookmark-tests-cache-timestamp-list)
+ bookmark-save-flag)
+ ,@body)))
+
+(defmacro with-bookmark-test-file-list (&rest body)
+ "Create environment for testing bookmark.el and evaluate BODY.
+Same as `with-bookmark-test-list' but also opens the resource file
+example.txt in a buffer, which can be accessed by callers through
+the lexically-bound variable `buffer'."
+ `(let ((buffer (find-file-noselect bookmark-tests-example-file)))
+ (unwind-protect
+ (with-bookmark-test-list
+ ,@body)
+ (kill-buffer buffer))))
+
(ert-deftest bookmark-tests-all-names ()
(with-bookmark-test
(should (equal (bookmark-all-names) '("name")))))
@@ -94,6 +151,30 @@ the lexically-bound variable `buffer'."
(with-bookmark-test
(should (equal (bookmark-get-bookmark-record "name") (cdr bookmark-tests-bookmark)))))
+(ert-deftest bookmark-tests-all-names-list ()
+ (with-bookmark-test-list
+ (should (equal (bookmark-all-names) '("name-0"
+ "name-1"
+ "name-2")))))
+
+(ert-deftest bookmark-tests-get-bookmark-list ()
+ (with-bookmark-test-list
+ (should (equal (bookmark-get-bookmark "name-0")
+ bookmark-tests-bookmark-list-0))
+ (should (equal (bookmark-get-bookmark "name-1")
+ bookmark-tests-bookmark-list-1))
+ (should (equal (bookmark-get-bookmark "name-2")
+ bookmark-tests-bookmark-list-2))))
+
+(ert-deftest bookmark-tests-get-bookmark-record-list ()
+ (with-bookmark-test-list
+ (should (equal (bookmark-get-bookmark-record "name-0")
+ (cdr bookmark-tests-bookmark-list-0)))
+ (should (equal (bookmark-get-bookmark-record "name-1")
+ (cdr bookmark-tests-bookmark-list-1)))
+ (should (equal (bookmark-get-bookmark-record "name-2")
+ (cdr bookmark-tests-bookmark-list-2)))))
+
(ert-deftest bookmark-tests-record-getters-and-setters-new ()
(with-temp-buffer
(let* ((buffer-file-name "test")
@@ -129,6 +210,19 @@ the lexically-bound variable `buffer'."
;; calling twice gives same record
(should (equal (bookmark-make-record) record))))))
+(ert-deftest bookmark-tests-make-record-list ()
+ (with-bookmark-test-file-list
+ (let* ((record `("example.txt" (filename . ,bookmark-tests-example-file)
+ (front-context-string . "is text file is ")
+ (rear-context-string)
+ (position . 3)
+ (defaults "example.txt"))))
+ (with-current-buffer buffer
+ (goto-char 3)
+ (should (equal (bookmark-make-record) record))
+ ;; calling twice gives same record
+ (should (equal (bookmark-make-record) record))))))
+
(ert-deftest bookmark-tests-make-record-function ()
(with-bookmark-test
(let ((buffer-file-name "test"))
@@ -218,7 +312,7 @@ the lexically-bound variable `buffer'."
(with-bookmark-test
(should-error (bookmark-insert-annotation "a missing bookmark"))
(bookmark-insert-annotation "name")
- (should (equal (buffer-string) (bookmark-default-annotation-text "name"))))
+ (should (string-match "Type the annotation" (buffer-string))))
(with-bookmark-test
(bookmark-set-annotation "name" "some stuff")
(bookmark-insert-annotation "name")
@@ -266,6 +360,11 @@ the lexically-bound variable `buffer'."
(bookmark-delete "name")
(should (equal bookmark-alist nil))))
+(ert-deftest bookmark-tests-delete-all ()
+ (with-bookmark-test-list
+ (bookmark-delete-all t)
+ (should (equal bookmark-alist nil))))
+
(defmacro with-bookmark-test-save-load (&rest body)
"Create environment for testing bookmark.el and evaluate BODY.
Same as `with-bookmark-test' but also sets a temporary
@@ -339,28 +438,209 @@ testing `bookmark-bmenu-list'."
,@body)
(kill-buffer bookmark-bmenu-buffer)))))
-(ert-deftest bookmark-bmenu.enu-edit-annotation/show-annotation ()
+(defmacro with-bookmark-bmenu-test-list (&rest body)
+ "Create environment for testing `bookmark-bmenu-list' and evaluate BODY.
+Same as `with-bookmark-test-list' but with additions suitable for
+testing `bookmark-bmenu-list'."
+ `(with-bookmark-test-list
+ (let ((bookmark-bmenu-buffer "*Bookmark List - Testing*"))
+ (unwind-protect
+ (save-window-excursion
+ (bookmark-bmenu-list)
+ ,@body)
+ (kill-buffer bookmark-bmenu-buffer)))))
+
+(ert-deftest bookmark-test-bmenu-edit-annotation/show-annotation ()
(with-bookmark-bmenu-test
(bookmark-set-annotation "name" "foo")
(bookmark-bmenu-edit-annotation)
(should (string-match "foo" (buffer-string)))
(kill-buffer (current-buffer))))
-(ert-deftest bookmark-bmenu-send-edited-annotation ()
+(ert-deftest bookmark-test-bmenu-send-edited-annotation ()
(with-bookmark-bmenu-test
(bookmark-bmenu-edit-annotation)
(insert "foo")
(bookmark-send-edited-annotation)
(should (equal (bookmark-get-annotation "name") "foo"))))
-(ert-deftest bookmark-bmenu-send-edited-annotation/restore-focus ()
+(ert-deftest bookmark-test-bmenu-send-edited-annotation/restore-focus ()
"Test for https://debbugs.gnu.org/20150 ."
(with-bookmark-bmenu-test
(bookmark-bmenu-edit-annotation)
(insert "foo")
(bookmark-send-edited-annotation)
(should (equal (buffer-name (current-buffer)) bookmark-bmenu-buffer))
+ (beginning-of-line)
+ (forward-char 4)
(should (looking-at "name"))))
+(ert-deftest bookmark-test-bmenu-toggle-filenames ()
+ (with-bookmark-bmenu-test
+ (should (re-search-forward "/some/file" nil t))
+ (bookmark-bmenu-toggle-filenames)
+ (goto-char (point-min))
+ (should-not (re-search-forward "/some/file" nil t))))
+
+(ert-deftest bookmark-test-bmenu-toggle-filenames/show ()
+ (with-bookmark-bmenu-test
+ (bookmark-bmenu-toggle-filenames t)
+ (should (re-search-forward "/some/file"))))
+
+(ert-deftest bookmark-test-bmenu-show-filenames ()
+ (with-bookmark-bmenu-test
+ (bookmark-bmenu-show-filenames)
+ (should (re-search-forward "/some/file"))))
+
+(ert-deftest bookmark-test-bmenu-hide-filenames ()
+ (with-bookmark-bmenu-test
+ (bookmark-bmenu-hide-filenames)
+ (goto-char (point-min))
+ (should-not (re-search-forward "/some/file" nil t))))
+
+(ert-deftest bookmark-test-bmenu-bookmark ()
+ (with-bookmark-bmenu-test
+ (should (equal (bookmark-bmenu-bookmark) "name"))))
+
+(ert-deftest bookmark-test-bmenu-mark ()
+ (with-bookmark-bmenu-test
+ (bookmark-bmenu-mark)
+ (forward-line -1)
+ (beginning-of-line)
+ (should (looking-at "^>"))))
+
+(ert-deftest bookmark-test-bmenu-any-marks ()
+ (with-bookmark-bmenu-test
+ (bookmark-bmenu-mark)
+ (beginning-of-line)
+ (should (bookmark-bmenu-any-marks))))
+
+(ert-deftest bookmark-test-bmenu-mark-all ()
+ (with-bookmark-bmenu-test-list
+ (let ((here (point-max)))
+ ;; Expect to not move the point
+ (goto-char here)
+ (bookmark-bmenu-mark-all)
+ (should (equal here (point)))
+ ;; Verify that all bookmarks are marked
+ (goto-char (point-min))
+ (bookmark-bmenu-ensure-position)
+ (should (looking-at "^> "))
+ (should (equal bookmark-tests-bookmark-list-0
+ (bookmark-get-bookmark (bookmark-bmenu-bookmark))))
+ (forward-line 1)
+ (should (looking-at "^> "))
+ (should (equal bookmark-tests-bookmark-list-1
+ (bookmark-get-bookmark (bookmark-bmenu-bookmark))))
+ (forward-line 1)
+ (should (looking-at "^> "))
+ (should (equal bookmark-tests-bookmark-list-2
+ (bookmark-get-bookmark (bookmark-bmenu-bookmark)))))))
+
+(ert-deftest bookmark-test-bmenu-any-marks-list ()
+ (with-bookmark-bmenu-test-list
+ ;; Mark just the second item
+ (goto-char (point-min))
+ (bookmark-bmenu-ensure-position)
+ (forward-line 1)
+ (bookmark-bmenu-mark)
+ ;; Verify that only the second item is marked
+ (goto-char (point-min))
+ (bookmark-bmenu-ensure-position)
+ (should (looking-at "^ "))
+ (should (equal bookmark-tests-bookmark-list-0
+ (bookmark-get-bookmark (bookmark-bmenu-bookmark))))
+ (forward-line 1)
+ (should (looking-at "^> "))
+ (should (equal bookmark-tests-bookmark-list-1
+ (bookmark-get-bookmark (bookmark-bmenu-bookmark))))
+ (forward-line 1)
+ (should (looking-at "^ "))
+ (should (equal bookmark-tests-bookmark-list-2
+ (bookmark-get-bookmark (bookmark-bmenu-bookmark))))
+ ;; There should be at least one mark
+ (should (bookmark-bmenu-any-marks))))
+
+(ert-deftest bookmark-test-bmenu-unmark ()
+ (with-bookmark-bmenu-test
+ (bookmark-bmenu-mark)
+ (goto-char (point-min))
+ (bookmark-bmenu-unmark)
+ (forward-line -1)
+ (beginning-of-line)
+ (should (looking-at "^ "))))
+
+(ert-deftest bookmark-test-bmenu-unmark-all ()
+ (with-bookmark-bmenu-test-list
+ (bookmark-bmenu-mark-all)
+ (let ((here (point-max)))
+ ;; Expect to not move the point
+ (goto-char here)
+ (bookmark-bmenu-unmark-all)
+ (should (equal here (point)))
+ ;; Verify that all bookmarks are unmarked
+ (goto-char (point-min))
+ (bookmark-bmenu-ensure-position)
+ (should (looking-at "^ "))
+ (should (equal bookmark-tests-bookmark-list-0
+ (bookmark-get-bookmark (bookmark-bmenu-bookmark))))
+ (forward-line 1)
+ (should (looking-at "^ "))
+ (should (equal bookmark-tests-bookmark-list-1
+ (bookmark-get-bookmark (bookmark-bmenu-bookmark))))
+ (forward-line 1)
+ (should (looking-at "^ "))
+ (should (equal bookmark-tests-bookmark-list-2
+ (bookmark-get-bookmark (bookmark-bmenu-bookmark)))))))
+
+(ert-deftest bookmark-test-bmenu-delete ()
+ (with-bookmark-bmenu-test
+ (bookmark-bmenu-delete)
+ (bookmark-bmenu-execute-deletions)
+ (should (equal (length bookmark-alist) 0))))
+
+(ert-deftest bookmark-test-bmenu-delete-all ()
+ (with-bookmark-bmenu-test-list
+ ;; Verify that unmarked bookmarks aren't deleted
+ (bookmark-bmenu-execute-deletions)
+ (should-not (eq bookmark-alist nil))
+ (let ((here (point-max)))
+ ;; Expect to not move the point
+ (goto-char here)
+ (bookmark-bmenu-delete-all)
+ (should (equal here (point)))
+ ;; Verify that all bookmarks are marked for deletion
+ (goto-char (point-min))
+ (bookmark-bmenu-ensure-position)
+ (should (looking-at "^D "))
+ (should (equal bookmark-tests-bookmark-list-0
+ (bookmark-get-bookmark (bookmark-bmenu-bookmark))))
+ (forward-line 1)
+ (should (looking-at "^D "))
+ (should (equal bookmark-tests-bookmark-list-1
+ (bookmark-get-bookmark (bookmark-bmenu-bookmark))))
+ (forward-line 1)
+ (should (looking-at "^D "))
+ (should (equal bookmark-tests-bookmark-list-2
+ (bookmark-get-bookmark (bookmark-bmenu-bookmark))))
+ ;; Verify that all bookmarks are deleted
+ (bookmark-bmenu-execute-deletions)
+ (should (eq bookmark-alist nil)))))
+
+(ert-deftest bookmark-test-bmenu-locate ()
+ (let (msg)
+ (cl-letf (((symbol-function 'message)
+ (lambda (&rest args)
+ (setq msg (apply #'format args)))))
+ (with-bookmark-bmenu-test
+ (bookmark-bmenu-locate)
+ (should (equal msg "/some/file"))))))
+
+(ert-deftest bookmark-test-bmenu-filter-alist-by-regexp ()
+ (with-bookmark-bmenu-test
+ (bookmark-bmenu-filter-alist-by-regexp regexp-unmatchable)
+ (goto-char (point-min))
+ (should (looking-at "^$"))))
+
(provide 'bookmark-tests)
;;; bookmark-tests.el ends here
diff --git a/test/lisp/button-tests.el b/test/lisp/button-tests.el
index e36f6c2b782..e0944afa344 100644
--- a/test/lisp/button-tests.el
+++ b/test/lisp/button-tests.el
@@ -21,6 +21,12 @@
(require 'ert)
+(defvar button-tests--map
+ (let ((map (make-sparse-keymap)))
+ (define-key map "x" #'ignore)
+ map)
+ "Keymap for testing command substitution.")
+
(ert-deftest button-at ()
"Test `button-at' behavior."
(with-temp-buffer
@@ -41,11 +47,13 @@
"Test `button--help-echo' with strings."
(with-temp-buffer
;; Text property buttons.
- (let ((button (insert-text-button "text" 'help-echo "text help")))
- (should (equal (button--help-echo button) "text help")))
+ (let ((button (insert-text-button
+ "text" 'help-echo "text: \\<button-tests--map>\\[ignore]")))
+ (should (equal (button--help-echo button) "text: x")))
;; Overlay buttons.
- (let ((button (insert-button "overlay" 'help-echo "overlay help")))
- (should (equal (button--help-echo button) "overlay help")))))
+ (let ((button (insert-button "overlay" 'help-echo
+ "overlay: \\<button-tests--map>\\[ignore]")))
+ (should (equal (button--help-echo button) "overlay: x")))))
(ert-deftest button--help-echo-form ()
"Test `button--help-echo' with forms."
@@ -55,16 +63,17 @@
(form `(funcall (let ((,help "lexical form"))
(lambda () ,help))))
(button (insert-text-button "text" 'help-echo form)))
- (set help "dynamic form")
- (should (equal (button--help-echo button) "dynamic form")))
+ (set help "dynamic: \\<button-tests--map>\\[ignore]")
+ (should (equal (button--help-echo button) "dynamic: x")))
;; Test overlay buttons with lexical scoping.
(setq lexical-binding t)
(let* ((help (make-symbol "help"))
- (form `(funcall (let ((,help "lexical form"))
- (lambda () ,help))))
+ (form `(funcall
+ (let ((,help "lexical: \\<button-tests--map>\\[ignore]"))
+ (lambda () ,help))))
(button (insert-button "overlay" 'help-echo form)))
(set help "dynamic form")
- (should (equal (button--help-echo button) "lexical form")))))
+ (should (equal (button--help-echo button) "lexical: x")))))
(ert-deftest button--help-echo-function ()
"Test `button--help-echo' with functions."
@@ -77,9 +86,9 @@
(should (eq win owin))
(should (eq obj obuf))
(should (= pos opos))
- "text function"))
+ "text: \\<button-tests--map>\\[ignore]"))
(button (insert-text-button "text" 'help-echo help)))
- (should (equal (button--help-echo button) "text function"))
+ (should (equal (button--help-echo button) "text: x"))
;; Overlay buttons.
(setq help (lambda (win obj pos)
(should (eq win owin))
@@ -88,9 +97,9 @@
(should (eq (overlay-buffer obj) obuf))
(should (= (overlay-start obj) opos))
(should (= pos opos))
- "overlay function"))
+ "overlay: \\<button-tests--map>\\[ignore]"))
(setq opos (point))
(setq button (insert-button "overlay" 'help-echo help))
- (should (equal (button--help-echo button) "overlay function")))))
+ (should (equal (button--help-echo button) "overlay: x")))))
;;; button-tests.el ends here
diff --git a/test/lisp/calc/calc-tests.el b/test/lisp/calc/calc-tests.el
index f06c41df71b..bdcf78e020a 100644
--- a/test/lisp/calc/calc-tests.el
+++ b/test/lisp/calc/calc-tests.el
@@ -63,29 +63,26 @@ An existing calc stack is reused, otherwise a new one is created."
(calc-top-n 1))
(calc-pop 0)))
-;; (ert-deftest test-math-bignum ()
-;; ;; bug#17556
-;; (let ((n (math-bignum most-negative-fixnum)))
-;; (should (math-negp n))
-;; (should (cl-notany #'cl-minusp (cdr n)))))
-
-(ert-deftest test-calc-remove-units ()
+(ert-deftest calc-remove-units ()
(should (calc-tests-equal (calc-tests-simple #'calc-remove-units "-1 m") -1)))
-(ert-deftest test-calc-extract-units ()
- (should (calc-tests-equal (calc-tests-simple #'calc-extract-units "-1 m")
- '(var m var-m)))
- (should (calc-tests-equal (calc-tests-simple #'calc-extract-units "-1 m*cm")
- '(* (float 1 -2) (^ (var m var-m) 2)))))
-
-(ert-deftest test-calc-convert-units ()
- ;; Used to ask for `(The expression is unitless when simplified) Old Units: '.
- (should (calc-tests-equal (calc-tests-simple #'calc-convert-units "-1 m" nil "cm")
- '(* -100 (var cm var-cm))))
- ;; Gave wrong result.
- (should (calc-tests-equal (calc-tests-simple #'calc-convert-units "-1 m"
- (math-read-expr "1m") "cm")
- '(* -100 (var cm var-cm)))))
+(ert-deftest calc-extract-units ()
+ (let ((calc-display-working-message nil))
+ (should (calc-tests-equal (calc-tests-simple #'calc-extract-units "-1 m")
+ '(var m var-m)))
+ (should (calc-tests-equal (calc-tests-simple #'calc-extract-units "-1 m*cm")
+ '(* (float 1 -2) (^ (var m var-m) 2))))))
+
+(ert-deftest calc-convert-units ()
+ (let ((calc-display-working-message nil))
+ ;; Used to ask `(The expression is unitless when simplified) Old Units: '.
+ (should (calc-tests-equal (calc-tests-simple #'calc-convert-units "-1 m"
+ nil "cm")
+ '(* -100 (var cm var-cm))))
+ ;; Gave wrong result.
+ (should (calc-tests-equal (calc-tests-simple #'calc-convert-units "-1 m"
+ (math-read-expr "1m") "cm")
+ '(* -100 (var cm var-cm))))))
(ert-deftest calc-imaginary-i ()
"Test `math-imaginary-i' for non-special-const values."
@@ -94,7 +91,7 @@ An existing calc stack is reused, otherwise a new one is created."
(let ((var-i (calcFunc-sqrt -1)))
(should (math-imaginary-i))))
-(ert-deftest test-calc-23889 ()
+(ert-deftest calc-bug-23889 ()
"Test for https://debbugs.gnu.org/23889 and 25652."
(skip-unless t) ;; (>= math-bignum-digit-length 9))
(dolist (mode '(deg rad))
@@ -139,7 +136,7 @@ An existing calc stack is reused, otherwise a new one is created."
(nth 1 (calcFunc-cos 1)))
0 4))))))
-(ert-deftest calc-test-trig ()
+(ert-deftest calc-trig ()
"Trigonometric simplification; bug#33052."
(let ((calc-angle-mode 'rad))
(let ((calc-symbolic-mode t))
@@ -169,7 +166,7 @@ An existing calc stack is reused, otherwise a new one is created."
(should (equal (math-simplify '(calcFunc-cot (/ (var pi var-pi) 3)))
'(calcFunc-cot (/ (var pi var-pi) 3)))))))
-(ert-deftest calc-test-format-radix ()
+(ert-deftest calc-format-radix ()
"Test integer formatting (bug#36689)."
(let ((calc-group-digits nil))
(let ((calc-number-radix 10))
@@ -194,7 +191,7 @@ An existing calc stack is reused, otherwise a new one is created."
(let ((calc-number-radix 36))
(should (equal (math-format-number 12345678901) "36#5,O6A,QT1")))))
-(ert-deftest calc-test-calendar ()
+(ert-deftest calc-calendar ()
"Test calendar conversions (bug#36822)."
(should (equal (calcFunc-julian (math-parse-date "2019-07-27")) 2458692))
(should (equal (math-parse-date "2019-07-27") '(date 737267)))
@@ -216,7 +213,7 @@ An existing calc stack is reused, otherwise a new one is created."
(should (equal (math-absolute-from-julian-dt -101 3 1) -36832))
(should (equal (math-absolute-from-julian-dt -4713 1 1) -1721425)))
-(ert-deftest calc-test-solve-linear-system ()
+(ert-deftest calc-solve-linear-system ()
"Test linear system solving (bug#35374)."
;; x + y = 3
;; 2x - 3y = -4
@@ -345,6 +342,371 @@ An existing calc stack is reused, otherwise a new one is created."
(should (Math-num-integerp '(float 1 0)))
(should-not (Math-num-integerp nil)))
+(ert-deftest calc-matrix-determinant ()
+ (let ((calc-display-working-message nil))
+ (should (equal (calcFunc-det '(vec (vec 3)))
+ 3))
+ (should (equal (calcFunc-det '(vec (vec 2 3) (vec 6 7)))
+ -4))
+ (should (equal (calcFunc-det '(vec (vec 1 2 3) (vec 4 5 7) (vec 9 6 2)))
+ 15))
+ (should (equal (calcFunc-det '(vec (vec 0 5 7 3)
+ (vec 0 0 2 0)
+ (vec 1 2 3 4)
+ (vec 0 0 0 3)))
+ 30))
+ (should (equal (calcFunc-det '(vec (vec (var a var-a))))
+ '(var a var-a)))
+ (should (equal (calcFunc-det '(vec (vec 2 (var a var-a))
+ (vec 7 (var a var-a))))
+ '(* -5 (var a var-a))))
+ (should (equal (calcFunc-det '(vec (vec 1 0 0 0)
+ (vec 0 1 0 0)
+ (vec 0 0 0 1)
+ (vec 0 0 (var a var-a) 0)))
+ '(neg (var a var-a))))))
+
+(ert-deftest calc-gcd ()
+ (should (equal (calcFunc-gcd 3 4) 1))
+ (should (equal (calcFunc-gcd 12 15) 3))
+ (should (equal (calcFunc-gcd -12 15) 3))
+ (should (equal (calcFunc-gcd 12 -15) 3))
+ (should (equal (calcFunc-gcd -12 -15) 3))
+ (should (equal (calcFunc-gcd 0 5) 5))
+ (should (equal (calcFunc-gcd 5 0) 5))
+ (should (equal (calcFunc-gcd 0 -5) 5))
+ (should (equal (calcFunc-gcd -5 0) 5))
+ (should (equal (calcFunc-gcd 0 0) 0))
+ (should (equal (calcFunc-gcd 0 '(var x var-x))
+ '(calcFunc-abs (var x var-x))))
+ (should (equal (calcFunc-gcd '(var x var-x) 0)
+ '(calcFunc-abs (var x var-x)))))
+
+(ert-deftest calc-sum-gcd ()
+ ;; sum(gcd(0,n),n,-1,-1)
+ (should (equal (math-simplify '(calcFunc-sum (calcFunc-gcd 0 (var n var-n))
+ (var n var-n) -1 -1))
+ 1))
+ ;; sum(sum(gcd(n,k),k,-1,1),n,-1,1)
+ (should (equal (math-simplify
+ '(calcFunc-sum
+ (calcFunc-sum (calcFunc-gcd (var n var-n) (var k var-k))
+ (var k var-k) -1 1)
+ (var n var-n) -1 1))
+ 8)))
+
+(defun calc-tests--fac (n)
+ (apply #'* (number-sequence 1 n)))
+
+(defun calc-tests--choose (n k)
+ "N choose K, reference implementation."
+ (cond
+ ((and (integerp n) (integerp k))
+ (if (<= 0 n)
+ (if (<= 0 k n)
+ (/ (calc-tests--fac n)
+ (* (calc-tests--fac k) (calc-tests--fac (- n k))))
+ 0) ; 0≤n<k
+ ;; n<0, n and k integers: use extension from M. J. Kronenburg
+ (cond
+ ((<= 0 k)
+ (* (expt -1 k)
+ (calc-tests--choose (+ (- n) k -1) k)))
+ ((<= k n)
+ (* (expt -1 (- n k))
+ (calc-tests--choose (+ (- k) -1) (- n k))))
+ (t ; n<k<0
+ 0))))
+ ((natnump k)
+ ;; Generalisation for any n, integral k≥0: use falling product
+ (/ (apply '* (number-sequence n (- n (1- k)) -1))
+ (calc-tests--fac k)))
+ (t (error "case not covered"))))
+
+(defun calc-tests--calc-to-number (x)
+ "Convert a Calc object to a Lisp number."
+ (pcase x
+ ((pred numberp) x)
+ (`(frac ,p ,q) (/ (float p) q))
+ (`(float ,m ,e) (* m (expt 10 e)))
+ (_ (error "calc object not converted: %S" x))))
+
+(ert-deftest calc-choose ()
+ "Test computation of binomial coefficients (bug#16999)."
+ (let ((calc-display-working-message nil))
+ ;; Integral arguments
+ (dolist (n (number-sequence -6 6))
+ (dolist (k (number-sequence -6 6))
+ (should (equal (calcFunc-choose n k)
+ (calc-tests--choose n k)))))
+
+ ;; Fractional n, natural k
+ (should (equal (calc-tests--calc-to-number
+ (calcFunc-choose '(frac 15 2) 3))
+ (calc-tests--choose 7.5 3)))
+
+ (should (equal (calc-tests--calc-to-number
+ (calcFunc-choose '(frac 1 2) 2))
+ (calc-tests--choose 0.5 2)))
+
+ (should (equal (calc-tests--calc-to-number
+ (calcFunc-choose '(frac -15 2) 3))
+ (calc-tests--choose -7.5 3)))))
+
+(ert-deftest calc-business-days ()
+ (cl-flet ((m (s) (math-parse-date s))
+ (b+ (a b) (calcFunc-badd a b))
+ (b- (a b) (calcFunc-bsub a b)))
+ ;; Sanity check.
+ (should (equal (m "2020-09-07") '(date 737675)))
+
+ ;; Test with standard business days (Mon-Fri):
+ (should (equal (b+ (m "2020-09-07") 1) (m "2020-09-08"))) ; Mon->Tue
+ (should (equal (b+ (m "2020-09-08") 1) (m "2020-09-09"))) ; Tue->Wed
+ (should (equal (b+ (m "2020-09-09") 1) (m "2020-09-10"))) ; Wed->Thu
+ (should (equal (b+ (m "2020-09-10") 1) (m "2020-09-11"))) ; Thu->Fri
+ (should (equal (b+ (m "2020-09-11") 1) (m "2020-09-14"))) ; Fri->Mon
+
+ (should (equal (b+ (m "2020-09-07") 4) (m "2020-09-11"))) ; Mon->Fri
+ (should (equal (b+ (m "2020-09-07") 6) (m "2020-09-15"))) ; Mon->Tue
+
+ (should (equal (b+ (m "2020-09-12") 1) (m "2020-09-14"))) ; Sat->Mon
+ (should (equal (b+ (m "2020-09-13") 1) (m "2020-09-14"))) ; Sun->Mon
+
+ (should (equal (b- (m "2020-09-11") 1) (m "2020-09-10"))) ; Fri->Thu
+ (should (equal (b- (m "2020-09-10") 1) (m "2020-09-09"))) ; Thu->Wed
+ (should (equal (b- (m "2020-09-09") 1) (m "2020-09-08"))) ; Wed->Tue
+ (should (equal (b- (m "2020-09-08") 1) (m "2020-09-07"))) ; Tue->Mon
+ (should (equal (b- (m "2020-09-07") 1) (m "2020-09-04"))) ; Mon->Fri
+
+ (should (equal (b- (m "2020-09-11") 4) (m "2020-09-07"))) ; Fri->Mon
+ (should (equal (b- (m "2020-09-15") 6) (m "2020-09-07"))) ; Tue->Mon
+
+ (should (equal (b- (m "2020-09-12") 1) (m "2020-09-11"))) ; Sat->Fri
+ (should (equal (b- (m "2020-09-13") 1) (m "2020-09-11"))) ; Sun->Fri
+
+ ;; Stepping fractional days
+ (should (equal (b+ (m "2020-09-08 21:00") '(frac 1 2))
+ (m "2020-09-09 09:00")))
+ (should (equal (b+ (m "2020-09-11 21:00") '(frac 1 2))
+ (m "2020-09-14 09:00")))
+ (should (equal (b- (m "2020-09-08 21:00") '(frac 1 2))
+ (m "2020-09-08 09:00")))
+ (should (equal (b- (m "2020-09-14 06:00") '(frac 1 2))
+ (m "2020-09-11 18:00")))
+
+ ;; Test with a couple of extra days off:
+ (let ((var-Holidays (list 'vec
+ '(var sat var-sat) '(var sun var-sun)
+ (m "2020-09-09") (m "2020-09-11"))))
+
+ (should (equal (b+ (m "2020-09-07") 1) (m "2020-09-08"))) ; Mon->Tue
+ (should (equal (b+ (m "2020-09-08") 1) (m "2020-09-10"))) ; Tue->Thu
+ (should (equal (b+ (m "2020-09-10") 1) (m "2020-09-14"))) ; Thu->Mon
+ (should (equal (b+ (m "2020-09-14") 1) (m "2020-09-15"))) ; Mon->Tue
+ (should (equal (b+ (m "2020-09-15") 1) (m "2020-09-16"))) ; Tue->Wed
+
+ (should (equal (b- (m "2020-09-16") 1) (m "2020-09-15"))) ; Wed->Tue
+ (should (equal (b- (m "2020-09-15") 1) (m "2020-09-14"))) ; Tue->Mon
+ (should (equal (b- (m "2020-09-14") 1) (m "2020-09-10"))) ; Mon->Thu
+ (should (equal (b- (m "2020-09-10") 1) (m "2020-09-08"))) ; Thu->Tue
+ (should (equal (b- (m "2020-09-08") 1) (m "2020-09-07"))) ; Tue->Mon
+ )
+
+ ;; Test with odd non-business weekdays (Tue, Wed, Sat):
+ (let ((var-Holidays '(vec (var tue var-tue)
+ (var wed var-wed)
+ (var sat var-sat))))
+ (should (equal (b+ (m "2020-09-07") 1) (m "2020-09-10"))) ; Mon->Thu
+ (should (equal (b+ (m "2020-09-10") 1) (m "2020-09-11"))) ; Thu->Fri
+ (should (equal (b+ (m "2020-09-11") 1) (m "2020-09-13"))) ; Fri->Sun
+ (should (equal (b+ (m "2020-09-13") 1) (m "2020-09-14"))) ; Sun->Mon
+
+ (should (equal (b- (m "2020-09-14") 1) (m "2020-09-13"))) ; Mon->Sun
+ (should (equal (b- (m "2020-09-13") 1) (m "2020-09-11"))) ; Sun->Fri
+ (should (equal (b- (m "2020-09-11") 1) (m "2020-09-10"))) ; Fri->Thu
+ (should (equal (b- (m "2020-09-10") 1) (m "2020-09-07"))) ; Thu->Mon
+ )
+ ))
+
+(ert-deftest calc-unix-date ()
+ (let* ((d-1970-01-01 (math-parse-date "1970-01-01"))
+ (d-2020-09-07 (math-parse-date "2020-09-07"))
+ (d-1991-01-09-0600 (math-parse-date "1991-01-09 06:00")))
+ ;; calcFunc-unixtime (command "t U") converts a date value to Unix time,
+ ;; and a number to a date.
+ (should (equal d-1970-01-01 '(date 719163)))
+ (should (equal (calcFunc-unixtime d-1970-01-01 0) 0))
+ (should (equal (calc-tests--calc-to-number (cadr (calcFunc-unixtime 0 0)))
+ (cadr d-1970-01-01)))
+ (should (equal (calcFunc-unixtime d-2020-09-07 0)
+ (* (- (cadr d-2020-09-07)
+ (cadr d-1970-01-01))
+ 86400)))
+ (should (equal (calcFunc-unixtime d-1991-01-09-0600 0)
+ 663400800))
+ (should (equal (calc-tests--calc-to-number
+ (cadr (calcFunc-unixtime 663400800 0)))
+ 726841.25))
+
+ (let ((calc-date-format '(U)))
+ ;; Test parsing Unix time.
+ (should (equal (calc-tests--calc-to-number
+ (cadr (math-parse-date "0")))
+ 719163))
+ (should (equal (calc-tests--calc-to-number
+ (cadr (math-parse-date "469324800")))
+ (+ 719163 (/ 469324800 86400))))
+ (should (equal (calc-tests--calc-to-number
+ (cadr (math-parse-date "663400800")))
+ 726841.25))
+
+ ;; Test formatting Unix time.
+ (should (equal (math-format-date d-1970-01-01) "0"))
+ (should (equal (math-format-date d-2020-09-07)
+ (number-to-string (* (- (cadr d-2020-09-07)
+ (cadr d-1970-01-01))
+ 86400))))
+ (should (equal (math-format-date d-1991-01-09-0600) "663400800")))))
+
+;; Reference implementations of bit operations:
+
+(defun calc-tests--clip (x w)
+ "Clip X to W bits, signed if W is negative, otherwise unsigned."
+ (cond ((zerop w) x)
+ ((> w 0) (logand x (- (ash 1 w) 1)))
+ (t (let ((y (calc-tests--clip x (- w)))
+ (msb (ash 1 (- (- w) 1))))
+ (- y (ash (logand y msb) 1))))))
+
+(defun calc-tests--not (x w)
+ "Bitwise complement of X, word size W."
+ (calc-tests--clip (lognot x) w))
+
+(defun calc-tests--and (x y w)
+ "Bitwise AND of X and W, word size W."
+ (calc-tests--clip (logand x y) w))
+
+(defun calc-tests--or (x y w)
+ "Bitwise OR of X and Y, word size W."
+ (calc-tests--clip (logior x y) w))
+
+(defun calc-tests--xor (x y w)
+ "Bitwise XOR of X and Y, word size W."
+ (calc-tests--clip (logxor x y) w))
+
+(defun calc-tests--diff (x y w)
+ "Bitwise AND of X and NOT Y, word size W."
+ (calc-tests--clip (logand x (lognot y)) w))
+
+(defun calc-tests--lsh (x n w)
+ "Logical shift left X by N steps, word size W."
+ (if (< n 0)
+ (calc-tests--rsh x (- n) w)
+ (calc-tests--clip (ash x n) w)))
+
+(defun calc-tests--rsh (x n w)
+ "Logical shift right X by N steps, word size W."
+ (if (< n 0)
+ (calc-tests--lsh x (- n) w)
+ ;; First zero-extend, then shift.
+ (calc-tests--clip
+ (ash (calc-tests--clip x (abs w)) (- n))
+ w)))
+
+(defun calc-tests--ash (x n w)
+ "Arithmetic shift left X by N steps, word size W."
+ (if (< n 0)
+ (calc-tests--rash x (- n) w)
+ (calc-tests--clip (ash x n) w)))
+
+(defun calc-tests--rash (x n w)
+ "Arithmetic shift right X by N steps, word size W."
+ (if (< n 0)
+ (calc-tests--ash x (- n) w)
+ ;; First sign-extend, then shift.
+ (calc-tests--clip
+ (ash (calc-tests--clip x (- (abs w))) (- n))
+ w)))
+
+(defun calc-tests--rot (x n w)
+ "Rotate X left by N steps, word size W."
+ (when (zerop w)
+ (error "Undefined"))
+ (let* ((aw (abs w))
+ (y (calc-tests--clip x aw))
+ (steps (mod n aw)))
+ (calc-tests--clip (logior (ash y steps) (ash y (- steps aw)))
+ w)))
+
+(ert-deftest calc-shift-binary ()
+ (dolist (w '(16 32 -16 -32 0))
+ (dolist (x '(0 1 #x1234 #x8000 #xabcd #xffff
+ #x12345678 #xabcdef12 #x80000000 #xffffffff
+ #x1234567890ab #x1234967890ab
+ -1 -14 #x-8000 #x-ffff #x-8001 #x-10000
+ #x-80000000 #x-ffffffff #x-80000001 #x-100000000))
+ (dolist (n '(0 1 4 16 32 -1 -4 -16 -32))
+ (should (equal (calcFunc-lsh x n w)
+ (calc-tests--lsh x n w)))
+ (should (equal (calcFunc-rsh x n w)
+ (calc-tests--rsh x n w)))
+ (should (equal (calcFunc-ash x n w)
+ (calc-tests--ash x n w)))
+ (should (equal (calcFunc-rash x n w)
+ (calc-tests--rash x n w)))
+ (unless (zerop w)
+ (should (equal (calcFunc-rot x n w)
+ (calc-tests--rot x n w)))))))
+ (should-error (calcFunc-rot 1 1 0)))
+
+(ert-deftest calc-bit-ops ()
+ (dolist (w '(16 32 -16 -32 0))
+ (dolist (x '(0 1 #x1234 #x8000 #xabcd #xffff
+ #x12345678 #xabcdef12 #x80000000 #xffffffff
+ #x1234567890ab #x1234967890ab
+ -1 -14 #x-8000 #x-ffff #x-8001 #x-10000
+ #x-80000000 #x-ffffffff #x-80000001 #x-100000000))
+ (should (equal (calcFunc-not x w)
+ (calc-tests--not x w)))
+
+ (dolist (n '(0 1 4 16 32 -1 -4 -16 -32))
+ (equal (calcFunc-clip x n)
+ (calc-tests--clip x n)))
+
+ (dolist (y '(0 1 #x1234 #x8000 #xabcd #xffff
+ #x12345678 #xabcdef12 #x80000000 #xffffffff
+ #x1234567890ab #x1234967890ab
+ -1 -14 #x-8000 #x-ffff #x-8001 #x-10000
+ #x-80000000 #x-ffffffff #x-80000001 #x-100000000))
+ (should (equal (calcFunc-and x y w)
+ (calc-tests--and x y w)))
+ (should (equal (calcFunc-or x y w)
+ (calc-tests--or x y w)))
+ (should (equal (calcFunc-xor x y w)
+ (calc-tests--xor x y w)))
+ (should (equal (calcFunc-diff x y w)
+ (calc-tests--diff x y w)))))))
+
+(ert-deftest calc-latex-input ()
+ ;; Check precedence of "/" in LaTeX input mode.
+ (should (equal (math-read-exprs "a+b/c*d")
+ '((+ (var a var-a) (/ (var b var-b)
+ (* (var c var-c) (var d var-d)))))))
+ (unwind-protect
+ (progn
+ (calc-set-language 'latex)
+ (should (equal (math-read-exprs "a+b/c*d")
+ '((+ (var a var-a) (/ (var b var-b)
+ (* (var c var-c) (var d var-d)))))))
+ (should (equal (math-read-exprs "a+b\\over c*d")
+ '((/ (+ (var a var-a) (var b var-b))
+ (* (var c var-c) (var d var-d))))))
+ (should (equal (math-read-exprs "a/b/c")
+ '((/ (/ (var a var-a) (var b var-b))
+ (var c var-c))))))
+ (calc-set-language nil)))
+
(provide 'calc-tests)
;;; calc-tests.el ends here
diff --git a/test/lisp/calendar/cal-julian-tests.el b/test/lisp/calendar/cal-julian-tests.el
new file mode 100644
index 00000000000..db3a4909fa4
--- /dev/null
+++ b/test/lisp/calendar/cal-julian-tests.el
@@ -0,0 +1,72 @@
+;;; cal-julian-tests.el --- tests for calendar/cal-julian.el -*- lexical-binding:t -*-
+
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+;; Author: Stefan Kangas <stefankangas@gmail.com>
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(require 'cal-julian)
+
+(ert-deftest cal-julian-test-to-absolute ()
+ (should (equal (calendar-gregorian-from-absolute
+ (calendar-julian-to-absolute
+ '(10 25 1917)))
+ '(11 7 1917))))
+
+(ert-deftest cal-julian-test-from-absolute ()
+ (should (equal (calendar-julian-from-absolute
+ (calendar-absolute-from-gregorian
+ '(11 7 1917)))
+ '(10 25 1917))))
+
+(ert-deftest cal-julian-test-date-string ()
+ (should (equal (let ((calendar-date-display-form calendar-iso-date-display-form))
+ (calendar-julian-date-string '(11 7 1917)))
+ "1917-10-25")))
+
+(defmacro with-cal-julian-test (&rest body)
+ `(save-window-excursion
+ (unwind-protect
+ (progn
+ (calendar)
+ ,@body)
+ (kill-buffer "*Calendar*"))))
+
+(ert-deftest cal-julian-test-goto-date ()
+ (with-cal-julian-test
+ (calendar-julian-goto-date '(10 25 1917))
+ (should (looking-at "7"))))
+
+(ert-deftest cal-julian-test-astro-to-and-from-absolute ()
+ (should (= (+ (calendar-astro-to-absolute 0.0)
+ (calendar-astro-from-absolute 0.0))
+ 0.0)))
+
+(ert-deftest cal-julian-calendar-astro-date-string ()
+ (should (equal (calendar-astro-date-string '(10 25 1917)) "2421527")))
+
+(ert-deftest calendar-astro-goto-day-number ()
+ (with-cal-julian-test
+ (calendar-astro-goto-day-number 2421527)
+ (backward-char)
+ (should (looking-at "25"))))
+
+(provide 'cal-julian-tests)
+;;; cal-julian-tests.el ends here
diff --git a/test/lisp/calendar/icalendar-resources/import-bug-11473.diary-european b/test/lisp/calendar/icalendar-resources/import-bug-11473.diary-european
new file mode 100644
index 00000000000..97348ae0498
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-bug-11473.diary-european
@@ -0,0 +1,10 @@
+&15/5/2012 15:00-15:30 Query
+ Desc:
+ Whassup?
+
+
+ Location: phone
+ Organizer: MAILTO:a.luser@foo.com
+ Status: CONFIRMED
+ Class: PUBLIC
+ UID: 040000008200E00074C5B7101A82E0080000000020FFAED0CFEFCC01000000000000000010000000575268034ECDB649A15349B1BF240F15
diff --git a/test/lisp/calendar/icalendar-resources/import-bug-11473.ics b/test/lisp/calendar/icalendar-resources/import-bug-11473.ics
new file mode 100644
index 00000000000..bc3a6c69fb7
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-bug-11473.ics
@@ -0,0 +1,54 @@
+BEGIN:VCALENDAR
+METHOD:REQUEST
+PRODID:Microsoft Exchange Server 2007
+VERSION:2.0
+BEGIN:VTIMEZONE
+TZID:(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna
+BEGIN:STANDARD
+DTSTART:16010101T030000
+TZOFFSETFROM:+0200
+TZOFFSETTO:+0100
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=10
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:16010101T020000
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0200
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=3
+END:DAYLIGHT
+END:VTIMEZONE
+BEGIN:VEVENT
+ORGANIZER;CN="A. Luser":MAILTO:a.luser@foo.com
+ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN="Luser, Oth
+ er":MAILTO:other.luser@foo.com
+DESCRIPTION;LANGUAGE=en-US:\nWhassup?\n\n
+SUMMARY;LANGUAGE=en-US:Query
+DTSTART;TZID="(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna"
+ :20120515T150000
+DTEND;TZID="(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna":2
+ 0120515T153000
+UID:040000008200E00074C5B7101A82E0080000000020FFAED0CFEFCC01000000000000000
+ 010000000575268034ECDB649A15349B1BF240F15
+RECURRENCE-ID;TZID="(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, V
+ ienna":20120515T170000
+CLASS:PUBLIC
+PRIORITY:5
+DTSTAMP:20120514T153645Z
+TRANSP:OPAQUE
+STATUS:CONFIRMED
+SEQUENCE:15
+LOCATION;LANGUAGE=en-US:phone
+X-MICROSOFT-CDO-APPT-SEQUENCE:15
+X-MICROSOFT-CDO-OWNERAPPTID:1907632092
+X-MICROSOFT-CDO-BUSYSTATUS:TENTATIVE
+X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY
+X-MICROSOFT-CDO-ALLDAYEVENT:FALSE
+X-MICROSOFT-CDO-IMPORTANCE:1
+X-MICROSOFT-CDO-INSTTYPE:3
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:REMINDER
+TRIGGER;RELATED=START:-PT15M
+END:VALARM
+END:VEVENT
+END:VCALENDAR \ No newline at end of file
diff --git a/test/lisp/calendar/icalendar-resources/import-bug-22092.diary-american b/test/lisp/calendar/icalendar-resources/import-bug-22092.diary-american
new file mode 100644
index 00000000000..392345fe0a2
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-bug-22092.diary-american
@@ -0,0 +1,6 @@
+&12/8/2014 18:30-22:55 Norwegian til Tromsoe-Langnes -
+ Desc: Fly med Norwegian, reservasjon. Fra Stavanger til Troms&#248; 8. des 2014 18:30, DY545Fly med Norwegian, reservasjon . Fra Stavanger til Troms&#248; 8. des 2014 21:00, DY390
+ Location: Stavanger-Sola
+ Organizer: noreply@norwegian.no
+ Class: PUBLIC
+ UID: RFCALITEM1
diff --git a/test/lisp/calendar/icalendar-resources/import-bug-22092.diary-european b/test/lisp/calendar/icalendar-resources/import-bug-22092.diary-european
new file mode 100644
index 00000000000..6a64cf6a8e9
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-bug-22092.diary-european
@@ -0,0 +1,6 @@
+&8/12/2014 18:30-22:55 Norwegian til Tromsoe-Langnes -
+ Desc: Fly med Norwegian, reservasjon. Fra Stavanger til Troms&#248; 8. des 2014 18:30, DY545Fly med Norwegian, reservasjon . Fra Stavanger til Troms&#248; 8. des 2014 21:00, DY390
+ Location: Stavanger-Sola
+ Organizer: noreply@norwegian.no
+ Class: PUBLIC
+ UID: RFCALITEM1
diff --git a/test/lisp/calendar/icalendar-resources/import-bug-22092.diary-iso b/test/lisp/calendar/icalendar-resources/import-bug-22092.diary-iso
new file mode 100644
index 00000000000..e0fadbf94dc
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-bug-22092.diary-iso
@@ -0,0 +1,6 @@
+&2014/12/8 18:30-22:55 Norwegian til Tromsoe-Langnes -
+ Desc: Fly med Norwegian, reservasjon. Fra Stavanger til Troms&#248; 8. des 2014 18:30, DY545Fly med Norwegian, reservasjon . Fra Stavanger til Troms&#248; 8. des 2014 21:00, DY390
+ Location: Stavanger-Sola
+ Organizer: noreply@norwegian.no
+ Class: PUBLIC
+ UID: RFCALITEM1
diff --git a/test/lisp/calendar/icalendar-resources/import-bug-22092.ics b/test/lisp/calendar/icalendar-resources/import-bug-22092.ics
new file mode 100644
index 00000000000..4a4c679da9c
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-bug-22092.ics
@@ -0,0 +1,30 @@
+BEGIN:VCALENDAR
+PRODID:-//www.norwegian.no//iCalendar MIMEDIR//EN
+VERSION:2.0
+METHOD:REQUEST
+BEGIN:VEVENT
+UID:RFCALITEM1
+SEQUENCE:1512040950
+DTSTAMP:20141204T095043Z
+ORGANIZER:noreply@norwegian.no
+DTSTART:20141208T173000Z
+
+DTEND:20141208T215500Z
+
+LOCATION:Stavanger-Sola
+
+DESCRIPTION:Fly med Norwegian, reservasjon. Fra Stavanger til Troms&#248; 8. des 2014 18:30, DY545Fly med Norwegian, reservasjon . Fra Stavanger til Troms&#248; 8. des 2014 21:00, DY390
+
+X-ALT-DESC;FMTTYPE=text/html:<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"><html><head><META NAME="Generator" CONTENT="MS Exchange Server version 08.00.0681.000"><title></title></head><body><b><font face="Calibri" size="3">Reisereferanse</p></body></html>
+SUMMARY:Norwegian til Tromsoe-Langnes -
+
+CATEGORIES:Appointment
+
+
+PRIORITY:5
+
+CLASS:PUBLIC
+
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
diff --git a/test/lisp/calendar/icalendar-resources/import-bug-24199.diary-american b/test/lisp/calendar/icalendar-resources/import-bug-24199.diary-american
new file mode 100644
index 00000000000..b3308f1fcfa
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-bug-24199.diary-american
@@ -0,0 +1,5 @@
+&%%(and (not (diary-date 1 6 2016)) (not (diary-date 2 3 2016)) (not (diary-date 3 2 2016)) (not (diary-date 5 4 2016)) (not (diary-date 6 1 2016)) (diary-float t 3 1) (diary-block 12 2 2015 1 1 9999)) 12:46-16:00 Summary
+ Desc: Desc
+ Location: Loc
+ Class: DEFAULT
+ UID: 9188710a-08a7-4061-bae3-d4cf4972599a
diff --git a/test/lisp/calendar/icalendar-resources/import-bug-24199.diary-european b/test/lisp/calendar/icalendar-resources/import-bug-24199.diary-european
new file mode 100644
index 00000000000..acba714b527
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-bug-24199.diary-european
@@ -0,0 +1,5 @@
+&%%(and (not (diary-date 6 1 2016)) (not (diary-date 3 2 2016)) (not (diary-date 2 3 2016)) (not (diary-date 4 5 2016)) (not (diary-date 1 6 2016)) (diary-float t 3 1) (diary-block 2 12 2015 1 1 9999)) 12:46-16:00 Summary
+ Desc: Desc
+ Location: Loc
+ Class: DEFAULT
+ UID: 9188710a-08a7-4061-bae3-d4cf4972599a
diff --git a/test/lisp/calendar/icalendar-resources/import-bug-24199.diary-iso b/test/lisp/calendar/icalendar-resources/import-bug-24199.diary-iso
new file mode 100644
index 00000000000..2c18395dea8
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-bug-24199.diary-iso
@@ -0,0 +1,5 @@
+&%%(and (not (diary-date 2016 1 6)) (not (diary-date 2016 2 3)) (not (diary-date 2016 3 2)) (not (diary-date 2016 5 4)) (not (diary-date 2016 6 1)) (diary-float t 3 1) (diary-block 2015 12 2 9999 1 1)) 12:46-16:00 Summary
+ Desc: Desc
+ Location: Loc
+ Class: DEFAULT
+ UID: 9188710a-08a7-4061-bae3-d4cf4972599a
diff --git a/test/lisp/calendar/icalendar-resources/import-bug-24199.ics b/test/lisp/calendar/icalendar-resources/import-bug-24199.ics
new file mode 100644
index 00000000000..a307c2da3ca
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-bug-24199.ics
@@ -0,0 +1,25 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+SUMMARY:Summary
+DESCRIPTION:Desc
+LOCATION:Loc
+DTSTART:20151202T124600
+DTEND:20151202T160000
+RRULE:FREQ=MONTHLY;BYDAY=1WE;INTERVAL=1
+EXDATE:20160106T114600Z
+EXDATE:20160203T114600Z
+EXDATE:20160302T114600Z
+EXDATE:20160504T104600Z
+EXDATE:20160601T104600Z
+CLASS:DEFAULT
+TRANSP:OPAQUE
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER;VALUE=DURATION:-PT3H
+END:VALARM
+LAST-MODIFIED:20160805T191040Z
+UID:9188710a-08a7-4061-bae3-d4cf4972599a
+END:VEVENT
+END:VCALENDAR
diff --git a/test/lisp/calendar/icalendar-resources/import-bug-33277.diary-american b/test/lisp/calendar/icalendar-resources/import-bug-33277.diary-american
new file mode 100644
index 00000000000..c546fa9a97c
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-bug-33277.diary-american
@@ -0,0 +1 @@
+&11/5/2018 21:00 event with same start/end time
diff --git a/test/lisp/calendar/icalendar-resources/import-bug-33277.diary-european b/test/lisp/calendar/icalendar-resources/import-bug-33277.diary-european
new file mode 100644
index 00000000000..28e53960536
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-bug-33277.diary-european
@@ -0,0 +1 @@
+&5/11/2018 21:00 event with same start/end time
diff --git a/test/lisp/calendar/icalendar-resources/import-bug-33277.diary-iso b/test/lisp/calendar/icalendar-resources/import-bug-33277.diary-iso
new file mode 100644
index 00000000000..faa7aeafeb5
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-bug-33277.diary-iso
@@ -0,0 +1 @@
+&2018/11/5 21:00 event with same start/end time
diff --git a/test/lisp/calendar/icalendar-resources/import-bug-33277.ics b/test/lisp/calendar/icalendar-resources/import-bug-33277.ics
new file mode 100644
index 00000000000..a4122a28007
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-bug-33277.ics
@@ -0,0 +1,15 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+DTSTART:20181105T200000Z
+DTSTAMP:20181105T181652Z
+DESCRIPTION:
+LAST-MODIFIED:20181105T181646Z
+LOCATION:
+SEQUENCE:0
+SUMMARY:event with same start/end time
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
+
diff --git a/test/lisp/calendar/icalendar-resources/import-bug-6766.diary-american b/test/lisp/calendar/icalendar-resources/import-bug-6766.diary-american
new file mode 100644
index 00000000000..30deea9911a
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-bug-6766.diary-american
@@ -0,0 +1,7 @@
+&%%(and (memq (calendar-day-of-week date) '(1 3 4 5)) (diary-cyclic 1 4 21 2010)) 11:30-12:00 Scrum
+ Status: CONFIRMED
+ Class: PUBLIC
+ UID: 8814e3f9-7482-408f-996c-3bfe486a1262
+&%%(and (memq (calendar-day-of-week date) '(2 4)) (diary-cyclic 1 4 22 2010)) Tues + Thurs thinking
+ Class: PUBLIC
+ UID: 8814e3f9-7482-408f-996c-3bfe486a1263
diff --git a/test/lisp/calendar/icalendar-resources/import-bug-6766.diary-european b/test/lisp/calendar/icalendar-resources/import-bug-6766.diary-european
new file mode 100644
index 00000000000..ba16c02305a
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-bug-6766.diary-european
@@ -0,0 +1,7 @@
+&%%(and (memq (calendar-day-of-week date) '(1 3 4 5)) (diary-cyclic 1 21 4 2010)) 11:30-12:00 Scrum
+ Status: CONFIRMED
+ Class: PUBLIC
+ UID: 8814e3f9-7482-408f-996c-3bfe486a1262
+&%%(and (memq (calendar-day-of-week date) '(2 4)) (diary-cyclic 1 22 4 2010)) Tues + Thurs thinking
+ Class: PUBLIC
+ UID: 8814e3f9-7482-408f-996c-3bfe486a1263
diff --git a/test/lisp/calendar/icalendar-resources/import-bug-6766.diary-iso b/test/lisp/calendar/icalendar-resources/import-bug-6766.diary-iso
new file mode 100644
index 00000000000..7794e586f37
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-bug-6766.diary-iso
@@ -0,0 +1,7 @@
+&%%(and (memq (calendar-day-of-week date) '(1 3 4 5)) (diary-cyclic 1 2010 4 21)) 11:30-12:00 Scrum
+ Status: CONFIRMED
+ Class: PUBLIC
+ UID: 8814e3f9-7482-408f-996c-3bfe486a1262
+&%%(and (memq (calendar-day-of-week date) '(2 4)) (diary-cyclic 1 2010 4 22)) Tues + Thurs thinking
+ Class: PUBLIC
+ UID: 8814e3f9-7482-408f-996c-3bfe486a1263
diff --git a/test/lisp/calendar/icalendar-resources/import-bug-6766.ics b/test/lisp/calendar/icalendar-resources/import-bug-6766.ics
new file mode 100644
index 00000000000..451391be025
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-bug-6766.ics
@@ -0,0 +1,28 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+CLASS:PUBLIC
+DTEND;TZID=America/New_York:20100421T120000
+DTSTAMP:20100525T141214Z
+DTSTART;TZID=America/New_York:20100421T113000
+RRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,WE,TH,FR
+SEQUENCE:1
+STATUS:CONFIRMED
+SUMMARY:Scrum
+TRANSP:OPAQUE
+UID:8814e3f9-7482-408f-996c-3bfe486a1262
+END:VEVENT
+BEGIN:VEVENT
+CLASS:PUBLIC
+DTSTAMP:20100525T141214Z
+DTSTART;VALUE=DATE:20100422
+DTEND;VALUE=DATE:20100423
+RRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=TU,TH
+SEQUENCE:1
+SUMMARY:Tues + Thurs thinking
+TRANSP:OPAQUE
+UID:8814e3f9-7482-408f-996c-3bfe486a1263
+END:VEVENT
+END:VCALENDAR
+
diff --git a/test/lisp/calendar/icalendar-resources/import-duration-2.diary-american b/test/lisp/calendar/icalendar-resources/import-duration-2.diary-american
new file mode 100644
index 00000000000..56f41d6ad9e
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-duration-2.diary-american
@@ -0,0 +1,3 @@
+&%%(and (diary-cyclic 1 12 21 2001) (diary-block 12 21 2001 12 29 2001)) Urlaub
+ Class: PUBLIC
+ UID: 20041127T183329Z-18215-1001-4536-49109@andromeda
diff --git a/test/lisp/calendar/icalendar-resources/import-duration-2.diary-european b/test/lisp/calendar/icalendar-resources/import-duration-2.diary-european
new file mode 100644
index 00000000000..999102ab6b4
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-duration-2.diary-european
@@ -0,0 +1,3 @@
+&%%(and (diary-cyclic 1 21 12 2001) (diary-block 21 12 2001 29 12 2001)) Urlaub
+ Class: PUBLIC
+ UID: 20041127T183329Z-18215-1001-4536-49109@andromeda
diff --git a/test/lisp/calendar/icalendar-resources/import-duration-2.diary-iso b/test/lisp/calendar/icalendar-resources/import-duration-2.diary-iso
new file mode 100644
index 00000000000..393937e6cd9
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-duration-2.diary-iso
@@ -0,0 +1,3 @@
+&%%(and (diary-cyclic 1 2001 12 21) (diary-block 2001 12 21 2001 12 29)) Urlaub
+ Class: PUBLIC
+ UID: 20041127T183329Z-18215-1001-4536-49109@andromeda
diff --git a/test/lisp/calendar/icalendar-resources/import-duration-2.ics b/test/lisp/calendar/icalendar-resources/import-duration-2.ics
new file mode 100644
index 00000000000..eb8a03ba36f
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-duration-2.ics
@@ -0,0 +1,17 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+UID:20041127T183329Z-18215-1001-4536-49109@andromeda
+DTSTAMP:20041127T183315Z
+LAST-MODIFIED:20041127T183329
+SUMMARY:Urlaub
+DTSTART;VALUE=DATE:20011221
+DTEND;VALUE=DATE:20011221
+RRULE:FREQ=DAILY;UNTIL=20011229;INTERVAL=1;WKST=SU
+CLASS:PUBLIC
+SEQUENCE:1
+CREATED:20041127T183329
+END:VEVENT
+END:VCALENDAR
+
diff --git a/test/lisp/calendar/icalendar-resources/import-duration.diary-american b/test/lisp/calendar/icalendar-resources/import-duration.diary-american
new file mode 100644
index 00000000000..268736a8cd0
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-duration.diary-american
@@ -0,0 +1 @@
+&%%(and (diary-block 2 17 2005 2 23 2005)) duration
diff --git a/test/lisp/calendar/icalendar-resources/import-duration.diary-european b/test/lisp/calendar/icalendar-resources/import-duration.diary-european
new file mode 100644
index 00000000000..7d852ddcd3c
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-duration.diary-european
@@ -0,0 +1 @@
+&%%(and (diary-block 17 2 2005 23 2 2005)) duration
diff --git a/test/lisp/calendar/icalendar-resources/import-duration.diary-iso b/test/lisp/calendar/icalendar-resources/import-duration.diary-iso
new file mode 100644
index 00000000000..5d3a714284e
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-duration.diary-iso
@@ -0,0 +1 @@
+&%%(and (diary-block 2005 2 17 2005 2 23)) duration
diff --git a/test/lisp/calendar/icalendar-resources/import-duration.ics b/test/lisp/calendar/icalendar-resources/import-duration.ics
new file mode 100644
index 00000000000..67f5c73571b
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-duration.ics
@@ -0,0 +1,10 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20050217
+SUMMARY:duration
+DURATION:P7D
+END:VEVENT
+END:VCALENDAR
+
diff --git a/test/lisp/calendar/icalendar-resources/import-multiple-vcalendars.diary-american b/test/lisp/calendar/icalendar-resources/import-multiple-vcalendars.diary-american
new file mode 100644
index 00000000000..d1b1992a022
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-multiple-vcalendars.diary-american
@@ -0,0 +1,4 @@
+&7/23/2011 event-1
+&7/24/2011 event-2
+&7/25/2011 event-3a
+&7/25/2011 event-3b
diff --git a/test/lisp/calendar/icalendar-resources/import-multiple-vcalendars.diary-european b/test/lisp/calendar/icalendar-resources/import-multiple-vcalendars.diary-european
new file mode 100644
index 00000000000..f068354220c
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-multiple-vcalendars.diary-european
@@ -0,0 +1,4 @@
+&23/7/2011 event-1
+&24/7/2011 event-2
+&25/7/2011 event-3a
+&25/7/2011 event-3b
diff --git a/test/lisp/calendar/icalendar-resources/import-multiple-vcalendars.diary-iso b/test/lisp/calendar/icalendar-resources/import-multiple-vcalendars.diary-iso
new file mode 100644
index 00000000000..5685e4708a7
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-multiple-vcalendars.diary-iso
@@ -0,0 +1,4 @@
+&2011/7/23 event-1
+&2011/7/24 event-2
+&2011/7/25 event-3a
+&2011/7/25 event-3b
diff --git a/test/lisp/calendar/icalendar-resources/import-multiple-vcalendars.ics b/test/lisp/calendar/icalendar-resources/import-multiple-vcalendars.ics
new file mode 100644
index 00000000000..69a02c09b1b
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-multiple-vcalendars.ics
@@ -0,0 +1,21 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20110723
+SUMMARY:event-1
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20110724
+SUMMARY:event-2
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20110725
+SUMMARY:event-3a
+END:VEVENT
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20110725
+SUMMARY:event-3b
+END:VEVENT
+END:VCALENDAR
+
diff --git a/test/lisp/calendar/icalendar-resources/import-non-recurring-1.diary-american b/test/lisp/calendar/icalendar-resources/import-non-recurring-1.diary-american
new file mode 100644
index 00000000000..780e3a8ce64
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-non-recurring-1.diary-american
@@ -0,0 +1 @@
+&9/19/2003 09:00-11:30 non-recurring
diff --git a/test/lisp/calendar/icalendar-resources/import-non-recurring-1.diary-european b/test/lisp/calendar/icalendar-resources/import-non-recurring-1.diary-european
new file mode 100644
index 00000000000..7e0cd21b784
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-non-recurring-1.diary-european
@@ -0,0 +1 @@
+&19/9/2003 09:00-11:30 non-recurring
diff --git a/test/lisp/calendar/icalendar-resources/import-non-recurring-1.diary-iso b/test/lisp/calendar/icalendar-resources/import-non-recurring-1.diary-iso
new file mode 100644
index 00000000000..c7311286619
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-non-recurring-1.diary-iso
@@ -0,0 +1 @@
+&2003/9/19 09:00-11:30 non-recurring
diff --git a/test/lisp/calendar/icalendar-resources/import-non-recurring-1.ics b/test/lisp/calendar/icalendar-resources/import-non-recurring-1.ics
new file mode 100644
index 00000000000..cd471efc861
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-non-recurring-1.ics
@@ -0,0 +1,10 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+SUMMARY:non-recurring
+DTSTART;VALUE=DATE-TIME:20030919T090000
+DTEND;VALUE=DATE-TIME:20030919T113000
+END:VEVENT
+END:VCALENDAR
+
diff --git a/test/lisp/calendar/icalendar-resources/import-non-recurring-all-day.diary-american b/test/lisp/calendar/icalendar-resources/import-non-recurring-all-day.diary-american
new file mode 100644
index 00000000000..1d4bb6a337e
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-non-recurring-all-day.diary-american
@@ -0,0 +1 @@
+&9/19/2003 non-recurring allday
diff --git a/test/lisp/calendar/icalendar-resources/import-non-recurring-all-day.diary-european b/test/lisp/calendar/icalendar-resources/import-non-recurring-all-day.diary-european
new file mode 100644
index 00000000000..b56c7f4e17f
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-non-recurring-all-day.diary-european
@@ -0,0 +1 @@
+&19/9/2003 non-recurring allday
diff --git a/test/lisp/calendar/icalendar-resources/import-non-recurring-all-day.diary-iso b/test/lisp/calendar/icalendar-resources/import-non-recurring-all-day.diary-iso
new file mode 100644
index 00000000000..f1c70ab34c3
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-non-recurring-all-day.diary-iso
@@ -0,0 +1 @@
+&2003/9/19 non-recurring allday
diff --git a/test/lisp/calendar/icalendar-resources/import-non-recurring-all-day.ics b/test/lisp/calendar/icalendar-resources/import-non-recurring-all-day.ics
new file mode 100644
index 00000000000..4efa8ffa133
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-non-recurring-all-day.ics
@@ -0,0 +1,9 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+SUMMARY:non-recurring allday
+DTSTART;VALUE=DATE-TIME:20030919
+END:VEVENT
+END:VCALENDAR
+
diff --git a/test/lisp/calendar/icalendar-resources/import-non-recurring-another-example.diary-american b/test/lisp/calendar/icalendar-resources/import-non-recurring-another-example.diary-american
new file mode 100644
index 00000000000..2eb8c0ab686
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-non-recurring-another-example.diary-american
@@ -0,0 +1,4 @@
+&11/23/2004 14:45-15:45 another example
+ Status: TENTATIVE
+ Class: PRIVATE
+ UID: 6161a312-3902-11d9-b512-f764153bb28b
diff --git a/test/lisp/calendar/icalendar-resources/import-non-recurring-another-example.diary-european b/test/lisp/calendar/icalendar-resources/import-non-recurring-another-example.diary-european
new file mode 100644
index 00000000000..394eae8bb77
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-non-recurring-another-example.diary-european
@@ -0,0 +1,4 @@
+&23/11/2004 14:45-15:45 another example
+ Status: TENTATIVE
+ Class: PRIVATE
+ UID: 6161a312-3902-11d9-b512-f764153bb28b
diff --git a/test/lisp/calendar/icalendar-resources/import-non-recurring-another-example.diary-iso b/test/lisp/calendar/icalendar-resources/import-non-recurring-another-example.diary-iso
new file mode 100644
index 00000000000..5e8bdf417d5
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-non-recurring-another-example.diary-iso
@@ -0,0 +1,4 @@
+&2004/11/23 14:45-15:45 another example
+ Status: TENTATIVE
+ Class: PRIVATE
+ UID: 6161a312-3902-11d9-b512-f764153bb28b
diff --git a/test/lisp/calendar/icalendar-resources/import-non-recurring-another-example.ics b/test/lisp/calendar/icalendar-resources/import-non-recurring-another-example.ics
new file mode 100644
index 00000000000..b145e418791
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-non-recurring-another-example.ics
@@ -0,0 +1,23 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+UID
+ :6161a312-3902-11d9-b512-f764153bb28b
+SUMMARY
+ :another example
+STATUS
+ :TENTATIVE
+CLASS
+ :PRIVATE
+X-MOZILLA-ALARM-DEFAULT-LENGTH
+ :0
+DTSTART
+ :20041123T144500
+DTEND
+ :20041123T154500
+DTSTAMP
+ :20041118T013641Z
+END:VEVENT
+END:VCALENDAR
+
diff --git a/test/lisp/calendar/icalendar-resources/import-non-recurring-block.diary-american b/test/lisp/calendar/icalendar-resources/import-non-recurring-block.diary-american
new file mode 100644
index 00000000000..b22234229cf
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-non-recurring-block.diary-american
@@ -0,0 +1,4 @@
+&%%(and (diary-block 7 19 2004 8 27 2004)) Sommerferien
+ Status: TENTATIVE
+ Class: PRIVATE
+ UID: 748f2da0-0d9b-11d8-97af-b4ec8686ea61
diff --git a/test/lisp/calendar/icalendar-resources/import-non-recurring-block.diary-european b/test/lisp/calendar/icalendar-resources/import-non-recurring-block.diary-european
new file mode 100644
index 00000000000..8043482442f
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-non-recurring-block.diary-european
@@ -0,0 +1,4 @@
+&%%(and (diary-block 19 7 2004 27 8 2004)) Sommerferien
+ Status: TENTATIVE
+ Class: PRIVATE
+ UID: 748f2da0-0d9b-11d8-97af-b4ec8686ea61
diff --git a/test/lisp/calendar/icalendar-resources/import-non-recurring-block.diary-iso b/test/lisp/calendar/icalendar-resources/import-non-recurring-block.diary-iso
new file mode 100644
index 00000000000..e0f1896114f
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-non-recurring-block.diary-iso
@@ -0,0 +1,4 @@
+&%%(and (diary-block 2004 7 19 2004 8 27)) Sommerferien
+ Status: TENTATIVE
+ Class: PRIVATE
+ UID: 748f2da0-0d9b-11d8-97af-b4ec8686ea61
diff --git a/test/lisp/calendar/icalendar-resources/import-non-recurring-block.ics b/test/lisp/calendar/icalendar-resources/import-non-recurring-block.ics
new file mode 100644
index 00000000000..0c52ba3d66a
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-non-recurring-block.ics
@@ -0,0 +1,16 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+UID:748f2da0-0d9b-11d8-97af-b4ec8686ea61
+SUMMARY:Sommerferien
+STATUS:TENTATIVE
+CLASS:PRIVATE
+X-MOZILLA-ALARM-DEFAULT-UNITS:Minuten
+X-MOZILLA-RECUR-DEFAULT-INTERVAL:0
+DTSTART;VALUE=DATE:20040719
+DTEND;VALUE=DATE:20040828
+DTSTAMP:20031103T011641Z
+END:VEVENT
+END:VCALENDAR
+
diff --git a/test/lisp/calendar/icalendar-resources/import-non-recurring-folded-summary.diary-american b/test/lisp/calendar/icalendar-resources/import-non-recurring-folded-summary.diary-american
new file mode 100644
index 00000000000..2954d0c4fd1
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-non-recurring-folded-summary.diary-american
@@ -0,0 +1,4 @@
+&11/23/2004 14:00-14:30 folded summary
+ Status: TENTATIVE
+ Class: PRIVATE
+ UID: 04979712-3902-11d9-93dd-8f9f4afe08da
diff --git a/test/lisp/calendar/icalendar-resources/import-non-recurring-folded-summary.diary-european b/test/lisp/calendar/icalendar-resources/import-non-recurring-folded-summary.diary-european
new file mode 100644
index 00000000000..7745fc811b4
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-non-recurring-folded-summary.diary-european
@@ -0,0 +1,4 @@
+&23/11/2004 14:00-14:30 folded summary
+ Status: TENTATIVE
+ Class: PRIVATE
+ UID: 04979712-3902-11d9-93dd-8f9f4afe08da
diff --git a/test/lisp/calendar/icalendar-resources/import-non-recurring-folded-summary.diary-iso b/test/lisp/calendar/icalendar-resources/import-non-recurring-folded-summary.diary-iso
new file mode 100644
index 00000000000..8c19a95ed2d
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-non-recurring-folded-summary.diary-iso
@@ -0,0 +1,4 @@
+&2004/11/23 14:00-14:30 folded summary
+ Status: TENTATIVE
+ Class: PRIVATE
+ UID: 04979712-3902-11d9-93dd-8f9f4afe08da
diff --git a/test/lisp/calendar/icalendar-resources/import-non-recurring-folded-summary.ics b/test/lisp/calendar/icalendar-resources/import-non-recurring-folded-summary.ics
new file mode 100644
index 00000000000..e3ecee9dae8
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-non-recurring-folded-summary.ics
@@ -0,0 +1,25 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+UID
+ :04979712-3902-11d9-93dd-8f9f4afe08da
+SUMMARY
+ :folded summary
+STATUS
+ :TENTATIVE
+CLASS
+ :PRIVATE
+X-MOZILLA-ALARM-DEFAULT-LENGTH
+ :0
+DTSTART
+ :20041123T140000
+DTEND
+ :20041123T143000
+DTSTAMP
+ :20041118T013430Z
+LAST-MODIFIED
+ :20041118T013640Z
+END:VEVENT
+END:VCALENDAR
+
diff --git a/test/lisp/calendar/icalendar-resources/import-non-recurring-long-summary.diary-american b/test/lisp/calendar/icalendar-resources/import-non-recurring-long-summary.diary-american
new file mode 100644
index 00000000000..84cd464c568
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-non-recurring-long-summary.diary-american
@@ -0,0 +1 @@
+&9/19/2003 long summary
diff --git a/test/lisp/calendar/icalendar-resources/import-non-recurring-long-summary.diary-european b/test/lisp/calendar/icalendar-resources/import-non-recurring-long-summary.diary-european
new file mode 100644
index 00000000000..5d6524202c3
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-non-recurring-long-summary.diary-european
@@ -0,0 +1 @@
+&19/9/2003 long summary
diff --git a/test/lisp/calendar/icalendar-resources/import-non-recurring-long-summary.diary-iso b/test/lisp/calendar/icalendar-resources/import-non-recurring-long-summary.diary-iso
new file mode 100644
index 00000000000..d2300522d9a
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-non-recurring-long-summary.diary-iso
@@ -0,0 +1 @@
+&2003/9/19 long summary
diff --git a/test/lisp/calendar/icalendar-resources/import-non-recurring-long-summary.ics b/test/lisp/calendar/icalendar-resources/import-non-recurring-long-summary.ics
new file mode 100644
index 00000000000..39ae02f10ca
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-non-recurring-long-summary.ics
@@ -0,0 +1,10 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+SUMMARY:long
+ summary
+DTSTART;VALUE=DATE:20030919
+END:VEVENT
+END:VCALENDAR
+
diff --git a/test/lisp/calendar/icalendar-resources/import-real-world-2003-05-29.diary-american b/test/lisp/calendar/icalendar-resources/import-real-world-2003-05-29.diary-american
new file mode 100644
index 00000000000..e6c8712d254
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-real-world-2003-05-29.diary-american
@@ -0,0 +1,6 @@
+&5/9/2003 07:00-12:00 On-Site Interview
+ Desc: 10:30am - Blah
+ Location: Cccc
+ Organizer: MAILTO:aaaaaaa@aaaaaaa.com
+ Status: CONFIRMED
+ UID: 040000008200E00074C5B7101A82E0080000000080B6DE661216C301000000000000000010000000DB823520692542408ED02D7023F9DFF9
diff --git a/test/lisp/calendar/icalendar-resources/import-real-world-2003-05-29.diary-european b/test/lisp/calendar/icalendar-resources/import-real-world-2003-05-29.diary-european
new file mode 100644
index 00000000000..cecca070a51
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-real-world-2003-05-29.diary-european
@@ -0,0 +1,6 @@
+&9/5/2003 07:00-12:00 On-Site Interview
+ Desc: 10:30am - Blah
+ Location: Cccc
+ Organizer: MAILTO:aaaaaaa@aaaaaaa.com
+ Status: CONFIRMED
+ UID: 040000008200E00074C5B7101A82E0080000000080B6DE661216C301000000000000000010000000DB823520692542408ED02D7023F9DFF9
diff --git a/test/lisp/calendar/icalendar-resources/import-real-world-2003-05-29.ics b/test/lisp/calendar/icalendar-resources/import-real-world-2003-05-29.ics
new file mode 100644
index 00000000000..decc8df5451
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-real-world-2003-05-29.ics
@@ -0,0 +1,54 @@
+BEGIN:VCALENDAR
+METHOD:REQUEST
+PRODID:Microsoft CDO for Microsoft Exchange
+VERSION:2.0
+BEGIN:VTIMEZONE
+TZID:Kolkata, Chennai, Mumbai, New Delhi
+X-MICROSOFT-CDO-TZID:23
+BEGIN:STANDARD
+DTSTART:16010101T000000
+TZOFFSETFROM:+0530
+TZOFFSETTO:+0530
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:16010101T000000
+TZOFFSETFROM:+0530
+TZOFFSETTO:+0530
+END:DAYLIGHT
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTAMP:20030509T043439Z
+DTSTART;TZID="Kolkata, Chennai, Mumbai, New Delhi":20030509T103000
+SUMMARY:On-Site Interview
+UID:040000008200E00074C5B7101A82E0080000000080B6DE661216C301000000000000000
+ 010000000DB823520692542408ED02D7023F9DFF9
+ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN="Xxxxx
+ xxx Xxxxxxxxxxxx":MAILTO:xxxxxxxx@xxxxxxx.com
+ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN="Yyyyyyy Y
+ yyyy":MAILTO:yyyyyyy@yyyyyyy.com
+ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN="Zzzz Zzzz
+ zz":MAILTO:zzzzzz@zzzzzzz.com
+ORGANIZER;CN="Aaaaaa Aaaaa":MAILTO:aaaaaaa@aaaaaaa.com
+LOCATION:Cccc
+DTEND;TZID="Kolkata, Chennai, Mumbai, New Delhi":20030509T153000
+DESCRIPTION:10:30am - Blah
+SEQUENCE:0
+PRIORITY:5
+CLASS:
+CREATED:20030509T043439Z
+LAST-MODIFIED:20030509T043459Z
+STATUS:CONFIRMED
+TRANSP:OPAQUE
+X-MICROSOFT-CDO-BUSYSTATUS:BUSY
+X-MICROSOFT-CDO-INSTTYPE:0
+X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY
+X-MICROSOFT-CDO-ALLDAYEVENT:FALSE
+X-MICROSOFT-CDO-IMPORTANCE:1
+X-MICROSOFT-CDO-OWNERAPPTID:126441427
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:REMINDER
+TRIGGER;RELATED=START:-PT00H15M00S
+END:VALARM
+END:VEVENT
+END:VCALENDAR
diff --git a/test/lisp/calendar/icalendar-resources/import-real-world-2003-06-18a.diary-american b/test/lisp/calendar/icalendar-resources/import-real-world-2003-06-18a.diary-american
new file mode 100644
index 00000000000..f2c914184e7
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-real-world-2003-06-18a.diary-american
@@ -0,0 +1,6 @@
+&6/23/2003 11:00-12:00 Dress Rehearsal for XXXX-XXXX
+ Desc: 753 Zeichen hier radiert
+ Location: 555 or TN 555-5555 ID 5555 & NochWas (see below)
+ Organizer: MAILTO:xxx@xxxxx.com
+ Status: CONFIRMED
+ UID: 040000008200E00074C5B7101A82E00800000000608AA7DA9835C3010000000000000000100000007C3A6D65EE726E40B7F3D69A23BD567E
diff --git a/test/lisp/calendar/icalendar-resources/import-real-world-2003-06-18a.diary-european b/test/lisp/calendar/icalendar-resources/import-real-world-2003-06-18a.diary-european
new file mode 100644
index 00000000000..89cff58af42
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-real-world-2003-06-18a.diary-european
@@ -0,0 +1,6 @@
+&23/6/2003 11:00-12:00 Dress Rehearsal for XXXX-XXXX
+ Desc: 753 Zeichen hier radiert
+ Location: 555 or TN 555-5555 ID 5555 & NochWas (see below)
+ Organizer: MAILTO:xxx@xxxxx.com
+ Status: CONFIRMED
+ UID: 040000008200E00074C5B7101A82E00800000000608AA7DA9835C3010000000000000000100000007C3A6D65EE726E40B7F3D69A23BD567E
diff --git a/test/lisp/calendar/icalendar-resources/import-real-world-2003-06-18a.ics b/test/lisp/calendar/icalendar-resources/import-real-world-2003-06-18a.ics
new file mode 100644
index 00000000000..6bb5b05af17
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-real-world-2003-06-18a.ics
@@ -0,0 +1,36 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+DTSTAMP:20030618T195512Z
+DTSTART;TZID="Mountain Time (US & Canada)":20030623T110000
+SUMMARY:Dress Rehearsal for XXXX-XXXX
+UID:040000008200E00074C5B7101A82E00800000000608AA7DA9835C301000000000000000
+ 0100000007C3A6D65EE726E40B7F3D69A23BD567E
+ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN="AAAAA,AAA
+ AA (A-AAAAAAA,ex1)":MAILTO:aaaaa_aaaaa@aaaaa.com
+ORGANIZER;CN="ABCD,TECHTRAINING
+ (A-Americas,exgen1)":MAILTO:xxx@xxxxx.com
+LOCATION:555 or TN 555-5555 ID 5555 & NochWas (see below)
+DTEND;TZID="Mountain Time (US & Canada)":20030623T120000
+DESCRIPTION:753 Zeichen hier radiert
+SEQUENCE:0
+PRIORITY:5
+CLASS:
+CREATED:20030618T195518Z
+LAST-MODIFIED:20030618T195527Z
+STATUS:CONFIRMED
+TRANSP:OPAQUE
+X-MICROSOFT-CDO-BUSYSTATUS:BUSY
+X-MICROSOFT-CDO-INSTTYPE:0
+X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY
+X-MICROSOFT-CDO-ALLDAYEVENT:FALSE
+X-MICROSOFT-CDO-IMPORTANCE:1
+X-MICROSOFT-CDO-OWNERAPPTID:1022519251
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:REMINDER
+TRIGGER;RELATED=START:-PT00H15M00S
+END:VALARM
+END:VEVENT
+END:VCALENDAR
diff --git a/test/lisp/calendar/icalendar-resources/import-real-world-2003-06-18b.diary-american b/test/lisp/calendar/icalendar-resources/import-real-world-2003-06-18b.diary-american
new file mode 100644
index 00000000000..2c0774cdd83
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-real-world-2003-06-18b.diary-american
@@ -0,0 +1,6 @@
+&6/23/2003 17:00-18:00 Updated: Dress Rehearsal for ABC01-15
+ Desc: Viele Zeichen standen hier früher
+ Location: 123 or TN 123-1234 ID abcd & SonstWo (see below)
+ Organizer: MAILTO:bbb@bbbbb.com
+ Status: CONFIRMED
+ UID: 040000008200E00074C5B7101A82E00800000000608AA7DA9835C3010000000000000000100000007C3A6D65EE726E40B7F3D69A23BD567E
diff --git a/test/lisp/calendar/icalendar-resources/import-real-world-2003-06-18b.diary-european b/test/lisp/calendar/icalendar-resources/import-real-world-2003-06-18b.diary-european
new file mode 100644
index 00000000000..95aac168699
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-real-world-2003-06-18b.diary-european
@@ -0,0 +1,6 @@
+&23/6/2003 17:00-18:00 Updated: Dress Rehearsal for ABC01-15
+ Desc: Viele Zeichen standen hier früher
+ Location: 123 or TN 123-1234 ID abcd & SonstWo (see below)
+ Organizer: MAILTO:bbb@bbbbb.com
+ Status: CONFIRMED
+ UID: 040000008200E00074C5B7101A82E00800000000608AA7DA9835C3010000000000000000100000007C3A6D65EE726E40B7F3D69A23BD567E
diff --git a/test/lisp/calendar/icalendar-resources/import-real-world-2003-06-18b.ics b/test/lisp/calendar/icalendar-resources/import-real-world-2003-06-18b.ics
new file mode 100644
index 00000000000..1523135adf3
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-real-world-2003-06-18b.ics
@@ -0,0 +1,55 @@
+BEGIN:VCALENDAR
+METHOD:REQUEST
+PRODID:Microsoft CDO for Microsoft Exchange
+VERSION:2.0
+BEGIN:VTIMEZONE
+TZID:Mountain Time (US & Canada)
+X-MICROSOFT-CDO-TZID:12
+BEGIN:STANDARD
+DTSTART:16010101T020000
+TZOFFSETFROM:-0600
+TZOFFSETTO:-0700
+RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=10;BYDAY=-1SU
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:16010101T020000
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0600
+RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=4;BYDAY=1SU
+END:DAYLIGHT
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTAMP:20030618T230323Z
+DTSTART;TZID="Mountain Time (US & Canada)":20030623T090000
+SUMMARY:Updated: Dress Rehearsal for ABC01-15
+UID:040000008200E00074C5B7101A82E00800000000608AA7DA9835C301000000000000000
+ 0100000007C3A6D65EE726E40B7F3D69A23BD567E
+ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;X-REPLYTIME=20030618T20
+ 0700Z;RSVP=TRUE;CN="AAAAA,AAAAAA
+\(A-AAAAAAA,ex1)":MAILTO:aaaaaa_aaaaa@aaaaa
+ .com
+ORGANIZER;CN="ABCD,TECHTRAINING
+\(A-Americas,exgen1)":MAILTO:bbb@bbbbb.com
+LOCATION:123 or TN 123-1234 ID abcd & SonstWo (see below)
+DTEND;TZID="Mountain Time (US & Canada)":20030623T100000
+DESCRIPTION:Viele Zeichen standen hier früher
+SEQUENCE:0
+PRIORITY:5
+CLASS:
+CREATED:20030618T230326Z
+LAST-MODIFIED:20030618T230335Z
+STATUS:CONFIRMED
+TRANSP:OPAQUE
+X-MICROSOFT-CDO-BUSYSTATUS:BUSY
+X-MICROSOFT-CDO-INSTTYPE:0
+X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY
+X-MICROSOFT-CDO-ALLDAYEVENT:FALSE
+X-MICROSOFT-CDO-IMPORTANCE:1
+X-MICROSOFT-CDO-OWNERAPPTID:1022519251
+BEGIN:VALARM
+ACTION:DISPLAY
+DESCRIPTION:REMINDER
+TRIGGER;RELATED=START:-PT00H15M00S
+END:VALARM
+END:VEVENT
+END:VCALENDAR \ No newline at end of file
diff --git a/test/lisp/calendar/icalendar-resources/import-real-world-2004-11-19.diary-american b/test/lisp/calendar/icalendar-resources/import-real-world-2004-11-19.diary-american
new file mode 100644
index 00000000000..a986f700ba2
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-real-world-2004-11-19.diary-american
@@ -0,0 +1,19 @@
+&11/23/2004 14:00-14:30 Jjjjj & Wwwww
+ Status: TENTATIVE
+ Class: PRIVATE
+&11/23/2004 14:45-15:45 BB Aaaaaaaa Bbbbb
+ Status: TENTATIVE
+ Class: PRIVATE
+&11/23/2004 11:00-12:00 Hhhhhhhh
+ Status: TENTATIVE
+ Class: PRIVATE
+&%%(and (diary-cyclic 14 11 12 2004)) 14:00-18:30 MMM Aaaaaaaaa
+ Status: TENTATIVE
+ Class: PRIVATE
+&%%(and (diary-block 11 19 2004 11 19 2004)) Rrrr/Cccccc ii Aaaaaaaa
+ Desc: Vvvvv Rrrr aaa Cccccc
+ Status: TENTATIVE
+ Class: PRIVATE
+&%%(and (diary-cyclic 7 11 1 2004)) Wwww aa hhhh
+ Status: TENTATIVE
+ Class: PRIVATE
diff --git a/test/lisp/calendar/icalendar-resources/import-real-world-2004-11-19.diary-european b/test/lisp/calendar/icalendar-resources/import-real-world-2004-11-19.diary-european
new file mode 100644
index 00000000000..cbfe99eb8e3
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-real-world-2004-11-19.diary-european
@@ -0,0 +1,19 @@
+&23/11/2004 14:00-14:30 Jjjjj & Wwwww
+ Status: TENTATIVE
+ Class: PRIVATE
+&23/11/2004 14:45-15:45 BB Aaaaaaaa Bbbbb
+ Status: TENTATIVE
+ Class: PRIVATE
+&23/11/2004 11:00-12:00 Hhhhhhhh
+ Status: TENTATIVE
+ Class: PRIVATE
+&%%(and (diary-cyclic 14 12 11 2004)) 14:00-18:30 MMM Aaaaaaaaa
+ Status: TENTATIVE
+ Class: PRIVATE
+&%%(and (diary-block 19 11 2004 19 11 2004)) Rrrr/Cccccc ii Aaaaaaaa
+ Desc: Vvvvv Rrrr aaa Cccccc
+ Status: TENTATIVE
+ Class: PRIVATE
+&%%(and (diary-cyclic 7 1 11 2004)) Wwww aa hhhh
+ Status: TENTATIVE
+ Class: PRIVATE
diff --git a/test/lisp/calendar/icalendar-resources/import-real-world-2004-11-19.ics b/test/lisp/calendar/icalendar-resources/import-real-world-2004-11-19.ics
new file mode 100644
index 00000000000..9edb682fcad
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-real-world-2004-11-19.ics
@@ -0,0 +1,120 @@
+BEGIN:VCALENDAR
+VERSION
+ :2.0
+PRODID
+ :-//Mozilla.org/NONSGML Mozilla Calendar V1.0//EN
+BEGIN:VEVENT
+SUMMARY
+ :Jjjjj & Wwwww
+STATUS
+ :TENTATIVE
+CLASS
+ :PRIVATE
+X-MOZILLA-ALARM-DEFAULT-LENGTH
+ :0
+DTSTART
+ :20041123T140000
+DTEND
+ :20041123T143000
+DTSTAMP
+ :20041118T013430Z
+LAST-MODIFIED
+ :20041118T013640Z
+END:VEVENT
+BEGIN:VEVENT
+SUMMARY
+ :BB Aaaaaaaa Bbbbb
+STATUS
+ :TENTATIVE
+CLASS
+ :PRIVATE
+X-MOZILLA-ALARM-DEFAULT-LENGTH
+ :0
+DTSTART
+ :20041123T144500
+DTEND
+ :20041123T154500
+DTSTAMP
+ :20041118T013641Z
+END:VEVENT
+BEGIN:VEVENT
+SUMMARY
+ :Hhhhhhhh
+STATUS
+ :TENTATIVE
+CLASS
+ :PRIVATE
+X-MOZILLA-ALARM-DEFAULT-LENGTH
+ :0
+DTSTART
+ :20041123T110000
+DTEND
+ :20041123T120000
+DTSTAMP
+ :20041118T013831Z
+END:VEVENT
+BEGIN:VEVENT
+SUMMARY
+ :MMM Aaaaaaaaa
+STATUS
+ :TENTATIVE
+CLASS
+ :PRIVATE
+X-MOZILLA-ALARM-DEFAULT-LENGTH
+ :0
+X-MOZILLA-RECUR-DEFAULT-INTERVAL
+ :2
+RRULE
+ :FREQ=WEEKLY;INTERVAL=2;BYDAY=FR
+DTSTART
+ :20041112T140000
+DTEND
+ :20041112T183000
+DTSTAMP
+ :20041118T014117Z
+END:VEVENT
+BEGIN:VEVENT
+SUMMARY
+ :Rrrr/Cccccc ii Aaaaaaaa
+DESCRIPTION
+ :Vvvvv Rrrr aaa Cccccc
+STATUS
+ :TENTATIVE
+CLASS
+ :PRIVATE
+X-MOZILLA-ALARM-DEFAULT-LENGTH
+ :0
+DTSTART
+ ;VALUE=DATE
+ :20041119
+DTEND
+ ;VALUE=DATE
+ :20041120
+DTSTAMP
+ :20041118T013107Z
+LAST-MODIFIED
+ :20041118T014203Z
+END:VEVENT
+BEGIN:VEVENT
+SUMMARY
+ :Wwww aa hhhh
+STATUS
+ :TENTATIVE
+CLASS
+ :PRIVATE
+X-MOZILLA-ALARM-DEFAULT-LENGTH
+ :0
+RRULE
+ :FREQ=WEEKLY;INTERVAL=1;BYDAY=MO
+DTSTART
+ ;VALUE=DATE
+ :20041101
+DTEND
+ ;VALUE=DATE
+ :20041102
+DTSTAMP
+ :20041118T014045Z
+LAST-MODIFIED
+ :20041118T023846Z
+END:VEVENT
+END:VCALENDAR
diff --git a/test/lisp/calendar/icalendar-resources/import-real-world-2005-02-07.diary-american b/test/lisp/calendar/icalendar-resources/import-real-world-2005-02-07.diary-american
new file mode 100644
index 00000000000..ce7d835d96b
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-real-world-2005-02-07.diary-american
@@ -0,0 +1,5 @@
+&%%(and (diary-block 2 6 2005 2 6 2005)) Waitangi Day
+ Desc: abcdef
+ Status: CONFIRMED
+ Class: PRIVATE
+ UID: b60d398e-1dd1-11b2-a159-cf8cb05139f4
diff --git a/test/lisp/calendar/icalendar-resources/import-real-world-2005-02-07.diary-european b/test/lisp/calendar/icalendar-resources/import-real-world-2005-02-07.diary-european
new file mode 100644
index 00000000000..3a52b0ab271
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-real-world-2005-02-07.diary-european
@@ -0,0 +1,5 @@
+&%%(and (diary-block 6 2 2005 6 2 2005)) Waitangi Day
+ Desc: abcdef
+ Status: CONFIRMED
+ Class: PRIVATE
+ UID: b60d398e-1dd1-11b2-a159-cf8cb05139f4
diff --git a/test/lisp/calendar/icalendar-resources/import-real-world-2005-02-07.ics b/test/lisp/calendar/icalendar-resources/import-real-world-2005-02-07.ics
new file mode 100644
index 00000000000..9eec71fe751
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-real-world-2005-02-07.ics
@@ -0,0 +1,26 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+UID
+ :b60d398e-1dd1-11b2-a159-cf8cb05139f4
+SUMMARY
+ :Waitangi Day
+DESCRIPTION
+ :abcdef
+CATEGORIES
+ :Public Holiday
+STATUS
+ :CONFIRMED
+CLASS
+ :PRIVATE
+DTSTART
+ ;VALUE=DATE
+ :20050206
+DTEND
+ ;VALUE=DATE
+ :20050207
+DTSTAMP
+ :20050128T011209Z
+END:VEVENT
+END:VCALENDAR
diff --git a/test/lisp/calendar/icalendar-resources/import-real-world-2005-03-01.diary-american b/test/lisp/calendar/icalendar-resources/import-real-world-2005-03-01.diary-american
new file mode 100644
index 00000000000..23c93d45d9a
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-real-world-2005-03-01.diary-american
@@ -0,0 +1,2 @@
+&%%(and (diary-block 2 17 2005 2 23 2005)) Hhhhhh Aaaaa ii Aaaaaaaa
+ UID: 6AFA7558-6994-11D9-8A3A-000A95A0E830-RID
diff --git a/test/lisp/calendar/icalendar-resources/import-real-world-2005-03-01.diary-european b/test/lisp/calendar/icalendar-resources/import-real-world-2005-03-01.diary-european
new file mode 100644
index 00000000000..106e9f3cdd0
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-real-world-2005-03-01.diary-european
@@ -0,0 +1,2 @@
+&%%(and (diary-block 17 2 2005 23 2 2005)) Hhhhhh Aaaaa ii Aaaaaaaa
+ UID: 6AFA7558-6994-11D9-8A3A-000A95A0E830-RID
diff --git a/test/lisp/calendar/icalendar-resources/import-real-world-2005-03-01.ics b/test/lisp/calendar/icalendar-resources/import-real-world-2005-03-01.ics
new file mode 100644
index 00000000000..ed9faa9b0bd
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-real-world-2005-03-01.ics
@@ -0,0 +1,11 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20050217
+SUMMARY:Hhhhhh Aaaaa ii Aaaaaaaa
+UID:6AFA7558-6994-11D9-8A3A-000A95A0E830-RID
+DTSTAMP:20050118T210335Z
+DURATION:P7D
+END:VEVENT
+END:VCALENDAR
diff --git a/test/lisp/calendar/icalendar-resources/import-real-world-no-dst.diary-american b/test/lisp/calendar/icalendar-resources/import-real-world-no-dst.diary-american
new file mode 100644
index 00000000000..290edb88760
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-real-world-no-dst.diary-american
@@ -0,0 +1,4 @@
+&11/16/2014 04:30-05:30 NoDST
+ Desc: Test event from timezone without DST
+ Location: Everywhere
+ UID: 20141116T171439Z-678877132@marudot.com
diff --git a/test/lisp/calendar/icalendar-resources/import-real-world-no-dst.diary-european b/test/lisp/calendar/icalendar-resources/import-real-world-no-dst.diary-european
new file mode 100644
index 00000000000..c56b7a6547a
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-real-world-no-dst.diary-european
@@ -0,0 +1,4 @@
+&16/11/2014 04:30-05:30 NoDST
+ Desc: Test event from timezone without DST
+ Location: Everywhere
+ UID: 20141116T171439Z-678877132@marudot.com
diff --git a/test/lisp/calendar/icalendar-resources/import-real-world-no-dst.ics b/test/lisp/calendar/icalendar-resources/import-real-world-no-dst.ics
new file mode 100644
index 00000000000..5f147af4f37
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-real-world-no-dst.ics
@@ -0,0 +1,26 @@
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//www.marudot.com//iCal Event Maker
+X-WR-CALNAME:Test
+CALSCALE:GREGORIAN
+BEGIN:VTIMEZONE
+TZID:Asia/Tehran
+TZURL:http://tzurl.org/zoneinfo-outlook/Asia/Tehran
+X-LIC-LOCATION:Asia/Tehran
+BEGIN:STANDARD
+TZOFFSETFROM:+0330
+TZOFFSETTO:+0330
+TZNAME:IRST
+DTSTART:19700101T000000
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTAMP:20141116T171439Z
+UID:20141116T171439Z-678877132@marudot.com
+DTSTART;TZID="Asia/Tehran":20141116T070000
+DTEND;TZID="Asia/Tehran":20141116T080000
+SUMMARY:NoDST
+DESCRIPTION:Test event from timezone without DST
+LOCATION:Everywhere
+END:VEVENT
+END:VCALENDAR \ No newline at end of file
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-anniversary.diary-american b/test/lisp/calendar/icalendar-resources/import-rrule-anniversary.diary-american
new file mode 100644
index 00000000000..7b86b554dd4
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-anniversary.diary-american
@@ -0,0 +1 @@
+&%%(and (diary-anniversary 8 15 2004)) Maria Himmelfahrt
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-anniversary.diary-european b/test/lisp/calendar/icalendar-resources/import-rrule-anniversary.diary-european
new file mode 100644
index 00000000000..3b82ec09fd5
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-anniversary.diary-european
@@ -0,0 +1 @@
+&%%(and (diary-anniversary 15 8 2004)) Maria Himmelfahrt
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-anniversary.diary-iso b/test/lisp/calendar/icalendar-resources/import-rrule-anniversary.diary-iso
new file mode 100644
index 00000000000..7fc99478d4e
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-anniversary.diary-iso
@@ -0,0 +1 @@
+&%%(and (diary-anniversary 2004 8 15)) Maria Himmelfahrt
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-anniversary.ics b/test/lisp/calendar/icalendar-resources/import-rrule-anniversary.ics
new file mode 100644
index 00000000000..2996f494167
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-anniversary.ics
@@ -0,0 +1,11 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20040815
+DTEND;VALUE=DATE:20040816
+SUMMARY:Maria Himmelfahrt
+RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=8
+END:VEVENT
+END:VCALENDAR
+
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-bi-weekly.diary-american b/test/lisp/calendar/icalendar-resources/import-rrule-count-bi-weekly.diary-american
new file mode 100644
index 00000000000..84b6d109953
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-bi-weekly.diary-american
@@ -0,0 +1 @@
+&%%(and (diary-cyclic 14 9 19 2003) (diary-block 9 19 2003 10 31 2003)) 09:00-11:30 rrule count bi-weekly 3 times
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-bi-weekly.diary-european b/test/lisp/calendar/icalendar-resources/import-rrule-count-bi-weekly.diary-european
new file mode 100644
index 00000000000..0bebdf8872f
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-bi-weekly.diary-european
@@ -0,0 +1 @@
+&%%(and (diary-cyclic 14 19 9 2003) (diary-block 19 9 2003 31 10 2003)) 09:00-11:30 rrule count bi-weekly 3 times
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-bi-weekly.diary-iso b/test/lisp/calendar/icalendar-resources/import-rrule-count-bi-weekly.diary-iso
new file mode 100644
index 00000000000..11429081abe
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-bi-weekly.diary-iso
@@ -0,0 +1 @@
+&%%(and (diary-cyclic 14 2003 9 19) (diary-block 2003 9 19 2003 10 31)) 09:00-11:30 rrule count bi-weekly 3 times
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-bi-weekly.ics b/test/lisp/calendar/icalendar-resources/import-rrule-count-bi-weekly.ics
new file mode 100644
index 00000000000..888b85bb331
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-bi-weekly.ics
@@ -0,0 +1,11 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+SUMMARY:rrule count bi-weekly 3 times
+DTSTART;VALUE=DATE-TIME:20030919T090000
+DTEND;VALUE=DATE-TIME:20030919T113000
+RRULE:FREQ=WEEKLY;COUNT=3;INTERVAL=2
+END:VEVENT
+END:VCALENDAR
+
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-daily-long.diary-american b/test/lisp/calendar/icalendar-resources/import-rrule-count-daily-long.diary-american
new file mode 100644
index 00000000000..23fe9fcaf32
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-daily-long.diary-american
@@ -0,0 +1 @@
+&%%(and (diary-cyclic 1 9 19 2003) (diary-block 9 19 2003 10 2 2003)) 09:00-11:30 rrule count daily long
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-daily-long.diary-european b/test/lisp/calendar/icalendar-resources/import-rrule-count-daily-long.diary-european
new file mode 100644
index 00000000000..0d4ab669058
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-daily-long.diary-european
@@ -0,0 +1 @@
+&%%(and (diary-cyclic 1 19 9 2003) (diary-block 19 9 2003 2 10 2003)) 09:00-11:30 rrule count daily long
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-daily-long.diary-iso b/test/lisp/calendar/icalendar-resources/import-rrule-count-daily-long.diary-iso
new file mode 100644
index 00000000000..8cecda5c879
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-daily-long.diary-iso
@@ -0,0 +1 @@
+&%%(and (diary-cyclic 1 2003 9 19) (diary-block 2003 9 19 2003 10 2)) 09:00-11:30 rrule count daily long
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-daily-long.ics b/test/lisp/calendar/icalendar-resources/import-rrule-count-daily-long.ics
new file mode 100644
index 00000000000..73df19a8196
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-daily-long.ics
@@ -0,0 +1,11 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+SUMMARY:rrule count daily long
+DTSTART;VALUE=DATE-TIME:20030919T090000
+DTEND;VALUE=DATE-TIME:20030919T113000
+RRULE:FREQ=DAILY;COUNT=14;INTERVAL=1
+END:VEVENT
+END:VCALENDAR
+
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-daily-short.diary-american b/test/lisp/calendar/icalendar-resources/import-rrule-count-daily-short.diary-american
new file mode 100644
index 00000000000..d69bb08c318
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-daily-short.diary-american
@@ -0,0 +1 @@
+&%%(and (diary-cyclic 1 9 19 2003) (diary-block 9 19 2003 9 19 2003)) 09:00-11:30 rrule count daily short
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-daily-short.diary-european b/test/lisp/calendar/icalendar-resources/import-rrule-count-daily-short.diary-european
new file mode 100644
index 00000000000..33a1ce4cf51
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-daily-short.diary-european
@@ -0,0 +1 @@
+&%%(and (diary-cyclic 1 19 9 2003) (diary-block 19 9 2003 19 9 2003)) 09:00-11:30 rrule count daily short
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-daily-short.diary-iso b/test/lisp/calendar/icalendar-resources/import-rrule-count-daily-short.diary-iso
new file mode 100644
index 00000000000..a06bcba0dc1
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-daily-short.diary-iso
@@ -0,0 +1 @@
+&%%(and (diary-cyclic 1 2003 9 19) (diary-block 2003 9 19 2003 9 19)) 09:00-11:30 rrule count daily short
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-daily-short.ics b/test/lisp/calendar/icalendar-resources/import-rrule-count-daily-short.ics
new file mode 100644
index 00000000000..92ffe8be654
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-daily-short.ics
@@ -0,0 +1,11 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+SUMMARY:rrule count daily short
+DTSTART;VALUE=DATE-TIME:20030919T090000
+DTEND;VALUE=DATE-TIME:20030919T113000
+RRULE:FREQ=DAILY;COUNT=1;INTERVAL=1
+END:VEVENT
+END:VCALENDAR
+
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-month.diary-american b/test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-month.diary-american
new file mode 100644
index 00000000000..4ce8ef842f8
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-month.diary-american
@@ -0,0 +1 @@
+&%%(and (diary-date t 19 t) (diary-block 9 19 2003 5 19 2004)) 09:00-11:30 rrule count every second month
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-month.diary-european b/test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-month.diary-european
new file mode 100644
index 00000000000..09ec3756295
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-month.diary-european
@@ -0,0 +1 @@
+&%%(and (diary-date 19 t t) (diary-block 19 9 2003 19 5 2004)) 09:00-11:30 rrule count every second month
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-month.diary-iso b/test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-month.diary-iso
new file mode 100644
index 00000000000..ae6feb70d4c
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-month.diary-iso
@@ -0,0 +1 @@
+&%%(and (diary-date t t 19) (diary-block 2003 9 19 2004 5 19)) 09:00-11:30 rrule count every second month
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-month.ics b/test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-month.ics
new file mode 100644
index 00000000000..3b27b665498
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-month.ics
@@ -0,0 +1,11 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+SUMMARY:rrule count every second month
+DTSTART;VALUE=DATE-TIME:20030919T090000
+DTEND;VALUE=DATE-TIME:20030919T113000
+RRULE:FREQ=MONTHLY;INTERVAL=2;COUNT=5
+END:VEVENT
+END:VCALENDAR
+
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-year.diary-american b/test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-year.diary-american
new file mode 100644
index 00000000000..99543aa9596
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-year.diary-american
@@ -0,0 +1 @@
+&%%(and (diary-date 9 19 t) (diary-block 9 19 2003 9 19 2011)) 09:00-11:30 rrule count every second year
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-year.diary-european b/test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-year.diary-european
new file mode 100644
index 00000000000..3b330886ce0
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-year.diary-european
@@ -0,0 +1 @@
+&%%(and (diary-date 19 9 t) (diary-block 19 9 2003 19 9 2011)) 09:00-11:30 rrule count every second year
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-year.diary-iso b/test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-year.diary-iso
new file mode 100644
index 00000000000..16af52ea91c
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-year.diary-iso
@@ -0,0 +1 @@
+&%%(and (diary-date t 9 19) (diary-block 2003 9 19 2011 9 19)) 09:00-11:30 rrule count every second year
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-year.ics b/test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-year.ics
new file mode 100644
index 00000000000..ce21c34d09a
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-every-second-year.ics
@@ -0,0 +1,10 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+SUMMARY:rrule count every second year
+DTSTART;VALUE=DATE-TIME:20030919T090000
+DTEND;VALUE=DATE-TIME:20030919T113000
+RRULE:FREQ=YEARLY;INTERVAL=2;COUNT=5
+END:VEVENT
+END:VCALENDAR
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-monthly.diary-american b/test/lisp/calendar/icalendar-resources/import-rrule-count-monthly.diary-american
new file mode 100644
index 00000000000..ad5ca0b0ed4
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-monthly.diary-american
@@ -0,0 +1 @@
+&%%(and (diary-date t 19 t) (diary-block 9 19 2003 1 19 2004)) 09:00-11:30 rrule count monthly
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-monthly.diary-european b/test/lisp/calendar/icalendar-resources/import-rrule-count-monthly.diary-european
new file mode 100644
index 00000000000..709de3a3fd5
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-monthly.diary-european
@@ -0,0 +1 @@
+&%%(and (diary-date 19 t t) (diary-block 19 9 2003 19 1 2004)) 09:00-11:30 rrule count monthly
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-monthly.diary-iso b/test/lisp/calendar/icalendar-resources/import-rrule-count-monthly.diary-iso
new file mode 100644
index 00000000000..9fc2a2def94
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-monthly.diary-iso
@@ -0,0 +1 @@
+&%%(and (diary-date t t 19) (diary-block 2003 9 19 2004 1 19)) 09:00-11:30 rrule count monthly
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-monthly.ics b/test/lisp/calendar/icalendar-resources/import-rrule-count-monthly.ics
new file mode 100644
index 00000000000..3391ca24252
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-monthly.ics
@@ -0,0 +1,11 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+SUMMARY:rrule count monthly
+DTSTART;VALUE=DATE-TIME:20030919T090000
+DTEND;VALUE=DATE-TIME:20030919T113000
+RRULE:FREQ=MONTHLY;INTERVAL=1;COUNT=5
+END:VEVENT
+END:VCALENDAR
+
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-yearly.diary-american b/test/lisp/calendar/icalendar-resources/import-rrule-count-yearly.diary-american
new file mode 100644
index 00000000000..8c1f95b0c05
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-yearly.diary-american
@@ -0,0 +1 @@
+&%%(and (diary-date 9 19 t) (diary-block 9 19 2003 9 19 2007)) 09:00-11:30 rrule count yearly
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-yearly.diary-european b/test/lisp/calendar/icalendar-resources/import-rrule-count-yearly.diary-european
new file mode 100644
index 00000000000..e216e224eae
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-yearly.diary-european
@@ -0,0 +1 @@
+&%%(and (diary-date 19 9 t) (diary-block 19 9 2003 19 9 2007)) 09:00-11:30 rrule count yearly
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-yearly.diary-iso b/test/lisp/calendar/icalendar-resources/import-rrule-count-yearly.diary-iso
new file mode 100644
index 00000000000..3801192ee60
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-yearly.diary-iso
@@ -0,0 +1 @@
+&%%(and (diary-date t 9 19) (diary-block 2003 9 19 2007 9 19)) 09:00-11:30 rrule count yearly
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-count-yearly.ics b/test/lisp/calendar/icalendar-resources/import-rrule-count-yearly.ics
new file mode 100644
index 00000000000..d8569933e0c
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-count-yearly.ics
@@ -0,0 +1,11 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+SUMMARY:rrule count yearly
+DTSTART;VALUE=DATE-TIME:20030919T090000
+DTEND;VALUE=DATE-TIME:20030919T113000
+RRULE:FREQ=YEARLY;INTERVAL=1;COUNT=5
+END:VEVENT
+END:VCALENDAR
+
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-daily-two-day.diary-american b/test/lisp/calendar/icalendar-resources/import-rrule-daily-two-day.diary-american
new file mode 100644
index 00000000000..495fca5f8df
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-daily-two-day.diary-american
@@ -0,0 +1 @@
+&%%(and (diary-cyclic 2 9 19 2003)) 09:00-11:30 rrule daily
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-daily-two-day.diary-european b/test/lisp/calendar/icalendar-resources/import-rrule-daily-two-day.diary-european
new file mode 100644
index 00000000000..61db14ab24a
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-daily-two-day.diary-european
@@ -0,0 +1 @@
+&%%(and (diary-cyclic 2 19 9 2003)) 09:00-11:30 rrule daily
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-daily-two-day.diary-iso b/test/lisp/calendar/icalendar-resources/import-rrule-daily-two-day.diary-iso
new file mode 100644
index 00000000000..0e0a4b19781
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-daily-two-day.diary-iso
@@ -0,0 +1 @@
+&%%(and (diary-cyclic 2 2003 9 19)) 09:00-11:30 rrule daily
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-daily-two-day.ics b/test/lisp/calendar/icalendar-resources/import-rrule-daily-two-day.ics
new file mode 100644
index 00000000000..8c9cb3b2845
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-daily-two-day.ics
@@ -0,0 +1,10 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+SUMMARY:rrule daily
+DTSTART;VALUE=DATE-TIME:20030919T090000
+DTEND;VALUE=DATE-TIME:20030919T113000
+RRULE:FREQ=DAILY;INTERVAL=2
+END:VEVENT
+END:VCALENDAR
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-daily-with-exceptions.diary-american b/test/lisp/calendar/icalendar-resources/import-rrule-daily-with-exceptions.diary-american
new file mode 100644
index 00000000000..83e5f582d5f
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-daily-with-exceptions.diary-american
@@ -0,0 +1 @@
+&%%(and (not (diary-date 9 25 2003)) (not (diary-date 9 21 2003)) (diary-cyclic 2 9 19 2003)) 09:00-11:30 rrule daily with exceptions
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-daily-with-exceptions.diary-european b/test/lisp/calendar/icalendar-resources/import-rrule-daily-with-exceptions.diary-european
new file mode 100644
index 00000000000..a3c7fdd4177
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-daily-with-exceptions.diary-european
@@ -0,0 +1 @@
+&%%(and (not (diary-date 25 9 2003)) (not (diary-date 21 9 2003)) (diary-cyclic 2 19 9 2003)) 09:00-11:30 rrule daily with exceptions
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-daily-with-exceptions.diary-iso b/test/lisp/calendar/icalendar-resources/import-rrule-daily-with-exceptions.diary-iso
new file mode 100644
index 00000000000..88b4c892d16
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-daily-with-exceptions.diary-iso
@@ -0,0 +1 @@
+&%%(and (not (diary-date 2003 9 25)) (not (diary-date 2003 9 21)) (diary-cyclic 2 2003 9 19)) 09:00-11:30 rrule daily with exceptions
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-daily-with-exceptions.ics b/test/lisp/calendar/icalendar-resources/import-rrule-daily-with-exceptions.ics
new file mode 100644
index 00000000000..5284bf42d8b
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-daily-with-exceptions.ics
@@ -0,0 +1,12 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+SUMMARY:rrule daily with exceptions
+DTSTART;VALUE=DATE-TIME:20030919T090000
+DTEND;VALUE=DATE-TIME:20030919T113000
+RRULE:FREQ=DAILY;INTERVAL=2
+EXDATE:20030921,20030925
+END:VEVENT
+END:VCALENDAR
+
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-daily.diary-american b/test/lisp/calendar/icalendar-resources/import-rrule-daily.diary-american
new file mode 100644
index 00000000000..9213270fa41
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-daily.diary-american
@@ -0,0 +1 @@
+&%%(and (diary-cyclic 1 9 19 2003)) 09:00-11:30 rrule daily
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-daily.diary-european b/test/lisp/calendar/icalendar-resources/import-rrule-daily.diary-european
new file mode 100644
index 00000000000..2c70cd7da55
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-daily.diary-european
@@ -0,0 +1 @@
+&%%(and (diary-cyclic 1 19 9 2003)) 09:00-11:30 rrule daily
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-daily.diary-iso b/test/lisp/calendar/icalendar-resources/import-rrule-daily.diary-iso
new file mode 100644
index 00000000000..b201cb44308
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-daily.diary-iso
@@ -0,0 +1 @@
+&%%(and (diary-cyclic 1 2003 9 19)) 09:00-11:30 rrule daily
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-daily.ics b/test/lisp/calendar/icalendar-resources/import-rrule-daily.ics
new file mode 100644
index 00000000000..6d013b0b4f6
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-daily.ics
@@ -0,0 +1,11 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+SUMMARY:rrule daily
+DTSTART;VALUE=DATE-TIME:20030919T090000
+DTEND;VALUE=DATE-TIME:20030919T113000
+RRULE:FREQ=DAILY;
+END:VEVENT
+END:VCALENDAR
+
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-monthly-no-end.diary-american b/test/lisp/calendar/icalendar-resources/import-rrule-monthly-no-end.diary-american
new file mode 100644
index 00000000000..bc5453fe425
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-monthly-no-end.diary-american
@@ -0,0 +1 @@
+&%%(and (diary-date t 19 t) (diary-block 9 19 2003 1 1 9999)) 09:00-11:30 rrule monthly no end
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-monthly-no-end.diary-european b/test/lisp/calendar/icalendar-resources/import-rrule-monthly-no-end.diary-european
new file mode 100644
index 00000000000..f071519701d
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-monthly-no-end.diary-european
@@ -0,0 +1 @@
+&%%(and (diary-date 19 t t) (diary-block 19 9 2003 1 1 9999)) 09:00-11:30 rrule monthly no end
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-monthly-no-end.diary-iso b/test/lisp/calendar/icalendar-resources/import-rrule-monthly-no-end.diary-iso
new file mode 100644
index 00000000000..3709e933337
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-monthly-no-end.diary-iso
@@ -0,0 +1 @@
+&%%(and (diary-date t t 19) (diary-block 2003 9 19 9999 1 1)) 09:00-11:30 rrule monthly no end
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-monthly-no-end.ics b/test/lisp/calendar/icalendar-resources/import-rrule-monthly-no-end.ics
new file mode 100644
index 00000000000..b871658600a
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-monthly-no-end.ics
@@ -0,0 +1,11 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+SUMMARY:rrule monthly no end
+DTSTART;VALUE=DATE-TIME:20030919T090000
+DTEND;VALUE=DATE-TIME:20030919T113000
+RRULE:FREQ=MONTHLY;
+END:VEVENT
+END:VCALENDAR
+
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-monthly-with-end.diary-american b/test/lisp/calendar/icalendar-resources/import-rrule-monthly-with-end.diary-american
new file mode 100644
index 00000000000..638ab8b2327
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-monthly-with-end.diary-american
@@ -0,0 +1 @@
+&%%(and (diary-date t 19 t) (diary-block 9 19 2003 8 19 2005)) 09:00-11:30 rrule monthly with end
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-monthly-with-end.diary-european b/test/lisp/calendar/icalendar-resources/import-rrule-monthly-with-end.diary-european
new file mode 100644
index 00000000000..c70cde25f32
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-monthly-with-end.diary-european
@@ -0,0 +1 @@
+&%%(and (diary-date 19 t t) (diary-block 19 9 2003 19 8 2005)) 09:00-11:30 rrule monthly with end
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-monthly-with-end.diary-iso b/test/lisp/calendar/icalendar-resources/import-rrule-monthly-with-end.diary-iso
new file mode 100644
index 00000000000..ee51a2142a4
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-monthly-with-end.diary-iso
@@ -0,0 +1 @@
+&%%(and (diary-date t t 19) (diary-block 2003 9 19 2005 8 19)) 09:00-11:30 rrule monthly with end
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-monthly-with-end.ics b/test/lisp/calendar/icalendar-resources/import-rrule-monthly-with-end.ics
new file mode 100644
index 00000000000..d8a1fe2e5af
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-monthly-with-end.ics
@@ -0,0 +1,11 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+SUMMARY:rrule monthly with end
+DTSTART;VALUE=DATE-TIME:20030919T090000
+DTEND;VALUE=DATE-TIME:20030919T113000
+RRULE:FREQ=MONTHLY;UNTIL=20050819;
+END:VEVENT
+END:VCALENDAR
+
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-weekly.diary-american b/test/lisp/calendar/icalendar-resources/import-rrule-weekly.diary-american
new file mode 100644
index 00000000000..d8bf2eba104
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-weekly.diary-american
@@ -0,0 +1 @@
+&%%(and (diary-cyclic 7 9 19 2003)) 09:00-11:30 rrule weekly
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-weekly.diary-european b/test/lisp/calendar/icalendar-resources/import-rrule-weekly.diary-european
new file mode 100644
index 00000000000..e368fde9709
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-weekly.diary-european
@@ -0,0 +1 @@
+&%%(and (diary-cyclic 7 19 9 2003)) 09:00-11:30 rrule weekly
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-weekly.diary-iso b/test/lisp/calendar/icalendar-resources/import-rrule-weekly.diary-iso
new file mode 100644
index 00000000000..49cd9d8ace6
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-weekly.diary-iso
@@ -0,0 +1 @@
+&%%(and (diary-cyclic 7 2003 9 19)) 09:00-11:30 rrule weekly
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-weekly.ics b/test/lisp/calendar/icalendar-resources/import-rrule-weekly.ics
new file mode 100644
index 00000000000..c3f0b8ae933
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-weekly.ics
@@ -0,0 +1,11 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+SUMMARY:rrule weekly
+DTSTART;VALUE=DATE-TIME:20030919T090000
+DTEND;VALUE=DATE-TIME:20030919T113000
+RRULE:FREQ=WEEKLY;
+END:VEVENT
+END:VCALENDAR
+
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-yearly.diary-american b/test/lisp/calendar/icalendar-resources/import-rrule-yearly.diary-american
new file mode 100644
index 00000000000..a54780b9699
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-yearly.diary-american
@@ -0,0 +1 @@
+&%%(and (diary-anniversary 9 19 2003)) 09:00-11:30 rrule yearly
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-yearly.diary-european b/test/lisp/calendar/icalendar-resources/import-rrule-yearly.diary-european
new file mode 100644
index 00000000000..a4bd81d6f2b
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-yearly.diary-european
@@ -0,0 +1 @@
+&%%(and (diary-anniversary 19 9 2003)) 09:00-11:30 rrule yearly
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-yearly.diary-iso b/test/lisp/calendar/icalendar-resources/import-rrule-yearly.diary-iso
new file mode 100644
index 00000000000..65a7abe0344
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-yearly.diary-iso
@@ -0,0 +1 @@
+&%%(and (diary-anniversary 2003 9 19)) 09:00-11:30 rrule yearly
diff --git a/test/lisp/calendar/icalendar-resources/import-rrule-yearly.ics b/test/lisp/calendar/icalendar-resources/import-rrule-yearly.ics
new file mode 100644
index 00000000000..21cca097f7e
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-rrule-yearly.ics
@@ -0,0 +1,11 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+SUMMARY:rrule yearly
+DTSTART;VALUE=DATE-TIME:20030919T090000
+DTEND;VALUE=DATE-TIME:20030919T113000
+RRULE:FREQ=YEARLY;INTERVAL=2
+END:VEVENT
+END:VCALENDAR
+
diff --git a/test/lisp/calendar/icalendar-resources/import-with-timezone.diary-iso b/test/lisp/calendar/icalendar-resources/import-with-timezone.diary-iso
new file mode 100644
index 00000000000..f99b59213e5
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-with-timezone.diary-iso
@@ -0,0 +1,2 @@
+&2012/1/15 15:00-15:30 standardtime
+&2012/12/15 11:00-11:30 daylightsavingtime
diff --git a/test/lisp/calendar/icalendar-resources/import-with-timezone.ics b/test/lisp/calendar/icalendar-resources/import-with-timezone.ics
new file mode 100644
index 00000000000..110a9835e41
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-with-timezone.ics
@@ -0,0 +1,27 @@
+BEGIN:VCALENDAR
+BEGIN:VTIMEZONE
+TZID:fictional, nonexistent, arbitrary
+BEGIN:STANDARD
+DTSTART:20100101T000000
+TZOFFSETFROM:+0200
+TZOFFSETTO:-0200
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=1SU;BYMONTH=01
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:20101201T000000
+TZOFFSETFROM:-0200
+TZOFFSETTO:+0200
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=1SU;BYMONTH=11
+END:DAYLIGHT
+END:VTIMEZONE
+BEGIN:VEVENT
+SUMMARY:standardtime
+DTSTART;TZID="fictional, nonexistent, arbitrary":20120115T120000
+DTEND;TZID="fictional, nonexistent, arbitrary":20120115T123000
+END:VEVENT
+BEGIN:VEVENT
+SUMMARY:daylightsavingtime
+DTSTART;TZID="fictional, nonexistent, arbitrary":20121215T120000
+DTEND;TZID="fictional, nonexistent, arbitrary":20121215T123000
+END:VEVENT
+END:VCALENDAR
diff --git a/test/lisp/calendar/icalendar-resources/import-with-uid.diary-american b/test/lisp/calendar/icalendar-resources/import-with-uid.diary-american
new file mode 100644
index 00000000000..9b2f06afc26
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-with-uid.diary-american
@@ -0,0 +1,2 @@
+&9/19/2003 09:00-11:30 non-recurring
+ UID: 1234567890uid
diff --git a/test/lisp/calendar/icalendar-resources/import-with-uid.diary-european b/test/lisp/calendar/icalendar-resources/import-with-uid.diary-european
new file mode 100644
index 00000000000..95db4d40151
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-with-uid.diary-european
@@ -0,0 +1,2 @@
+&19/9/2003 09:00-11:30 non-recurring
+ UID: 1234567890uid
diff --git a/test/lisp/calendar/icalendar-resources/import-with-uid.diary-iso b/test/lisp/calendar/icalendar-resources/import-with-uid.diary-iso
new file mode 100644
index 00000000000..d372e5a3d1f
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-with-uid.diary-iso
@@ -0,0 +1,2 @@
+&2003/9/19 09:00-11:30 non-recurring
+ UID: 1234567890uid
diff --git a/test/lisp/calendar/icalendar-resources/import-with-uid.ics b/test/lisp/calendar/icalendar-resources/import-with-uid.ics
new file mode 100644
index 00000000000..db412d9d9f5
--- /dev/null
+++ b/test/lisp/calendar/icalendar-resources/import-with-uid.ics
@@ -0,0 +1,10 @@
+BEGIN:VCALENDAR
+PRODID:-//Emacs//NONSGML icalendar.el//EN
+VERSION:2.0
+BEGIN:VEVENT
+UID:1234567890uid
+SUMMARY:non-recurring
+DTSTART;VALUE=DATE-TIME:20030919T090000
+DTEND;VALUE=DATE-TIME:20030919T113000
+END:VEVENT
+END:VCALENDAR
diff --git a/test/lisp/calendar/icalendar-tests.el b/test/lisp/calendar/icalendar-tests.el
index 53fb9ab6cd4..7993a1fd806 100644
--- a/test/lisp/calendar/icalendar-tests.el
+++ b/test/lisp/calendar/icalendar-tests.el
@@ -1,4 +1,4 @@
-;; icalendar-tests.el --- Test suite for icalendar.el
+;; icalendar-tests.el --- Test suite for icalendar.el -*- lexical-binding:t -*-
;; Copyright (C) 2005, 2008-2021 Free Software Foundation, Inc.
@@ -32,6 +32,7 @@
;;; Code:
(require 'ert)
+(require 'ert-x)
(require 'icalendar)
;; ======================================================================
@@ -51,6 +52,15 @@
(replace-regexp-in-string "[ \t\n]+\\'" ""
(replace-regexp-in-string "\\`[ \t\n]+" "" string)))
+(defun icalendar-tests--get-file-contents (filename)
+ "Return contents of file in test data directory named FILENAME."
+ (with-temp-buffer
+ (let ((coding-system-for-read 'raw-text)
+ (inhibit-eol-conversion t))
+ (insert-file-contents-literally
+ (ert-resource-file filename))
+ (buffer-string))))
+
;; ======================================================================
;; Tests of functions
;; ======================================================================
@@ -183,6 +193,7 @@
(ert-deftest icalendar--parse-vtimezone ()
"Test method for `icalendar--parse-vtimezone'."
(let (vtimezone result)
+ ;; testcase: valid timezone with rrule
(setq vtimezone (icalendar-tests--get-ical-event "BEGIN:VTIMEZONE
TZID:thename
BEGIN:STANDARD
@@ -204,6 +215,8 @@ END:VTIMEZONE
(message (cdr result))
(should (string= "STD-02:00DST-03:00,M3.5.0/03:00:00,M10.5.0/04:00:00"
(cdr result)))
+
+ ;; testcase: name of tz contains comma
(setq vtimezone (icalendar-tests--get-ical-event "BEGIN:VTIMEZONE
TZID:anothername, with a comma
BEGIN:STANDARD
@@ -225,7 +238,8 @@ END:VTIMEZONE
(message (cdr result))
(should (string= "STD-02:00DST-03:00,M3.2.1/03:00:00,M10.2.1/04:00:00"
(cdr result)))
- ;; offsetfrom = offsetto
+
+ ;; testcase: offsetfrom = offsetto
(setq vtimezone (icalendar-tests--get-ical-event "BEGIN:VTIMEZONE
TZID:Kolkata, Chennai, Mumbai, New Delhi
X-MICROSOFT-CDO-TZID:23
@@ -245,7 +259,10 @@ END:VTIMEZONE
(should (string= "Kolkata, Chennai, Mumbai, New Delhi" (car result)))
(message (cdr result))
(should (string= "STD-05:30DST-05:30,M1.1.1/00:00:00,M1.1.1/00:00:00"
- (cdr result)))))
+ (cdr result)))
+
+ ;; FIXME: add testcase that covers changes for fix of bug#34315
+ ))
(ert-deftest icalendar--convert-ordinary-to-ical ()
"Test method for `icalendar--convert-ordinary-to-ical'."
@@ -419,11 +436,11 @@ END:VEVENT
")))
(should (string= "SUM sum DES des LOC loc ORG org"
(icalendar--format-ical-event event)))
- (setq icalendar-import-format (lambda (&rest ignore)
+ (setq icalendar-import-format (lambda (&rest _ignore)
"helloworld"))
(should (string= "helloworld" (icalendar--format-ical-event event)))
(setq icalendar-import-format
- (lambda (e)
+ (lambda (event)
(format "-%s-%s-%s-%s-%s-%s-%s-"
(icalendar--get-event-property event 'SUMMARY)
(icalendar--get-event-property event 'DESCRIPTION)
@@ -465,8 +482,7 @@ END:VEVENT
(ert-deftest icalendar--decode-isodatetime ()
"Test `icalendar--decode-isodatetime'."
- (let ((tz (getenv "TZ"))
- result)
+ (let ((tz (getenv "TZ")))
(unwind-protect
(progn
;; Use Eastern European Time (UTC+2, UTC+3 daylight saving)
@@ -483,17 +499,132 @@ END:VEVENT
(should (equal '(0 0 10 1 8 2013 4 t 10800)
(icalendar--decode-isodatetime "20130801T100000")))
+ ;; testcase: no time zone in input, shift by -1 days
+ ;; 1 Jan 2013 10:00 -> 31 Dec 2012
+ (should (equal '(0 0 10 31 12 2012 1 nil 7200)
+ (icalendar--decode-isodatetime "20130101T100000" -1)))
+ ;; 1 Aug 2013 10:00 (DST) -> 31 Jul 2012 (DST)
+ (should (equal '(0 0 10 31 7 2013 3 t 10800)
+ (icalendar--decode-isodatetime "20130801T100000" -1)))
+
+
;; testcase: UTC time zone specifier in input -> convert to local time
- ;; 31 Dec 2013 23:00 UTC -> 1 Jan 2013 01:00 EET
+ ;; 31 Dec 2013 23:00 UTC -> 1 Jan 2014 01:00 EET
(should (equal '(0 0 1 1 1 2014 3 nil 7200)
(icalendar--decode-isodatetime "20131231T230000Z")))
;; 1 Aug 2013 10:00 UTC -> 1 Aug 2013 13:00 EEST
(should (equal '(0 0 13 1 8 2013 4 t 10800)
(icalendar--decode-isodatetime "20130801T100000Z")))
+ ;; testcase: override timezone with Central European Time, 1 Jan 2013 10:00 -> 1 Jan 2013 11:00
+ (should (equal '(0 0 11 1 1 2013 2 nil 7200)
+ (icalendar--decode-isodatetime "20130101T100000" nil
+ '(3600 "CET"))))
+ ;; testcase: override timezone (UTC-02:00), 1 Jan 2013 10:00 -> 1 Jan 2013 14:00
+ (should (equal '(0 0 14 1 1 2013 2 nil 7200)
+ (icalendar--decode-isodatetime "20130101T100000" nil -7200)))
+
+ ;; FIXME: add testcase that covers changes for fix of bug#34315
+
)
;; restore time-zone even if something went terribly wrong
- (setenv "TZ" tz))) )
+ (setenv "TZ" tz))))
+
+(ert-deftest icalendar--convert-tz-offset ()
+ "Test `icalendar--convert-tz-offset'."
+ (let ((tz (getenv "TZ")))
+ (unwind-protect
+ (progn
+ ;; Use Eastern European Time (UTC+2, UTC+3 daylight saving)
+ (setenv "TZ" "EET-2EEST,M3.5.0/3,M10.5.0/4")
+
+ ;; testcase: artificial input
+ (should (equal '("DST-03:00" . "M5.1.1/01:23:45")
+ (icalendar--convert-tz-offset
+ '((DTSTART nil "________T012345") ;
+ (TZOFFSETFROM nil "+0200")
+ (TZOFFSETTO nil "+0300")
+ (RRULE nil "FREQ=YEARLY;INTERVAL=1;BYDAY=1MO;BYMONTH=5"))
+ t)))
+
+ ;; testcase: Europe/Berlin Standard
+ (should (equal '("STD-01:00" . "M10.5.0/03:00:00")
+ (icalendar--convert-tz-offset
+ '((TZOFFSETFROM nil "+0200")
+ (TZOFFSETTO nil "+0100")
+ (TZNAME nil CET)
+ (DTSTART nil "19701025T030000")
+ (RRULE nil "FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU"))
+ nil)))
+
+ ;; testcase: Europe/Berlin DST
+ (should (equal '("DST-02:00" . "M3.5.0/02:00:00")
+ (icalendar--convert-tz-offset
+ '((TZOFFSETFROM nil "+0100")
+ (TZOFFSETTO nil "+0200")
+ (TZNAME nil CEST)
+ (DTSTART nil "19700329T020000")
+ (RRULE nil "FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU"))
+ t)))
+
+ ;; testcase: dtstart is mandatory
+ (should (null (icalendar--convert-tz-offset
+ '((TZOFFSETFROM nil "+0100")
+ (TZOFFSETTO nil "+0200")
+ (RRULE nil "FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU"))
+ t)))
+
+ ;; FIXME: rrule and rdate are NOT mandatory! Must fix code
+ ;; before activating these testcases
+ ;; ;; testcase: no rrule and no rdate => no result
+ ;; (should (null (icalendar--convert-tz-offset
+ ;; '((TZOFFSETFROM nil "+0100")
+ ;; (TZOFFSETTO nil "+0200")
+ ;; (DTSTART nil "19700329T020000"))
+ ;; t)))
+ ;; ;; testcase: no rrule with rdate => no result
+ ;; (should (null (icalendar--convert-tz-offset
+ ;; '((TZOFFSETFROM nil "+0100")
+ ;; (TZOFFSETTO nil "+0200")
+ ;; (DTSTART nil "18840101T000000")
+ ;; (RDATE nil "18840101T000000"))
+ ;; t)))
+ )
+ ;; restore time-zone even if something went terribly wrong
+ (setenv "TZ" tz))))
+
+(ert-deftest icalendar--decode-isoduration ()
+ "Test `icalendar--decode-isoduration'."
+
+ ;; testcase: 7 days
+ (should (equal '(0 0 0 7 0 0)
+ (icalendar--decode-isoduration "P7D")))
+
+ ;; testcase: 7 days, one second -- see bug#34315
+ (should (equal '(1 0 0 7 0 0)
+ (icalendar--decode-isoduration "P7DT1S")))
+
+ ;; testcase: 3 hours, 2 minutes, one second
+ (should (equal '(1 2 3 0 0 0)
+ (icalendar--decode-isoduration "PT3H2M1S")))
+
+ ;; testcase: 99 days, 3 hours, 2 minutes, one second -- see bug#34315
+ (should (equal '(1 2 3 99 0 0)
+ (icalendar--decode-isoduration "P99DT3H2M1S")))
+
+ ;; testcase: 2 weeks
+ (should (equal '(0 0 0 14 0 0)
+ (icalendar--decode-isoduration "P2W")))
+
+ ;; testcase: rfc2445, section 4.3.6: 15 days, 5 hours and 20 seconds -- see bug#34315
+ (should (equal '(20 0 5 15 0 0)
+ (icalendar--decode-isoduration "P15DT5H0M20S")))
+
+ ;; testcase: rfc2445, section 4.3.6: 7 weeks
+ (should (equal '(0 0 0 49 0 0)
+ (icalendar--decode-isoduration "P7W")))
+ )
+
;; ======================================================================
;; Export tests
@@ -842,13 +973,16 @@ END:VALARM
;; Import tests
;; ======================================================================
-(defun icalendar-tests--test-import (input expected-iso expected-european
- expected-american)
+(defun icalendar-tests--test-import (filename expected-iso expected-european
+ expected-american)
"Perform import test.
-Argument INPUT icalendar event string.
-Argument EXPECTED-ISO expected iso style diary string.
-Argument EXPECTED-EUROPEAN expected european style diary string.
-Argument EXPECTED-AMERICAN expected american style diary string.
+Argument FILENAME ics file to import.
+Argument EXPECTED-ISO diary-file containing expected
+iso-calendar-style result.
+Argument EXPECTED-EUROPEAN diary-file containing expected
+european-calendar-style result.
+Argument EXPECTED-AMERICAN diary-file containing expected
+american-calendar-style result.
During import test the timezone is set to Central European Time."
(let ((timezone (getenv "TZ")))
(unwind-protect
@@ -857,14 +991,7 @@ During import test the timezone is set to Central European Time."
;; Eg hydra.nixos.org.
(setenv "TZ" "CET-1CEST,M3.5.0/2,M10.5.0/3")
(with-temp-buffer
- (if (string-match "^BEGIN:VCALENDAR" input)
- (insert input)
- (insert "BEGIN:VCALENDAR\nPRODID:-//Emacs//NONSGML icalendar.el//EN\n")
- (insert "VERSION:2.0\nBEGIN:VEVENT\n")
- (insert input)
- (unless (eq (char-before) ?\n)
- (insert "\n"))
- (insert "END:VEVENT\nEND:VCALENDAR\n"))
+ (insert (icalendar-tests--get-file-contents filename))
(let ((icalendar-import-format "%s%d%l%o%t%u%c%U")
(icalendar-import-format-summary "%s")
(icalendar-import-format-location "\n Location: %s")
@@ -877,26 +1004,29 @@ During import test the timezone is set to Central European Time."
calendar-date-style)
(when expected-iso
(setq calendar-date-style 'iso)
- (icalendar-tests--do-test-import input expected-iso))
+ (icalendar-tests--do-test-import
+ (icalendar-tests--get-file-contents expected-iso)))
(when expected-european
(setq calendar-date-style 'european)
- (icalendar-tests--do-test-import input expected-european))
+ (icalendar-tests--do-test-import
+ (icalendar-tests--get-file-contents expected-european)))
(when expected-american
(setq calendar-date-style 'american)
- (icalendar-tests--do-test-import input expected-american)))))
+ (icalendar-tests--do-test-import
+ (icalendar-tests--get-file-contents expected-american))))))
(setenv "TZ" timezone))))
-(defun icalendar-tests--do-test-import (input expected-output)
+(defun icalendar-tests--do-test-import (expected-output)
"Actually perform import test.
-Argument INPUT input icalendar string.
-Argument EXPECTED-OUTPUT expected diary string."
+Argument EXPECTED-OUTPUT file containing expected diary string."
(let ((temp-file (make-temp-file "icalendar-test-diary")))
;; Test the Catch-the-mysterious-coding-header logic below.
;; Ruby-mode adds an after-save-hook which inserts the header!
;; (save-excursion
;; (find-file temp-file)
;; (ruby-mode))
- (icalendar-import-buffer temp-file t t)
+ (let ((coding-system-for-write 'raw-text))
+ (icalendar-import-buffer temp-file t t))
(save-excursion
(find-file temp-file)
;; Check for the mysterious "# coding: ..." header, remove it
@@ -924,452 +1054,135 @@ Argument EXPECTED-OUTPUT expected diary string."
(ert-deftest icalendar-import-non-recurring ()
"Perform standard import tests."
- (icalendar-tests--test-import
- "SUMMARY:non-recurring
-DTSTART;VALUE=DATE-TIME:20030919T090000
-DTEND;VALUE=DATE-TIME:20030919T113000"
- "&2003/9/19 09:00-11:30 non-recurring\n"
- "&19/9/2003 09:00-11:30 non-recurring\n"
- "&9/19/2003 09:00-11:30 non-recurring\n")
- (icalendar-tests--test-import
- "SUMMARY:non-recurring allday
-DTSTART;VALUE=DATE-TIME:20030919"
- "&2003/9/19 non-recurring allday\n"
- "&19/9/2003 non-recurring allday\n"
- "&9/19/2003 non-recurring allday\n")
- (icalendar-tests--test-import
- ;; Checkdoc removes trailing blanks. Therefore: format!
- (format "%s\n%s\n%s" "SUMMARY:long " " summary"
- "DTSTART;VALUE=DATE:20030919")
- "&2003/9/19 long summary\n"
- "&19/9/2003 long summary\n"
- "&9/19/2003 long summary\n")
- (icalendar-tests--test-import
- "UID:748f2da0-0d9b-11d8-97af-b4ec8686ea61
-SUMMARY:Sommerferien
-STATUS:TENTATIVE
-CLASS:PRIVATE
-X-MOZILLA-ALARM-DEFAULT-UNITS:Minuten
-X-MOZILLA-RECUR-DEFAULT-INTERVAL:0
-DTSTART;VALUE=DATE:20040719
-DTEND;VALUE=DATE:20040828
-DTSTAMP:20031103T011641Z
-"
- "&%%(and (diary-block 2004 7 19 2004 8 27)) Sommerferien
- Status: TENTATIVE
- Class: PRIVATE
- UID: 748f2da0-0d9b-11d8-97af-b4ec8686ea61
-"
- "&%%(and (diary-block 19 7 2004 27 8 2004)) Sommerferien
- Status: TENTATIVE
- Class: PRIVATE
- UID: 748f2da0-0d9b-11d8-97af-b4ec8686ea61
-"
- "&%%(and (diary-block 7 19 2004 8 27 2004)) Sommerferien
- Status: TENTATIVE
- Class: PRIVATE
- UID: 748f2da0-0d9b-11d8-97af-b4ec8686ea61
-")
- (icalendar-tests--test-import
- "UID
- :04979712-3902-11d9-93dd-8f9f4afe08da
-SUMMARY
- :folded summary
-STATUS
- :TENTATIVE
-CLASS
- :PRIVATE
-X-MOZILLA-ALARM-DEFAULT-LENGTH
- :0
-DTSTART
- :20041123T140000
-DTEND
- :20041123T143000
-DTSTAMP
- :20041118T013430Z
-LAST-MODIFIED
- :20041118T013640Z
-"
- "&2004/11/23 14:00-14:30 folded summary
- Status: TENTATIVE
- Class: PRIVATE
- UID: 04979712-3902-11d9-93dd-8f9f4afe08da\n"
- "&23/11/2004 14:00-14:30 folded summary
- Status: TENTATIVE
- Class: PRIVATE
- UID: 04979712-3902-11d9-93dd-8f9f4afe08da\n"
- "&11/23/2004 14:00-14:30 folded summary
- Status: TENTATIVE
- Class: PRIVATE
- UID: 04979712-3902-11d9-93dd-8f9f4afe08da\n")
-
- (icalendar-tests--test-import
- "UID
- :6161a312-3902-11d9-b512-f764153bb28b
-SUMMARY
- :another example
-STATUS
- :TENTATIVE
-CLASS
- :PRIVATE
-X-MOZILLA-ALARM-DEFAULT-LENGTH
- :0
-DTSTART
- :20041123T144500
-DTEND
- :20041123T154500
-DTSTAMP
- :20041118T013641Z
-"
- "&2004/11/23 14:45-15:45 another example
- Status: TENTATIVE
- Class: PRIVATE
- UID: 6161a312-3902-11d9-b512-f764153bb28b\n"
- "&23/11/2004 14:45-15:45 another example
- Status: TENTATIVE
- Class: PRIVATE
- UID: 6161a312-3902-11d9-b512-f764153bb28b\n"
- "&11/23/2004 14:45-15:45 another example
- Status: TENTATIVE
- Class: PRIVATE
- UID: 6161a312-3902-11d9-b512-f764153bb28b\n"))
+ (icalendar-tests--test-import "import-non-recurring-1.ics"
+ "import-non-recurring-1.diary-iso"
+ "import-non-recurring-1.diary-european"
+ "import-non-recurring-1.diary-american")
+ (icalendar-tests--test-import "import-non-recurring-all-day.ics"
+ "import-non-recurring-all-day.diary-iso"
+ "import-non-recurring-all-day.diary-european"
+ "import-non-recurring-all-day.diary-american")
+ (icalendar-tests--test-import "import-non-recurring-long-summary.ics"
+ "import-non-recurring-long-summary.diary-iso"
+ "import-non-recurring-long-summary.diary-european"
+ "import-non-recurring-long-summary.diary-american")
+ (icalendar-tests--test-import "import-non-recurring-block.ics"
+ "import-non-recurring-block.diary-iso"
+ "import-non-recurring-block.diary-european"
+ "import-non-recurring-block.diary-american")
+ (icalendar-tests--test-import "import-non-recurring-folded-summary.ics"
+ "import-non-recurring-folded-summary.diary-iso"
+ "import-non-recurring-folded-summary.diary-european"
+ "import-non-recurring-folded-summary.diary-american")
+ (icalendar-tests--test-import "import-non-recurring-another-example.ics"
+ "import-non-recurring-another-example.diary-iso"
+ "import-non-recurring-another-example.diary-european"
+ "import-non-recurring-another-example.diary-american"))
+
(ert-deftest icalendar-import-rrule ()
- (icalendar-tests--test-import
- "SUMMARY:rrule daily
-DTSTART;VALUE=DATE-TIME:20030919T090000
-DTEND;VALUE=DATE-TIME:20030919T113000
-RRULE:FREQ=DAILY;
-"
- "&%%(and (diary-cyclic 1 2003 9 19)) 09:00-11:30 rrule daily\n"
- "&%%(and (diary-cyclic 1 19 9 2003)) 09:00-11:30 rrule daily\n"
- "&%%(and (diary-cyclic 1 9 19 2003)) 09:00-11:30 rrule daily\n")
- ;; RRULE examples
- (icalendar-tests--test-import
- "SUMMARY:rrule daily
-DTSTART;VALUE=DATE-TIME:20030919T090000
-DTEND;VALUE=DATE-TIME:20030919T113000
-RRULE:FREQ=DAILY;INTERVAL=2
-"
- "&%%(and (diary-cyclic 2 2003 9 19)) 09:00-11:30 rrule daily\n"
- "&%%(and (diary-cyclic 2 19 9 2003)) 09:00-11:30 rrule daily\n"
- "&%%(and (diary-cyclic 2 9 19 2003)) 09:00-11:30 rrule daily\n")
- (icalendar-tests--test-import
- "SUMMARY:rrule daily with exceptions
-DTSTART;VALUE=DATE-TIME:20030919T090000
-DTEND;VALUE=DATE-TIME:20030919T113000
-RRULE:FREQ=DAILY;INTERVAL=2
-EXDATE:20030921,20030925
-"
- "&%%(and (not (diary-date 2003 9 25)) (not (diary-date 2003 9 21)) (diary-cyclic 2 2003 9 19)) 09:00-11:30 rrule daily with exceptions\n"
- "&%%(and (not (diary-date 25 9 2003)) (not (diary-date 21 9 2003)) (diary-cyclic 2 19 9 2003)) 09:00-11:30 rrule daily with exceptions\n"
- "&%%(and (not (diary-date 9 25 2003)) (not (diary-date 9 21 2003)) (diary-cyclic 2 9 19 2003)) 09:00-11:30 rrule daily with exceptions\n")
- (icalendar-tests--test-import
- "SUMMARY:rrule weekly
-DTSTART;VALUE=DATE-TIME:20030919T090000
-DTEND;VALUE=DATE-TIME:20030919T113000
-RRULE:FREQ=WEEKLY;
-"
- "&%%(and (diary-cyclic 7 2003 9 19)) 09:00-11:30 rrule weekly\n"
- "&%%(and (diary-cyclic 7 19 9 2003)) 09:00-11:30 rrule weekly\n"
- "&%%(and (diary-cyclic 7 9 19 2003)) 09:00-11:30 rrule weekly\n")
- (icalendar-tests--test-import
- "SUMMARY:rrule monthly no end
-DTSTART;VALUE=DATE-TIME:20030919T090000
-DTEND;VALUE=DATE-TIME:20030919T113000
-RRULE:FREQ=MONTHLY;
-"
- "&%%(and (diary-date t t 19) (diary-block 2003 9 19 9999 1 1)) 09:00-11:30 rrule monthly no end\n"
- "&%%(and (diary-date 19 t t) (diary-block 19 9 2003 1 1 9999)) 09:00-11:30 rrule monthly no end\n"
- "&%%(and (diary-date t 19 t) (diary-block 9 19 2003 1 1 9999)) 09:00-11:30 rrule monthly no end\n")
- (icalendar-tests--test-import
- "SUMMARY:rrule monthly with end
-DTSTART;VALUE=DATE-TIME:20030919T090000
-DTEND;VALUE=DATE-TIME:20030919T113000
-RRULE:FREQ=MONTHLY;UNTIL=20050819;
-"
- "&%%(and (diary-date t t 19) (diary-block 2003 9 19 2005 8 19)) 09:00-11:30 rrule monthly with end\n"
- "&%%(and (diary-date 19 t t) (diary-block 19 9 2003 19 8 2005)) 09:00-11:30 rrule monthly with end\n"
- "&%%(and (diary-date t 19 t) (diary-block 9 19 2003 8 19 2005)) 09:00-11:30 rrule monthly with end\n")
- (icalendar-tests--test-import
- "DTSTART;VALUE=DATE:20040815
-DTEND;VALUE=DATE:20040816
-SUMMARY:Maria Himmelfahrt
-RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=8
-"
- "&%%(and (diary-anniversary 2004 8 15)) Maria Himmelfahrt\n"
- "&%%(and (diary-anniversary 15 8 2004)) Maria Himmelfahrt\n"
- "&%%(and (diary-anniversary 8 15 2004)) Maria Himmelfahrt\n")
- (icalendar-tests--test-import
- "SUMMARY:rrule yearly
-DTSTART;VALUE=DATE-TIME:20030919T090000
-DTEND;VALUE=DATE-TIME:20030919T113000
-RRULE:FREQ=YEARLY;INTERVAL=2
-"
- "&%%(and (diary-anniversary 2003 9 19)) 09:00-11:30 rrule yearly\n" ;FIXME
- "&%%(and (diary-anniversary 19 9 2003)) 09:00-11:30 rrule yearly\n" ;FIXME
- "&%%(and (diary-anniversary 9 19 2003)) 09:00-11:30 rrule yearly\n") ;FIXME
- (icalendar-tests--test-import
- "SUMMARY:rrule count daily short
-DTSTART;VALUE=DATE-TIME:20030919T090000
-DTEND;VALUE=DATE-TIME:20030919T113000
-RRULE:FREQ=DAILY;COUNT=1;INTERVAL=1
-"
- "&%%(and (diary-cyclic 1 2003 9 19) (diary-block 2003 9 19 2003 9 19)) 09:00-11:30 rrule count daily short\n"
- "&%%(and (diary-cyclic 1 19 9 2003) (diary-block 19 9 2003 19 9 2003)) 09:00-11:30 rrule count daily short\n"
- "&%%(and (diary-cyclic 1 9 19 2003) (diary-block 9 19 2003 9 19 2003)) 09:00-11:30 rrule count daily short\n")
- (icalendar-tests--test-import
- "SUMMARY:rrule count daily long
-DTSTART;VALUE=DATE-TIME:20030919T090000
-DTEND;VALUE=DATE-TIME:20030919T113000
-RRULE:FREQ=DAILY;COUNT=14;INTERVAL=1
-"
- "&%%(and (diary-cyclic 1 2003 9 19) (diary-block 2003 9 19 2003 10 2)) 09:00-11:30 rrule count daily long\n"
- "&%%(and (diary-cyclic 1 19 9 2003) (diary-block 19 9 2003 2 10 2003)) 09:00-11:30 rrule count daily long\n"
- "&%%(and (diary-cyclic 1 9 19 2003) (diary-block 9 19 2003 10 2 2003)) 09:00-11:30 rrule count daily long\n")
- (icalendar-tests--test-import
- "SUMMARY:rrule count bi-weekly 3 times
-DTSTART;VALUE=DATE-TIME:20030919T090000
-DTEND;VALUE=DATE-TIME:20030919T113000
-RRULE:FREQ=WEEKLY;COUNT=3;INTERVAL=2
-"
- "&%%(and (diary-cyclic 14 2003 9 19) (diary-block 2003 9 19 2003 10 31)) 09:00-11:30 rrule count bi-weekly 3 times\n"
- "&%%(and (diary-cyclic 14 19 9 2003) (diary-block 19 9 2003 31 10 2003)) 09:00-11:30 rrule count bi-weekly 3 times\n"
- "&%%(and (diary-cyclic 14 9 19 2003) (diary-block 9 19 2003 10 31 2003)) 09:00-11:30 rrule count bi-weekly 3 times\n")
- (icalendar-tests--test-import
- "SUMMARY:rrule count monthly
-DTSTART;VALUE=DATE-TIME:20030919T090000
-DTEND;VALUE=DATE-TIME:20030919T113000
-RRULE:FREQ=MONTHLY;INTERVAL=1;COUNT=5
-"
- "&%%(and (diary-date t t 19) (diary-block 2003 9 19 2004 1 19)) 09:00-11:30 rrule count monthly\n"
- "&%%(and (diary-date 19 t t) (diary-block 19 9 2003 19 1 2004)) 09:00-11:30 rrule count monthly\n"
- "&%%(and (diary-date t 19 t) (diary-block 9 19 2003 1 19 2004)) 09:00-11:30 rrule count monthly\n")
- (icalendar-tests--test-import
- "SUMMARY:rrule count every second month
-DTSTART;VALUE=DATE-TIME:20030919T090000
-DTEND;VALUE=DATE-TIME:20030919T113000
-RRULE:FREQ=MONTHLY;INTERVAL=2;COUNT=5
-"
- "&%%(and (diary-date t t 19) (diary-block 2003 9 19 2004 5 19)) 09:00-11:30 rrule count every second month\n" ;FIXME
- "&%%(and (diary-date 19 t t) (diary-block 19 9 2003 19 5 2004)) 09:00-11:30 rrule count every second month\n" ;FIXME
- "&%%(and (diary-date t 19 t) (diary-block 9 19 2003 5 19 2004)) 09:00-11:30 rrule count every second month\n") ;FIXME
- (icalendar-tests--test-import
- "SUMMARY:rrule count yearly
-DTSTART;VALUE=DATE-TIME:20030919T090000
-DTEND;VALUE=DATE-TIME:20030919T113000
-RRULE:FREQ=YEARLY;INTERVAL=1;COUNT=5
-"
- "&%%(and (diary-date t 9 19) (diary-block 2003 9 19 2007 9 19)) 09:00-11:30 rrule count yearly\n"
- "&%%(and (diary-date 19 9 t) (diary-block 19 9 2003 19 9 2007)) 09:00-11:30 rrule count yearly\n"
- "&%%(and (diary-date 9 19 t) (diary-block 9 19 2003 9 19 2007)) 09:00-11:30 rrule count yearly\n")
- (icalendar-tests--test-import
- "SUMMARY:rrule count every second year
-DTSTART;VALUE=DATE-TIME:20030919T090000
-DTEND;VALUE=DATE-TIME:20030919T113000
-RRULE:FREQ=YEARLY;INTERVAL=2;COUNT=5
-"
- "&%%(and (diary-date t 9 19) (diary-block 2003 9 19 2011 9 19)) 09:00-11:30 rrule count every second year\n" ;FIXME!!!
- "&%%(and (diary-date 19 9 t) (diary-block 19 9 2003 19 9 2011)) 09:00-11:30 rrule count every second year\n" ;FIXME!!!
- "&%%(and (diary-date 9 19 t) (diary-block 9 19 2003 9 19 2011)) 09:00-11:30 rrule count every second year\n") ;FIXME!!!
-)
+ (icalendar-tests--test-import "import-rrule-daily.ics"
+ "import-rrule-daily.diary-iso"
+ "import-rrule-daily.diary-european"
+ "import-rrule-daily.diary-american")
+ (icalendar-tests--test-import "import-rrule-daily-two-day.ics"
+ "import-rrule-daily-two-day.diary-iso"
+ "import-rrule-daily-two-day.diary-european"
+ "import-rrule-daily-two-day.diary-american")
+ (icalendar-tests--test-import "import-rrule-daily-with-exceptions.ics"
+ "import-rrule-daily-with-exceptions.diary-iso"
+ "import-rrule-daily-with-exceptions.diary-european"
+ "import-rrule-daily-with-exceptions.diary-american")
+ (icalendar-tests--test-import "import-rrule-weekly.ics"
+ "import-rrule-weekly.diary-iso"
+ "import-rrule-weekly.diary-european"
+ "import-rrule-weekly.diary-american")
+ (icalendar-tests--test-import "import-rrule-monthly-no-end.ics"
+ "import-rrule-monthly-no-end.diary-iso"
+ "import-rrule-monthly-no-end.diary-european"
+ "import-rrule-monthly-no-end.diary-american")
+ (icalendar-tests--test-import "import-rrule-monthly-with-end.ics"
+ "import-rrule-monthly-with-end.diary-iso"
+ "import-rrule-monthly-with-end.diary-european"
+ "import-rrule-monthly-with-end.diary-american")
+ (icalendar-tests--test-import "import-rrule-anniversary.ics"
+ "import-rrule-anniversary.diary-iso"
+ "import-rrule-anniversary.diary-european"
+ "import-rrule-anniversary.diary-american")
+ (icalendar-tests--test-import "import-rrule-yearly.ics"
+ "import-rrule-yearly.diary-iso"
+ "import-rrule-yearly.diary-european"
+ "import-rrule-yearly.diary-american")
+ (icalendar-tests--test-import "import-rrule-count-daily-short.ics"
+ "import-rrule-count-daily-short.diary-iso"
+ "import-rrule-count-daily-short.diary-european"
+ "import-rrule-count-daily-short.diary-american")
+ (icalendar-tests--test-import "import-rrule-count-daily-long.ics"
+ "import-rrule-count-daily-long.diary-iso"
+ "import-rrule-count-daily-long.diary-european"
+ "import-rrule-count-daily-long.diary-american")
+ (icalendar-tests--test-import "import-rrule-count-monthly.ics"
+ "import-rrule-count-monthly.diary-iso"
+ "import-rrule-count-monthly.diary-european"
+ "import-rrule-count-monthly.diary-american")
+ (icalendar-tests--test-import "import-rrule-count-every-second-month.ics"
+ "import-rrule-count-every-second-month.diary-iso"
+ "import-rrule-count-every-second-month.diary-european"
+ "import-rrule-count-every-second-month.diary-american")
+ (icalendar-tests--test-import "import-rrule-count-yearly.ics"
+ "import-rrule-count-yearly.diary-iso"
+ "import-rrule-count-yearly.diary-european"
+ "import-rrule-count-yearly.diary-american")
+ (icalendar-tests--test-import "import-rrule-count-every-second-year.ics"
+ "import-rrule-count-every-second-year.diary-iso"
+ "import-rrule-count-every-second-year.diary-european"
+ "import-rrule-count-every-second-year.diary-american")
+ )
(ert-deftest icalendar-import-duration ()
- ;; duration
- (icalendar-tests--test-import
- "DTSTART;VALUE=DATE:20050217
-SUMMARY:duration
-DURATION:P7D
-"
- "&%%(and (diary-block 2005 2 17 2005 2 23)) duration\n"
- "&%%(and (diary-block 17 2 2005 23 2 2005)) duration\n"
- "&%%(and (diary-block 2 17 2005 2 23 2005)) duration\n")
- (icalendar-tests--test-import
- "UID:20041127T183329Z-18215-1001-4536-49109@andromeda
-DTSTAMP:20041127T183315Z
-LAST-MODIFIED:20041127T183329
-SUMMARY:Urlaub
-DTSTART;VALUE=DATE:20011221
-DTEND;VALUE=DATE:20011221
-RRULE:FREQ=DAILY;UNTIL=20011229;INTERVAL=1;WKST=SU
-CLASS:PUBLIC
-SEQUENCE:1
-CREATED:20041127T183329
-"
- "&%%(and (diary-cyclic 1 2001 12 21) (diary-block 2001 12 21 2001 12 29)) Urlaub
- Class: PUBLIC
- UID: 20041127T183329Z-18215-1001-4536-49109@andromeda\n"
- "&%%(and (diary-cyclic 1 21 12 2001) (diary-block 21 12 2001 29 12 2001)) Urlaub
- Class: PUBLIC
- UID: 20041127T183329Z-18215-1001-4536-49109@andromeda\n"
- "&%%(and (diary-cyclic 1 12 21 2001) (diary-block 12 21 2001 12 29 2001)) Urlaub
- Class: PUBLIC
- UID: 20041127T183329Z-18215-1001-4536-49109@andromeda\n"))
+ (icalendar-tests--test-import "import-duration.ics"
+ "import-duration.diary-iso"
+ "import-duration.diary-european"
+ "import-duration.diary-american")
+ ;; duration-2: this is actually an rrule test
+ (icalendar-tests--test-import "import-duration-2.ics"
+ "import-duration-2.diary-iso"
+ "import-duration-2.diary-european"
+ "import-duration-2.diary-american"))
(ert-deftest icalendar-import-bug-6766 ()
;;bug#6766 -- multiple byday values in a weekly rrule
- (icalendar-tests--test-import
-"CLASS:PUBLIC
-DTEND;TZID=America/New_York:20100421T120000
-DTSTAMP:20100525T141214Z
-DTSTART;TZID=America/New_York:20100421T113000
-RRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,WE,TH,FR
-SEQUENCE:1
-STATUS:CONFIRMED
-SUMMARY:Scrum
-TRANSP:OPAQUE
-UID:8814e3f9-7482-408f-996c-3bfe486a1262
-END:VEVENT
-BEGIN:VEVENT
-CLASS:PUBLIC
-DTSTAMP:20100525T141214Z
-DTSTART;VALUE=DATE:20100422
-DTEND;VALUE=DATE:20100423
-RRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=TU,TH
-SEQUENCE:1
-SUMMARY:Tues + Thurs thinking
-TRANSP:OPAQUE
-UID:8814e3f9-7482-408f-996c-3bfe486a1263
-"
-"&%%(and (memq (calendar-day-of-week date) '(1 3 4 5)) (diary-cyclic 1 2010 4 21)) 11:30-12:00 Scrum
- Status: CONFIRMED
- Class: PUBLIC
- UID: 8814e3f9-7482-408f-996c-3bfe486a1262
-&%%(and (memq (calendar-day-of-week date) '(2 4)) (diary-cyclic 1 2010 4 22)) Tues + Thurs thinking
- Class: PUBLIC
- UID: 8814e3f9-7482-408f-996c-3bfe486a1263
-"
-"&%%(and (memq (calendar-day-of-week date) '(1 3 4 5)) (diary-cyclic 1 21 4 2010)) 11:30-12:00 Scrum
- Status: CONFIRMED
- Class: PUBLIC
- UID: 8814e3f9-7482-408f-996c-3bfe486a1262
-&%%(and (memq (calendar-day-of-week date) '(2 4)) (diary-cyclic 1 22 4 2010)) Tues + Thurs thinking
- Class: PUBLIC
- UID: 8814e3f9-7482-408f-996c-3bfe486a1263
-"
-"&%%(and (memq (calendar-day-of-week date) '(1 3 4 5)) (diary-cyclic 1 4 21 2010)) 11:30-12:00 Scrum
- Status: CONFIRMED
- Class: PUBLIC
- UID: 8814e3f9-7482-408f-996c-3bfe486a1262
-&%%(and (memq (calendar-day-of-week date) '(2 4)) (diary-cyclic 1 4 22 2010)) Tues + Thurs thinking
- Class: PUBLIC
- UID: 8814e3f9-7482-408f-996c-3bfe486a1263
-"))
+ (icalendar-tests--test-import "import-bug-6766.ics"
+ "import-bug-6766.diary-iso"
+ "import-bug-6766.diary-european"
+ "import-bug-6766.diary-american"))
(ert-deftest icalendar-import-bug-24199 ()
;;bug#24199 -- monthly rule with byday-clause
- (icalendar-tests--test-import
-"
-SUMMARY:Summary
-DESCRIPTION:Desc
-LOCATION:Loc
-DTSTART:20151202T124600
-DTEND:20151202T160000
-RRULE:FREQ=MONTHLY;BYDAY=1WE;INTERVAL=1
-EXDATE:20160106T114600Z
-EXDATE:20160203T114600Z
-EXDATE:20160302T114600Z
-EXDATE:20160504T104600Z
-EXDATE:20160601T104600Z
-CLASS:DEFAULT
-TRANSP:OPAQUE
-BEGIN:VALARM
-ACTION:DISPLAY
-TRIGGER;VALUE=DURATION:-PT3H
-END:VALARM
-LAST-MODIFIED:20160805T191040Z
-UID:9188710a-08a7-4061-bae3-d4cf4972599a
-"
-"&%%(and (not (diary-date 2016 1 6)) (not (diary-date 2016 2 3)) (not (diary-date 2016 3 2)) (not (diary-date 2016 5 4)) (not (diary-date 2016 6 1)) (diary-float t 3 1) (diary-block 2015 12 2 9999 1 1)) 12:46-16:00 Summary
- Desc: Desc
- Location: Loc
- Class: DEFAULT
- UID: 9188710a-08a7-4061-bae3-d4cf4972599a
-"
-"&%%(and (not (diary-date 6 1 2016)) (not (diary-date 3 2 2016)) (not (diary-date 2 3 2016)) (not (diary-date 4 5 2016)) (not (diary-date 1 6 2016)) (diary-float t 3 1) (diary-block 2 12 2015 1 1 9999)) 12:46-16:00 Summary
- Desc: Desc
- Location: Loc
- Class: DEFAULT
- UID: 9188710a-08a7-4061-bae3-d4cf4972599a
-"
-"&%%(and (not (diary-date 1 6 2016)) (not (diary-date 2 3 2016)) (not (diary-date 3 2 2016)) (not (diary-date 5 4 2016)) (not (diary-date 6 1 2016)) (diary-float t 3 1) (diary-block 12 2 2015 1 1 9999)) 12:46-16:00 Summary
- Desc: Desc
- Location: Loc
- Class: DEFAULT
- UID: 9188710a-08a7-4061-bae3-d4cf4972599a
-"
-))
+ (icalendar-tests--test-import "import-bug-24199.ics"
+ "import-bug-24199.diary-iso"
+ "import-bug-24199.diary-european"
+ "import-bug-24199.diary-american"))
(ert-deftest icalendar-import-bug-33277 ()
;;bug#33277 -- start time equals end time
- (icalendar-tests--test-import
- "DTSTART:20181105T200000Z
-DTSTAMP:20181105T181652Z
-DESCRIPTION:
-LAST-MODIFIED:20181105T181646Z
-LOCATION:
-SEQUENCE:0
-SUMMARY:event with same start/end time
-TRANSP:OPAQUE
-"
-
- "&2018/11/5 21:00 event with same start/end time\n"
- "&5/11/2018 21:00 event with same start/end time\n"
- "&11/5/2018 21:00 event with same start/end time\n"
- ))
+ (icalendar-tests--test-import "import-bug-33277.ics"
+ "import-bug-33277.diary-iso"
+ "import-bug-33277.diary-european"
+ "import-bug-33277.diary-american"))
(ert-deftest icalendar-import-multiple-vcalendars ()
- (icalendar-tests--test-import
- "DTSTART;VALUE=DATE:20110723
-SUMMARY:event-1
-"
- "&2011/7/23 event-1\n"
- "&23/7/2011 event-1\n"
- "&7/23/2011 event-1\n")
-
- (icalendar-tests--test-import
- "BEGIN:VCALENDAR
-PRODID:-//Emacs//NONSGML icalendar.el//EN
-VERSION:2.0\nBEGIN:VEVENT
-DTSTART;VALUE=DATE:20110723
-SUMMARY:event-1
-END:VEVENT
-END:VCALENDAR
-BEGIN:VCALENDAR
-PRODID:-//Emacs//NONSGML icalendar.el//EN
-VERSION:2.0
-BEGIN:VEVENT
-DTSTART;VALUE=DATE:20110724
-SUMMARY:event-2
-END:VEVENT
-END:VCALENDAR
-BEGIN:VCALENDAR
-PRODID:-//Emacs//NONSGML icalendar.el//EN
-VERSION:2.0
-BEGIN:VEVENT
-DTSTART;VALUE=DATE:20110725
-SUMMARY:event-3a
-END:VEVENT
-BEGIN:VEVENT
-DTSTART;VALUE=DATE:20110725
-SUMMARY:event-3b
-END:VEVENT
-END:VCALENDAR
-"
- "&2011/7/23 event-1\n&2011/7/24 event-2\n&2011/7/25 event-3a\n&2011/7/25 event-3b\n"
- "&23/7/2011 event-1\n&24/7/2011 event-2\n&25/7/2011 event-3a\n&25/7/2011 event-3b\n"
- "&7/23/2011 event-1\n&7/24/2011 event-2\n&7/25/2011 event-3a\n&7/25/2011 event-3b\n"))
+ (icalendar-tests--test-import "import-multiple-vcalendars.ics"
+ "import-multiple-vcalendars.diary-iso"
+ "import-multiple-vcalendars.diary-european"
+ "import-multiple-vcalendars.diary-american"))
(ert-deftest icalendar-import-with-uid ()
"Perform import test with uid."
- (icalendar-tests--test-import
- "UID:1234567890uid
-SUMMARY:non-recurring
-DTSTART;VALUE=DATE-TIME:20030919T090000
-DTEND;VALUE=DATE-TIME:20030919T113000"
- "&2003/9/19 09:00-11:30 non-recurring\n UID: 1234567890uid\n"
- "&19/9/2003 09:00-11:30 non-recurring\n UID: 1234567890uid\n"
- "&9/19/2003 09:00-11:30 non-recurring\n UID: 1234567890uid\n"))
+ (icalendar-tests--test-import "import-with-uid.ics"
+ "import-with-uid.diary-iso"
+ "import-with-uid.diary-european"
+ "import-with-uid.diary-american"))
(ert-deftest icalendar-import-with-timezone ()
;; This is known to fail on MS-Windows, because the test assumes
@@ -1378,42 +1191,13 @@ DTEND;VALUE=DATE-TIME:20030919T113000"
:failed
:passed)
;; bug#11473
- (icalendar-tests--test-import
- "BEGIN:VCALENDAR
-BEGIN:VTIMEZONE
-TZID:fictional, nonexistent, arbitrary
-BEGIN:STANDARD
-DTSTART:20100101T000000
-TZOFFSETFROM:+0200
-TZOFFSETTO:-0200
-RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=1SU;BYMONTH=01
-END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:20101201T000000
-TZOFFSETFROM:-0200
-TZOFFSETTO:+0200
-RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=1SU;BYMONTH=11
-END:DAYLIGHT
-END:VTIMEZONE
-BEGIN:VEVENT
-SUMMARY:standardtime
-DTSTART;TZID=\"fictional, nonexistent, arbitrary\":20120115T120000
-DTEND;TZID=\"fictional, nonexistent, arbitrary\":20120115T123000
-END:VEVENT
-BEGIN:VEVENT
-SUMMARY:daylightsavingtime
-DTSTART;TZID=\"fictional, nonexistent, arbitrary\":20121215T120000
-DTEND;TZID=\"fictional, nonexistent, arbitrary\":20121215T123000
-END:VEVENT
-END:VCALENDAR"
- ;; "standardtime" begins first sunday in january and is 4 hours behind CET
- ;; "daylightsavingtime" begins first sunday in november and is 1 hour before CET
- "&2012/1/15 15:00-15:30 standardtime
-&2012/12/15 11:00-11:30 daylightsavingtime
-"
- nil
- nil)
- )
+ ;; "standardtime" begins first sunday in january and is 4 hours behind CET
+ ;; "daylightsavingtime" begins first sunday in november and is 1 hour before CET
+ (icalendar-tests--test-import "import-with-timezone.ics"
+ "import-with-timezone.diary-iso"
+ nil
+ nil))
+
;; ======================================================================
;; Cycle
;; ======================================================================
@@ -1511,237 +1295,27 @@ SUMMARY:and diary-anniversary
:failed
:passed)
;; 2003-05-29
- (icalendar-tests--test-import
- "BEGIN:VCALENDAR
-METHOD:REQUEST
-PRODID:Microsoft CDO for Microsoft Exchange
-VERSION:2.0
-BEGIN:VTIMEZONE
-TZID:Kolkata, Chennai, Mumbai, New Delhi
-X-MICROSOFT-CDO-TZID:23
-BEGIN:STANDARD
-DTSTART:16010101T000000
-TZOFFSETFROM:+0530
-TZOFFSETTO:+0530
-END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:16010101T000000
-TZOFFSETFROM:+0530
-TZOFFSETTO:+0530
-END:DAYLIGHT
-END:VTIMEZONE
-BEGIN:VEVENT
-DTSTAMP:20030509T043439Z
-DTSTART;TZID=\"Kolkata, Chennai, Mumbai, New Delhi\":20030509T103000
-SUMMARY:On-Site Interview
-UID:040000008200E00074C5B7101A82E0080000000080B6DE661216C301000000000000000
- 010000000DB823520692542408ED02D7023F9DFF9
-ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=\"Xxxxx
- xxx Xxxxxxxxxxxx\":MAILTO:xxxxxxxx@xxxxxxx.com
-ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=\"Yyyyyyy Y
- yyyy\":MAILTO:yyyyyyy@yyyyyyy.com
-ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=\"Zzzz Zzzz
- zz\":MAILTO:zzzzzz@zzzzzzz.com
-ORGANIZER;CN=\"Aaaaaa Aaaaa\":MAILTO:aaaaaaa@aaaaaaa.com
-LOCATION:Cccc
-DTEND;TZID=\"Kolkata, Chennai, Mumbai, New Delhi\":20030509T153000
-DESCRIPTION:10:30am - Blah
-SEQUENCE:0
-PRIORITY:5
-CLASS:
-CREATED:20030509T043439Z
-LAST-MODIFIED:20030509T043459Z
-STATUS:CONFIRMED
-TRANSP:OPAQUE
-X-MICROSOFT-CDO-BUSYSTATUS:BUSY
-X-MICROSOFT-CDO-INSTTYPE:0
-X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY
-X-MICROSOFT-CDO-ALLDAYEVENT:FALSE
-X-MICROSOFT-CDO-IMPORTANCE:1
-X-MICROSOFT-CDO-OWNERAPPTID:126441427
-BEGIN:VALARM
-ACTION:DISPLAY
-DESCRIPTION:REMINDER
-TRIGGER;RELATED=START:-PT00H15M00S
-END:VALARM
-END:VEVENT
-END:VCALENDAR"
- nil
- "&9/5/2003 07:00-12:00 On-Site Interview
- Desc: 10:30am - Blah
- Location: Cccc
- Organizer: MAILTO:aaaaaaa@aaaaaaa.com
- Status: CONFIRMED
- UID: 040000008200E00074C5B7101A82E0080000000080B6DE661216C301000000000000000010000000DB823520692542408ED02D7023F9DFF9
-"
- "&5/9/2003 07:00-12:00 On-Site Interview
- Desc: 10:30am - Blah
- Location: Cccc
- Organizer: MAILTO:aaaaaaa@aaaaaaa.com
- Status: CONFIRMED
- UID: 040000008200E00074C5B7101A82E0080000000080B6DE661216C301000000000000000010000000DB823520692542408ED02D7023F9DFF9
-")
+ (icalendar-tests--test-import "import-real-world-2003-05-29.ics"
+ nil
+ "import-real-world-2003-05-29.diary-european"
+ "import-real-world-2003-05-29.diary-american")
;; created with http://apps.marudot.com/ical/
- (icalendar-tests--test-import
- "BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//www.marudot.com//iCal Event Maker
-X-WR-CALNAME:Test
-CALSCALE:GREGORIAN
-BEGIN:VTIMEZONE
-TZID:Asia/Tehran
-TZURL:http://tzurl.org/zoneinfo-outlook/Asia/Tehran
-X-LIC-LOCATION:Asia/Tehran
-BEGIN:STANDARD
-TZOFFSETFROM:+0330
-TZOFFSETTO:+0330
-TZNAME:IRST
-DTSTART:19700101T000000
-END:STANDARD
-END:VTIMEZONE
-BEGIN:VEVENT
-DTSTAMP:20141116T171439Z
-UID:20141116T171439Z-678877132@marudot.com
-DTSTART;TZID=\"Asia/Tehran\":20141116T070000
-DTEND;TZID=\"Asia/Tehran\":20141116T080000
-SUMMARY:NoDST
-DESCRIPTION:Test event from timezone without DST
-LOCATION:Everywhere
-END:VEVENT
-END:VCALENDAR"
- nil
- "&16/11/2014 04:30-05:30 NoDST
- Desc: Test event from timezone without DST
- Location: Everywhere
- UID: 20141116T171439Z-678877132@marudot.com
-"
- "&11/16/2014 04:30-05:30 NoDST
- Desc: Test event from timezone without DST
- Location: Everywhere
- UID: 20141116T171439Z-678877132@marudot.com
-")
-
+ (icalendar-tests--test-import "import-real-world-no-dst.ics"
+ nil
+ "import-real-world-no-dst.diary-european"
+ "import-real-world-no-dst.diary-american")
;; 2003-06-18 a
- (icalendar-tests--test-import
- "DTSTAMP:20030618T195512Z
-DTSTART;TZID=\"Mountain Time (US & Canada)\":20030623T110000
-SUMMARY:Dress Rehearsal for XXXX-XXXX
-UID:040000008200E00074C5B7101A82E00800000000608AA7DA9835C301000000000000000
- 0100000007C3A6D65EE726E40B7F3D69A23BD567E
-ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=\"AAAAA,AAA
- AA (A-AAAAAAA,ex1)\":MAILTO:aaaaa_aaaaa@aaaaa.com
-ORGANIZER;CN=\"ABCD,TECHTRAINING
- (A-Americas,exgen1)\":MAILTO:xxx@xxxxx.com
-LOCATION:555 or TN 555-5555 ID 5555 & NochWas (see below)
-DTEND;TZID=\"Mountain Time (US & Canada)\":20030623T120000
-DESCRIPTION:753 Zeichen hier radiert
-SEQUENCE:0
-PRIORITY:5
-CLASS:
-CREATED:20030618T195518Z
-LAST-MODIFIED:20030618T195527Z
-STATUS:CONFIRMED
-TRANSP:OPAQUE
-X-MICROSOFT-CDO-BUSYSTATUS:BUSY
-X-MICROSOFT-CDO-INSTTYPE:0
-X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY
-X-MICROSOFT-CDO-ALLDAYEVENT:FALSE
-X-MICROSOFT-CDO-IMPORTANCE:1
-X-MICROSOFT-CDO-OWNERAPPTID:1022519251
-BEGIN:VALARM
-ACTION:DISPLAY
-DESCRIPTION:REMINDER
-TRIGGER;RELATED=START:-PT00H15M00S
-END:VALARM"
- nil
- "&23/6/2003 11:00-12:00 Dress Rehearsal for XXXX-XXXX
- Desc: 753 Zeichen hier radiert
- Location: 555 or TN 555-5555 ID 5555 & NochWas (see below)
- Organizer: MAILTO:xxx@xxxxx.com
- Status: CONFIRMED
- UID: 040000008200E00074C5B7101A82E00800000000608AA7DA9835C3010000000000000000100000007C3A6D65EE726E40B7F3D69A23BD567E
-"
- "&6/23/2003 11:00-12:00 Dress Rehearsal for XXXX-XXXX
- Desc: 753 Zeichen hier radiert
- Location: 555 or TN 555-5555 ID 5555 & NochWas (see below)
- Organizer: MAILTO:xxx@xxxxx.com
- Status: CONFIRMED
- UID: 040000008200E00074C5B7101A82E00800000000608AA7DA9835C3010000000000000000100000007C3A6D65EE726E40B7F3D69A23BD567E
-")
+ (icalendar-tests--test-import "import-real-world-2003-06-18a.ics"
+ nil
+ "import-real-world-2003-06-18a.diary-european"
+ "import-real-world-2003-06-18a.diary-american")
;; 2003-06-18 b -- uses timezone
- (icalendar-tests--test-import
- "BEGIN:VCALENDAR
-METHOD:REQUEST
-PRODID:Microsoft CDO for Microsoft Exchange
-VERSION:2.0
-BEGIN:VTIMEZONE
-TZID:Mountain Time (US & Canada)
-X-MICROSOFT-CDO-TZID:12
-BEGIN:STANDARD
-DTSTART:16010101T020000
-TZOFFSETFROM:-0600
-TZOFFSETTO:-0700
-RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=10;BYDAY=-1SU
-END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:16010101T020000
-TZOFFSETFROM:-0700
-TZOFFSETTO:-0600
-RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=4;BYDAY=1SU
-END:DAYLIGHT
-END:VTIMEZONE
-BEGIN:VEVENT
-DTSTAMP:20030618T230323Z
-DTSTART;TZID=\"Mountain Time (US & Canada)\":20030623T090000
-SUMMARY:Updated: Dress Rehearsal for ABC01-15
-UID:040000008200E00074C5B7101A82E00800000000608AA7DA9835C301000000000000000
- 0100000007C3A6D65EE726E40B7F3D69A23BD567E
-ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;X-REPLYTIME=20030618T20
- 0700Z;RSVP=TRUE;CN=\"AAAAA,AAAAAA
-\(A-AAAAAAA,ex1)\":MAILTO:aaaaaa_aaaaa@aaaaa
- .com
-ORGANIZER;CN=\"ABCD,TECHTRAINING
-\(A-Americas,exgen1)\":MAILTO:bbb@bbbbb.com
-LOCATION:123 or TN 123-1234 ID abcd & SonstWo (see below)
-DTEND;TZID=\"Mountain Time (US & Canada)\":20030623T100000
-DESCRIPTION:Viele Zeichen standen hier früher
-SEQUENCE:0
-PRIORITY:5
-CLASS:
-CREATED:20030618T230326Z
-LAST-MODIFIED:20030618T230335Z
-STATUS:CONFIRMED
-TRANSP:OPAQUE
-X-MICROSOFT-CDO-BUSYSTATUS:BUSY
-X-MICROSOFT-CDO-INSTTYPE:0
-X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY
-X-MICROSOFT-CDO-ALLDAYEVENT:FALSE
-X-MICROSOFT-CDO-IMPORTANCE:1
-X-MICROSOFT-CDO-OWNERAPPTID:1022519251
-BEGIN:VALARM
-ACTION:DISPLAY
-DESCRIPTION:REMINDER
-TRIGGER;RELATED=START:-PT00H15M00S
-END:VALARM
-END:VEVENT
-END:VCALENDAR"
- nil
- "&23/6/2003 17:00-18:00 Updated: Dress Rehearsal for ABC01-15
- Desc: Viele Zeichen standen hier früher
- Location: 123 or TN 123-1234 ID abcd & SonstWo (see below)
- Organizer: MAILTO:bbb@bbbbb.com
- Status: CONFIRMED
- UID: 040000008200E00074C5B7101A82E00800000000608AA7DA9835C3010000000000000000100000007C3A6D65EE726E40B7F3D69A23BD567E
-"
- "&6/23/2003 17:00-18:00 Updated: Dress Rehearsal for ABC01-15
- Desc: Viele Zeichen standen hier früher
- Location: 123 or TN 123-1234 ID abcd & SonstWo (see below)
- Organizer: MAILTO:bbb@bbbbb.com
- Status: CONFIRMED
- UID: 040000008200E00074C5B7101A82E00800000000608AA7DA9835C3010000000000000000100000007C3A6D65EE726E40B7F3D69A23BD567E
-")
+ (icalendar-tests--test-import "import-real-world-2003-06-18b.ics"
+ nil
+ "import-real-world-2003-06-18b.diary-european"
+ "import-real-world-2003-06-18b.diary-american")
;; export 2004-10-28 block entries
(icalendar-tests--test-export
nil
@@ -1957,169 +1531,10 @@ DTEND;VALUE=DATE-TIME:20041012T150000
SUMMARY:Tue: [2004-10-12] q1")
;; 2004-11-19
- (icalendar-tests--test-import
- "BEGIN:VCALENDAR
-VERSION
- :2.0
-PRODID
- :-//Mozilla.org/NONSGML Mozilla Calendar V1.0//EN
-BEGIN:VEVENT
-SUMMARY
- :Jjjjj & Wwwww
-STATUS
- :TENTATIVE
-CLASS
- :PRIVATE
-X-MOZILLA-ALARM-DEFAULT-LENGTH
- :0
-DTSTART
- :20041123T140000
-DTEND
- :20041123T143000
-DTSTAMP
- :20041118T013430Z
-LAST-MODIFIED
- :20041118T013640Z
-END:VEVENT
-BEGIN:VEVENT
-SUMMARY
- :BB Aaaaaaaa Bbbbb
-STATUS
- :TENTATIVE
-CLASS
- :PRIVATE
-X-MOZILLA-ALARM-DEFAULT-LENGTH
- :0
-DTSTART
- :20041123T144500
-DTEND
- :20041123T154500
-DTSTAMP
- :20041118T013641Z
-END:VEVENT
-BEGIN:VEVENT
-SUMMARY
- :Hhhhhhhh
-STATUS
- :TENTATIVE
-CLASS
- :PRIVATE
-X-MOZILLA-ALARM-DEFAULT-LENGTH
- :0
-DTSTART
- :20041123T110000
-DTEND
- :20041123T120000
-DTSTAMP
- :20041118T013831Z
-END:VEVENT
-BEGIN:VEVENT
-SUMMARY
- :MMM Aaaaaaaaa
-STATUS
- :TENTATIVE
-CLASS
- :PRIVATE
-X-MOZILLA-ALARM-DEFAULT-LENGTH
- :0
-X-MOZILLA-RECUR-DEFAULT-INTERVAL
- :2
-RRULE
- :FREQ=WEEKLY;INTERVAL=2;BYDAY=FR
-DTSTART
- :20041112T140000
-DTEND
- :20041112T183000
-DTSTAMP
- :20041118T014117Z
-END:VEVENT
-BEGIN:VEVENT
-SUMMARY
- :Rrrr/Cccccc ii Aaaaaaaa
-DESCRIPTION
- :Vvvvv Rrrr aaa Cccccc
-STATUS
- :TENTATIVE
-CLASS
- :PRIVATE
-X-MOZILLA-ALARM-DEFAULT-LENGTH
- :0
-DTSTART
- ;VALUE=DATE
- :20041119
-DTEND
- ;VALUE=DATE
- :20041120
-DTSTAMP
- :20041118T013107Z
-LAST-MODIFIED
- :20041118T014203Z
-END:VEVENT
-BEGIN:VEVENT
-SUMMARY
- :Wwww aa hhhh
-STATUS
- :TENTATIVE
-CLASS
- :PRIVATE
-X-MOZILLA-ALARM-DEFAULT-LENGTH
- :0
-RRULE
- :FREQ=WEEKLY;INTERVAL=1;BYDAY=MO
-DTSTART
- ;VALUE=DATE
- :20041101
-DTEND
- ;VALUE=DATE
- :20041102
-DTSTAMP
- :20041118T014045Z
-LAST-MODIFIED
- :20041118T023846Z
-END:VEVENT
-END:VCALENDAR
-"
- nil
- "&23/11/2004 14:00-14:30 Jjjjj & Wwwww
- Status: TENTATIVE
- Class: PRIVATE
-&23/11/2004 14:45-15:45 BB Aaaaaaaa Bbbbb
- Status: TENTATIVE
- Class: PRIVATE
-&23/11/2004 11:00-12:00 Hhhhhhhh
- Status: TENTATIVE
- Class: PRIVATE
-&%%(and (diary-cyclic 14 12 11 2004)) 14:00-18:30 MMM Aaaaaaaaa
- Status: TENTATIVE
- Class: PRIVATE
-&%%(and (diary-block 19 11 2004 19 11 2004)) Rrrr/Cccccc ii Aaaaaaaa
- Desc: Vvvvv Rrrr aaa Cccccc
- Status: TENTATIVE
- Class: PRIVATE
-&%%(and (diary-cyclic 7 1 11 2004)) Wwww aa hhhh
- Status: TENTATIVE
- Class: PRIVATE
-"
- "&11/23/2004 14:00-14:30 Jjjjj & Wwwww
- Status: TENTATIVE
- Class: PRIVATE
-&11/23/2004 14:45-15:45 BB Aaaaaaaa Bbbbb
- Status: TENTATIVE
- Class: PRIVATE
-&11/23/2004 11:00-12:00 Hhhhhhhh
- Status: TENTATIVE
- Class: PRIVATE
-&%%(and (diary-cyclic 14 11 12 2004)) 14:00-18:30 MMM Aaaaaaaaa
- Status: TENTATIVE
- Class: PRIVATE
-&%%(and (diary-block 11 19 2004 11 19 2004)) Rrrr/Cccccc ii Aaaaaaaa
- Desc: Vvvvv Rrrr aaa Cccccc
- Status: TENTATIVE
- Class: PRIVATE
-&%%(and (diary-cyclic 7 11 1 2004)) Wwww aa hhhh
- Status: TENTATIVE
- Class: PRIVATE
-")
+ (icalendar-tests--test-import "import-real-world-2004-11-19.ics"
+ nil
+ "import-real-world-2004-11-19.diary-european"
+ "import-real-world-2004-11-19.diary-american")
;; 2004-09-09 pg
(icalendar-tests--test-export
@@ -2149,53 +1564,16 @@ DTEND;VALUE=DATE-TIME:20041102T163000
SUMMARY:Zahnarzt")
;; 2005-02-07 lt
- (icalendar-tests--test-import
- "UID
- :b60d398e-1dd1-11b2-a159-cf8cb05139f4
-SUMMARY
- :Waitangi Day
-DESCRIPTION
- :abcdef
-CATEGORIES
- :Public Holiday
-STATUS
- :CONFIRMED
-CLASS
- :PRIVATE
-DTSTART
- ;VALUE=DATE
- :20050206
-DTEND
- ;VALUE=DATE
- :20050207
-DTSTAMP
- :20050128T011209Z"
- nil
- "&%%(and (diary-block 6 2 2005 6 2 2005)) Waitangi Day
- Desc: abcdef
- Status: CONFIRMED
- Class: PRIVATE
- UID: b60d398e-1dd1-11b2-a159-cf8cb05139f4
-"
- "&%%(and (diary-block 2 6 2005 2 6 2005)) Waitangi Day
- Desc: abcdef
- Status: CONFIRMED
- Class: PRIVATE
- UID: b60d398e-1dd1-11b2-a159-cf8cb05139f4
-")
+ (icalendar-tests--test-import "import-real-world-2005-02-07.ics"
+ nil
+ "import-real-world-2005-02-07.diary-european"
+ "import-real-world-2005-02-07.diary-american")
;; 2005-03-01 lt
- (icalendar-tests--test-import
- "DTSTART;VALUE=DATE:20050217
-SUMMARY:Hhhhhh Aaaaa ii Aaaaaaaa
-UID:6AFA7558-6994-11D9-8A3A-000A95A0E830-RID
-DTSTAMP:20050118T210335Z
-DURATION:P7D"
- nil
- "&%%(and (diary-block 17 2 2005 23 2 2005)) Hhhhhh Aaaaa ii Aaaaaaaa
- UID: 6AFA7558-6994-11D9-8A3A-000A95A0E830-RID\n"
- "&%%(and (diary-block 2 17 2005 2 23 2005)) Hhhhhh Aaaaa ii Aaaaaaaa
- UID: 6AFA7558-6994-11D9-8A3A-000A95A0E830-RID\n")
+ (icalendar-tests--test-import "import-real-world-2005-03-01.ics"
+ nil
+ "import-real-world-2005-03-01.diary-european"
+ "import-real-world-2005-03-01.diary-american")
;; 2005-03-23 lt
(icalendar-tests--test-export
@@ -2222,132 +1600,24 @@ SUMMARY:NNN Wwwwwwww Wwwww - Aaaaaa Pppppppp rrrrrr ddd oo Nnnnnnnn 30
")
;; bug#11473
- (icalendar-tests--test-import
- "BEGIN:VCALENDAR
-METHOD:REQUEST
-PRODID:Microsoft Exchange Server 2007
-VERSION:2.0
-BEGIN:VTIMEZONE
-TZID:(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna
-BEGIN:STANDARD
-DTSTART:16010101T030000
-TZOFFSETFROM:+0200
-TZOFFSETTO:+0100
-RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=10
-END:STANDARD
-BEGIN:DAYLIGHT
-DTSTART:16010101T020000
-TZOFFSETFROM:+0100
-TZOFFSETTO:+0200
-RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=3
-END:DAYLIGHT
-END:VTIMEZONE
-BEGIN:VEVENT
-ORGANIZER;CN=\"A. Luser\":MAILTO:a.luser@foo.com
-ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=\"Luser, Oth
- er\":MAILTO:other.luser@foo.com
-DESCRIPTION;LANGUAGE=en-US:\nWhassup?\n\n
-SUMMARY;LANGUAGE=en-US:Query
-DTSTART;TZID=\"(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna\"
- :20120515T150000
-DTEND;TZID=\"(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna\":2
- 0120515T153000
-UID:040000008200E00074C5B7101A82E0080000000020FFAED0CFEFCC01000000000000000
- 010000000575268034ECDB649A15349B1BF240F15
-RECURRENCE-ID;TZID=\"(UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, V
- ienna\":20120515T170000
-CLASS:PUBLIC
-PRIORITY:5
-DTSTAMP:20120514T153645Z
-TRANSP:OPAQUE
-STATUS:CONFIRMED
-SEQUENCE:15
-LOCATION;LANGUAGE=en-US:phone
-X-MICROSOFT-CDO-APPT-SEQUENCE:15
-X-MICROSOFT-CDO-OWNERAPPTID:1907632092
-X-MICROSOFT-CDO-BUSYSTATUS:TENTATIVE
-X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY
-X-MICROSOFT-CDO-ALLDAYEVENT:FALSE
-X-MICROSOFT-CDO-IMPORTANCE:1
-X-MICROSOFT-CDO-INSTTYPE:3
-BEGIN:VALARM
-ACTION:DISPLAY
-DESCRIPTION:REMINDER
-TRIGGER;RELATED=START:-PT15M
-END:VALARM
-END:VEVENT
-END:VCALENDAR"
- nil
- "&15/5/2012 15:00-15:30 Query
- Location: phone
- Organizer: MAILTO:a.luser@foo.com
- Status: CONFIRMED
- Class: PUBLIC
- UID: 040000008200E00074C5B7101A82E0080000000020FFAED0CFEFCC01000000000000000010000000575268034ECDB649A15349B1BF240F15
-" nil)
+ (icalendar-tests--test-import "import-bug-11473.ics"
+ nil
+ "import-bug-11473.diary-european"
+ nil)
;; 2015-12-05, mixed line endings and empty lines, see Bug#22092.
- (icalendar-tests--test-import
- "BEGIN:VCALENDAR\r
-PRODID:-//www.norwegian.no//iCalendar MIMEDIR//EN\r
-VERSION:2.0\r
-METHOD:REQUEST\r
-BEGIN:VEVENT\r
-UID:RFCALITEM1\r
-SEQUENCE:1512040950\r
-DTSTAMP:20141204T095043Z\r
-ORGANIZER:noreply@norwegian.no\r
-DTSTART:20141208T173000Z\r
-
-DTEND:20141208T215500Z\r
-
-LOCATION:Stavanger-Sola\r
-
-DESCRIPTION:Fly med Norwegian, reservasjon. Fra Stavanger til Troms&#248; 8. des 2014 18:30, DY545Fly med Norwegian, reservasjon . Fra Stavanger til Troms&#248; 8. des 2014 21:00, DY390\r
-
-X-ALT-DESC;FMTTYPE=text/html:<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\"><html><head><META NAME=\"Generator\" CONTENT=\"MS Exchange Server version 08.00.0681.000\"><title></title></head><body><b><font face=\"Calibri\" size=\"3\">Reisereferanse</p></body></html>
-SUMMARY:Norwegian til Tromsoe-Langnes -\r
-
-CATEGORIES:Appointment\r
-
-
-PRIORITY:5\r
-
-CLASS:PUBLIC\r
-
-TRANSP:OPAQUE\r
-END:VEVENT\r
-END:VCALENDAR
-"
-"&2014/12/8 18:30-22:55 Norwegian til Tromsoe-Langnes -
- Desc: Fly med Norwegian, reservasjon. Fra Stavanger til Troms&#248; 8. des 2014 18:30, DY545Fly med Norwegian, reservasjon . Fra Stavanger til Troms&#248; 8. des 2014 21:00, DY390
- Location: Stavanger-Sola
- Organizer: noreply@norwegian.no
- Class: PUBLIC
- UID: RFCALITEM1
-"
-"&8/12/2014 18:30-22:55 Norwegian til Tromsoe-Langnes -
- Desc: Fly med Norwegian, reservasjon. Fra Stavanger til Troms&#248; 8. des 2014 18:30, DY545Fly med Norwegian, reservasjon . Fra Stavanger til Troms&#248; 8. des 2014 21:00, DY390
- Location: Stavanger-Sola
- Organizer: noreply@norwegian.no
- Class: PUBLIC
- UID: RFCALITEM1
-"
-"&12/8/2014 18:30-22:55 Norwegian til Tromsoe-Langnes -
- Desc: Fly med Norwegian, reservasjon. Fra Stavanger til Troms&#248; 8. des 2014 18:30, DY545Fly med Norwegian, reservasjon . Fra Stavanger til Troms&#248; 8. des 2014 21:00, DY390
- Location: Stavanger-Sola
- Organizer: noreply@norwegian.no
- Class: PUBLIC
- UID: RFCALITEM1
-"
-)
- )
+ (icalendar-tests--test-import "import-bug-22092.ics"
+ "import-bug-22092.diary-iso"
+ "import-bug-22092.diary-european"
+ "import-bug-22092.diary-american"))
(defun icalendar-test--format (string &optional day zone)
+ "Decode and format STRING with DAY and ZONE."
(let ((time (icalendar--decode-isodatetime string day zone)))
(format-time-string "%FT%T%z" (encode-time time) 0)))
-(defun icalendar-tests--decode-isodatetime (ical-string)
+(defun icalendar-tests--decode-isodatetime (_ical-string)
+ "Test icalendar--decode-isodatetime."
(should (equal (icalendar-test--format "20040917T050910-0200")
"2004-09-17T03:09:10+0000"))
(should (equal (icalendar-test--format "20040917T050910")
diff --git a/test/lisp/calendar/iso8601-tests.el b/test/lisp/calendar/iso8601-tests.el
index 44485381f07..618e5b12386 100644
--- a/test/lisp/calendar/iso8601-tests.el
+++ b/test/lisp/calendar/iso8601-tests.el
@@ -24,49 +24,61 @@
(ert-deftest test-iso8601-date-years ()
(should (equal (iso8601-parse-date "1985")
- '(nil nil nil nil nil 1985 nil nil nil)))
+ '(nil nil nil nil nil 1985 nil -1 nil)))
(should (equal (iso8601-parse-date "-0003")
- '(nil nil nil nil nil -3 nil nil nil)))
+ '(nil nil nil nil nil -3 nil -1 nil)))
(should (equal (iso8601-parse-date "+1985")
- '(nil nil nil nil nil 1985 nil nil nil))))
+ '(nil nil nil nil nil 1985 nil -1 nil))))
(ert-deftest test-iso8601-date-dates ()
(should (equal (iso8601-parse-date "1985-03-14")
- '(nil nil nil 14 3 1985 nil nil nil)))
+ '(nil nil nil 14 3 1985 nil -1 nil)))
(should (equal (iso8601-parse-date "19850314")
- '(nil nil nil 14 3 1985 nil nil nil)))
+ '(nil nil nil 14 3 1985 nil -1 nil)))
(should (equal (iso8601-parse-date "1985-02")
- '(nil nil nil nil 2 1985 nil nil nil))))
+ '(nil nil nil nil 2 1985 nil -1 nil))))
(ert-deftest test-iso8601-date-obsolete ()
(should (equal (iso8601-parse-date "--02-01")
- '(nil nil nil 1 2 nil nil nil nil)))
+ '(nil nil nil 1 2 nil nil -1 nil)))
(should (equal (iso8601-parse-date "--0201")
- '(nil nil nil 1 2 nil nil nil nil))))
+ '(nil nil nil 1 2 nil nil -1 nil))))
+
+(ert-deftest test-iso8601-date-obsolete-2000 ()
+ ;; These are forms in 5.2.1.3 of the 2000 version of the standard,
+ ;; e) and f).
+ (should (equal (iso8601-parse-date "--12")
+ '(nil nil nil nil 12 nil nil -1 nil)))
+ (should (equal (iso8601-parse "--12T14")
+ '(0 0 14 nil 12 nil nil -1 nil)))
+ (should (equal (iso8601-parse-date "---12")
+ '(nil nil nil 12 nil nil nil -1 nil)))
+ (should (equal (iso8601-parse "---12T14:10:12")
+ '(12 10 14 12 nil nil nil -1 nil))))
(ert-deftest test-iso8601-date-weeks ()
(should (equal (iso8601-parse-date "2008W39-6")
- '(nil nil nil 27 9 2008 nil nil nil)))
+ '(nil nil nil 27 9 2008 nil -1 nil)))
(should (equal (iso8601-parse-date "2009W01-1")
- '(nil nil nil 29 12 2008 nil nil nil)))
+ '(nil nil nil 29 12 2008 nil -1 nil)))
(should (equal (iso8601-parse-date "2009W53-7")
- '(nil nil nil 3 1 2010 nil nil nil))))
+ '(nil nil nil 3 1 2010 nil -1 nil))))
(ert-deftest test-iso8601-date-ordinals ()
(should (equal (iso8601-parse-date "1981-095")
- '(nil nil nil 5 4 1981 nil nil nil))))
+ '(nil nil nil 5 4 1981 nil -1 nil))))
(ert-deftest test-iso8601-time ()
(should (equal (iso8601-parse-time "13:47:30")
- '(30 47 13 nil nil nil nil nil nil)))
+ '(30 47 13 nil nil nil nil -1 nil)))
(should (equal (iso8601-parse-time "134730")
- '(30 47 13 nil nil nil nil nil nil)))
+ '(30 47 13 nil nil nil nil -1 nil)))
(should (equal (iso8601-parse-time "1347")
- '(0 47 13 nil nil nil nil nil nil))))
+ '(0 47 13 nil nil nil nil -1 nil))))
(ert-deftest test-iso8601-combined ()
(should (equal (iso8601-parse "2008-03-02T13:47:30")
- '(30 47 13 2 3 2008 nil nil nil)))
+ '(30 47 13 2 3 2008 nil -1 nil)))
(should (equal (iso8601-parse "2008-03-02T13:47:30Z")
'(30 47 13 2 3 2008 nil nil 0)))
(should (equal (iso8601-parse "2008-03-02T13:47:30+01:00")
@@ -76,13 +88,13 @@
(ert-deftest test-iso8601-duration ()
(should (equal (iso8601-parse-duration "P3Y6M4DT12H30M5S")
- '(5 30 12 4 6 3 nil nil nil)))
+ '(5 30 12 4 6 3 nil -1 nil)))
(should (equal (iso8601-parse-duration "P1M")
- '(0 0 0 0 1 0 nil nil nil)))
+ '(0 0 0 0 1 0 nil -1 nil)))
(should (equal (iso8601-parse-duration "PT1M")
- '(0 1 0 0 0 0 nil nil nil)))
+ '(0 1 0 0 0 0 nil -1 nil)))
(should (equal (iso8601-parse-duration "P0003-06-04T12:30:05")
- '(5 30 12 4 6 3 nil nil nil))))
+ '(5 30 12 4 6 3 nil -1 nil))))
(ert-deftest test-iso8601-invalid ()
(should-not (iso8601-valid-p " 2008-03-02T13:47:30-01"))
@@ -101,88 +113,88 @@
(should (equal (iso8601-parse-interval "2007-03-01T13:00:00Z/P1Y2M10DT2H30M")
'((0 0 13 1 3 2007 nil nil 0)
(0 30 15 11 5 2008 nil nil 0)
- (0 30 2 10 2 1 nil nil nil))))
+ (0 30 2 10 2 1 nil -1 nil))))
(should (equal (iso8601-parse-interval "P1Y2M10DT2H30M/2008-05-11T15:30:00Z")
'((0 0 13 1 3 2007 nil nil 0)
(0 30 15 11 5 2008 nil nil 0)
- (0 30 2 10 2 1 nil nil nil)))))
+ (0 30 2 10 2 1 nil -1 nil)))))
(ert-deftest standard-test-dates ()
(should (equal (iso8601-parse-date "19850412")
- '(nil nil nil 12 4 1985 nil nil nil)))
+ '(nil nil nil 12 4 1985 nil -1 nil)))
(should (equal (iso8601-parse-date "1985-04-12")
- '(nil nil nil 12 4 1985 nil nil nil)))
+ '(nil nil nil 12 4 1985 nil -1 nil)))
(should (equal (iso8601-parse-date "1985102")
- '(nil nil nil 12 4 1985 nil nil nil)))
+ '(nil nil nil 12 4 1985 nil -1 nil)))
(should (equal (iso8601-parse-date "1985-102")
- '(nil nil nil 12 4 1985 nil nil nil)))
+ '(nil nil nil 12 4 1985 nil -1 nil)))
(should (equal (iso8601-parse-date "1985W155")
- '(nil nil nil 12 4 1985 nil nil nil)))
+ '(nil nil nil 12 4 1985 nil -1 nil)))
(should (equal (iso8601-parse-date "1985-W15-5")
- '(nil nil nil 12 4 1985 nil nil nil)))
+ '(nil nil nil 12 4 1985 nil -1 nil)))
(should (equal (iso8601-parse-date "1985W15")
- '(nil nil nil 7 4 1985 nil nil nil)))
+ '(nil nil nil 7 4 1985 nil -1 nil)))
(should (equal (iso8601-parse-date "1985-W15")
- '(nil nil nil 7 4 1985 nil nil nil)))
+ '(nil nil nil 7 4 1985 nil -1 nil)))
(should (equal (iso8601-parse-date "1985-04")
- '(nil nil nil nil 4 1985 nil nil nil)))
+ '(nil nil nil nil 4 1985 nil -1 nil)))
(should (equal (iso8601-parse-date "1985")
- '(nil nil nil nil nil 1985 nil nil nil)))
+ '(nil nil nil nil nil 1985 nil -1 nil)))
(should (equal (iso8601-parse-date "+1985-04-12")
- '(nil nil nil 12 4 1985 nil nil nil)))
+ '(nil nil nil 12 4 1985 nil -1 nil)))
(should (equal (iso8601-parse-date "+19850412")
- '(nil nil nil 12 4 1985 nil nil nil))))
+ '(nil nil nil 12 4 1985 nil -1 nil))))
(ert-deftest standard-test-time-of-day-local-time ()
(should (equal (iso8601-parse-time "152746")
- '(46 27 15 nil nil nil nil nil nil)))
+ '(46 27 15 nil nil nil nil -1 nil)))
(should (equal (iso8601-parse-time "15:27:46")
- '(46 27 15 nil nil nil nil nil nil)))
+ '(46 27 15 nil nil nil nil -1 nil)))
(should (equal (iso8601-parse-time "1528")
- '(0 28 15 nil nil nil nil nil nil)))
+ '(0 28 15 nil nil nil nil -1 nil)))
(should (equal (iso8601-parse-time "15:28")
- '(0 28 15 nil nil nil nil nil nil)))
+ '(0 28 15 nil nil nil nil -1 nil)))
(should (equal (iso8601-parse-time "15")
- '(0 0 15 nil nil nil nil nil nil))))
+ '(0 0 15 nil nil nil nil -1 nil))))
(ert-deftest standard-test-time-of-day-fractions ()
(should (equal (iso8601-parse-time "152735,5" t)
- '((355 . 10) 27 15 nil nil nil nil nil nil)))
+ '((355 . 10) 27 15 nil nil nil nil -1 nil)))
(should (equal (iso8601-parse-time "15:27:35,5" t)
- '((355 . 10) 27 15 nil nil nil nil nil nil)))
+ '((355 . 10) 27 15 nil nil nil nil -1 nil)))
(should (equal (iso8601-parse-time "2320,5" t)
- '(30 20 23 nil nil nil nil nil nil)))
+ '(30 20 23 nil nil nil nil -1 nil)))
(should (equal (iso8601-parse-time "23:20,8" t)
- '(48 20 23 nil nil nil nil nil nil)))
+ '(48 20 23 nil nil nil nil -1 nil)))
(should (equal (iso8601-parse-time "23,3" t)
- '(0 18 23 nil nil nil nil nil nil))))
+ '(0 18 23 nil nil nil nil -1 nil))))
(ert-deftest nonstandard-test-time-of-day-decimals ()
(should (equal (iso8601-parse-time "15:27:35.123" t)
- '((35123 . 1000) 27 15 nil nil nil nil nil nil)))
+ '((35123 . 1000) 27 15 nil nil nil nil -1 nil)))
(should (equal (iso8601-parse-time "15:27:35.123456789" t)
- '((35123456789 . 1000000000) 27 15 nil nil nil nil nil nil))))
+ '((35123456789 . 1000000000) 27 15 nil nil nil nil -1 nil))))
(ert-deftest standard-test-time-of-day-beginning-of-day ()
(should (equal (iso8601-parse-time "000000")
- '(0 0 0 nil nil nil nil nil nil)))
+ '(0 0 0 nil nil nil nil -1 nil)))
(should (equal (iso8601-parse-time "00:00:00")
- '(0 0 0 nil nil nil nil nil nil)))
+ '(0 0 0 nil nil nil nil -1 nil)))
(should (equal (iso8601-parse-time "0000")
- '(0 0 0 nil nil nil nil nil nil)))
+ '(0 0 0 nil nil nil nil -1 nil)))
(should (equal (iso8601-parse-time "00:00")
- '(0 0 0 nil nil nil nil nil nil))))
+ '(0 0 0 nil nil nil nil -1 nil))))
(ert-deftest standard-test-time-of-day-utc ()
(should (equal (iso8601-parse-time "232030Z")
@@ -220,11 +232,42 @@
(should (equal (iso8601-parse-time "15:27:46-05")
'(46 27 15 nil nil nil nil nil -18000))))
+
+(defun test-iso8601-format-time-string-zone-round-trip (offset-minutes z-format)
+ "Pass OFFSET-MINUTES to format-time-string with Z-FORMAT, a %z variation,
+and then to iso8601-parse-zone. The result should be the original offset."
+ (let* ((offset-seconds (* 60 offset-minutes))
+ (zone-string (format-time-string z-format 0 offset-seconds))
+ (offset-rt
+ (condition-case nil
+ (iso8601-parse-zone zone-string)
+ (wrong-type-argument (format "(failed to parse %S)" zone-string))))
+ ;; compare strings that contain enough info to debug failures
+ (success (format "%s(%s) -> %S -> %s"
+ z-format offset-minutes zone-string offset-minutes))
+ (actual (format "%s(%s) -> %S -> %s"
+ z-format offset-minutes zone-string offset-rt)))
+ (should (equal success actual))))
+
+(ert-deftest iso8601-format-time-string-zone-round-trip ()
+ "Round trip zone offsets through format-time-string and iso8601-parse-zone.
+Passing a time zone created by format-time-string %z to
+iso8601-parse-zone should yield the original offset."
+ (dolist (offset-minutes
+ (list
+ ;; compare hours (1- and 2-digit), minutes, both, neither
+ (* 5 60) (* 11 60) 5 11 (+ (* 5 60) 30) (+ (* 11 60) 30) 0
+ ;; do negative values, too
+ (* -5 60) (* -11 60) -5 -11 (- (* -5 60) 30) (- (* -11 60) 30)))
+ (dolist (z-format '("%z" "%:z" "%:::z"))
+ (test-iso8601-format-time-string-zone-round-trip
+ offset-minutes z-format))))
+
(ert-deftest standard-test-date-and-time-of-day ()
(should (equal (iso8601-parse "19850412T101530")
- '(30 15 10 12 4 1985 nil nil nil)))
+ '(30 15 10 12 4 1985 nil -1 nil)))
(should (equal (iso8601-parse "1985-04-12T10:15:30")
- '(30 15 10 12 4 1985 nil nil nil)))
+ '(30 15 10 12 4 1985 nil -1 nil)))
(should (equal (iso8601-parse "1985102T235030Z")
'(30 50 23 12 4 1985 nil nil 0)))
@@ -232,9 +275,9 @@
'(30 50 23 12 4 1985 nil nil 0)))
(should (equal (iso8601-parse "1985W155T235030")
- '(30 50 23 12 4 1985 nil nil nil)))
+ '(30 50 23 12 4 1985 nil -1 nil)))
(should (equal (iso8601-parse "1985-W155T23:50:30")
- '(30 50 23 12 4 1985 nil nil nil))))
+ '(30 50 23 12 4 1985 nil -1 nil))))
(ert-deftest standard-test-interval ()
;; A time interval starting at 20 minutes and 50 seconds past 23
@@ -256,48 +299,48 @@
;; This example doesn't seem valid according to the standard.
;; "0625" is unambiguous, and means "the year 625". Weird.
;; (should (equal (iso8601-parse-interval "19850412/0625")
- ;; '((nil nil nil 12 4 1985 nil nil nil)
- ;; (nil nil nil nil nil 625 nil nil nil)
+ ;; '((nil nil nil 12 4 1985 nil -1 nil)
+ ;; (nil nil nil nil nil 625 nil -1 nil)
;; (0 17 0 22 9 609 5 nil 0))))
;; A time interval of 2 years, 10 months, 15 days, 10 hours, 20
;; minutes and 30 seconds.
(should (equal (iso8601-parse-duration "P2Y10M15DT10H20M30S")
- '(30 20 10 15 10 2 nil nil nil)))
+ '(30 20 10 15 10 2 nil -1 nil)))
(should (equal (iso8601-parse-duration "P00021015T102030")
- '(30 20 10 15 10 2 nil nil nil)))
+ '(30 20 10 15 10 2 nil -1 nil)))
(should (equal (iso8601-parse-duration "P0002-10-15T10:20:30")
- '(30 20 10 15 10 2 nil nil nil)))
+ '(30 20 10 15 10 2 nil -1 nil)))
;; A time interval of 1 year and 6 months.
(should (equal (iso8601-parse-duration "P1Y6M")
- '(0 0 0 0 6 1 nil nil nil)))
+ '(0 0 0 0 6 1 nil -1 nil)))
(should (equal (iso8601-parse-duration "P0001-06")
- '(nil nil nil nil 6 1 nil nil nil)))
+ '(nil nil nil nil 6 1 nil -1 nil)))
;; A time interval of seventy-two hours.
(should (equal (iso8601-parse-duration "PT72H")
- '(0 0 72 0 0 0 nil nil nil)))
+ '(0 0 72 0 0 0 nil -1 nil)))
;; Defined by start and duration
;; A time interval of 1 year, 2 months, 15 days and 12 hours,
;; beginning on 12 April 1985 at 20 minutes past 23 hours.
(should (equal (iso8601-parse-interval "19850412T232000/P1Y2M15DT12H")
- '((0 20 23 12 4 1985 nil nil nil)
- (0 20 11 28 6 1986 nil nil nil)
- (0 0 12 15 2 1 nil nil nil))))
+ '((0 20 23 12 4 1985 nil -1 nil)
+ (0 20 11 28 6 1986 nil -1 nil)
+ (0 0 12 15 2 1 nil -1 nil))))
(should (equal (iso8601-parse-interval "1985-04-12T23:20:00/P1Y2M15DT12H")
- '((0 20 23 12 4 1985 nil nil nil)
- (0 20 11 28 6 1986 nil nil nil)
- (0 0 12 15 2 1 nil nil nil))))
+ '((0 20 23 12 4 1985 nil -1 nil)
+ (0 20 11 28 6 1986 nil -1 nil)
+ (0 0 12 15 2 1 nil -1 nil))))
;; Defined by duration and end
;; A time interval of 1 year, 2 months, 15 days and 12 hours, ending
;; on 12 April 1985 at 20 minutes past 23 hour.
(should (equal (iso8601-parse-interval "P1Y2M15DT12H/19850412T232000")
- '((0 20 11 28 1 1984 nil nil nil)
- (0 20 23 12 4 1985 nil nil nil)
- (0 0 12 15 2 1 nil nil nil)))))
+ '((0 20 11 28 1 1984 nil -1 nil)
+ (0 20 23 12 4 1985 nil -1 nil)
+ (0 0 12 15 2 1 nil -1 nil)))))
;;; iso8601-tests.el ends here
diff --git a/test/lisp/calendar/lunar-tests.el b/test/lisp/calendar/lunar-tests.el
new file mode 100644
index 00000000000..5f1f6782f1a
--- /dev/null
+++ b/test/lisp/calendar/lunar-tests.el
@@ -0,0 +1,75 @@
+;;; lunar-tests.el --- tests for calendar/lunar.el -*- lexical-binding:t -*-
+
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+;; Author: Stefan Kangas <stefankangas@gmail.com>
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(require 'lunar)
+
+(defmacro with-lunar-test (&rest body)
+ `(let ((calendar-latitude 40.1)
+ (calendar-longitude -88.2)
+ (calendar-location-name "Urbana, IL")
+ (calendar-time-zone -360)
+ (calendar-standard-time-zone-name "CST")
+ (calendar-time-display-form '(12-hours ":" minutes am-pm)))
+ ,@body))
+
+(ert-deftest lunar-test-phase ()
+ (with-lunar-test
+ (should (equal (lunar-phase 1)
+ '((1 7 1900) "11:40pm" 1 "")))))
+
+(ert-deftest lunar-test-eclipse-check ()
+ (with-lunar-test
+ (should (equal (eclipse-check 1 1) "** Eclipse **"))))
+
+;; This fails in certain time zones.
+;; Eg TZ=America/Phoenix make lisp/calendar/lunar-tests
+;; Similarly with TZ=UTC.
+;; Daylight saving related?
+(ert-deftest lunar-test-phase-list ()
+ :tags '(:unstable)
+ (with-lunar-test
+ (should (equal (lunar-phase-list 3 1871)
+ '(((3 20 1871) "11:03pm" 0 "")
+ ((3 29 1871) "1:46am" 1 "** Eclipse **")
+ ((4 5 1871) "9:20am" 2 "")
+ ((4 12 1871) "12:57am" 3 "** Eclipse possible **")
+ ((4 19 1871) "2:06pm" 0 "")
+ ((4 27 1871) "6:49pm" 1 "")
+ ((5 4 1871) "5:57pm" 2 "")
+ ((5 11 1871) "9:29am" 3 "")
+ ((5 19 1871) "5:46am" 0 "")
+ ((5 27 1871) "8:02am" 1 ""))))))
+
+(ert-deftest lunar-test-new-moon-time ()
+ (with-lunar-test
+ (should (= (round (lunar-new-moon-time 1))
+ 2451580))))
+
+(ert-deftest lunar-test-new-moon-on-or-after ()
+ (with-lunar-test
+ (should (= (round (lunar-new-moon-on-or-after (calendar-absolute-from-gregorian '(5 5 1818))))
+ 664525))))
+
+(provide 'lunar-tests)
+;;; lunar-tests.el ends here
diff --git a/test/lisp/calendar/parse-time-tests.el b/test/lisp/calendar/parse-time-tests.el
index b43a72d7ae1..b90fe0bd85b 100644
--- a/test/lisp/calendar/parse-time-tests.el
+++ b/test/lisp/calendar/parse-time-tests.el
@@ -1,4 +1,4 @@
-;; parse-time-tests.el --- Test suite for parse-time.el
+;; parse-time-tests.el --- Test suite for parse-time.el -*- lexical-binding:t -*-
;; Copyright (C) 2016-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/calendar/solar-tests.el b/test/lisp/calendar/solar-tests.el
new file mode 100644
index 00000000000..7a37f8db558
--- /dev/null
+++ b/test/lisp/calendar/solar-tests.el
@@ -0,0 +1,42 @@
+;;; solar-tests.el --- tests for solar.el -*- lexical-binding: t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+(require 'ert)
+(require 'solar)
+
+(ert-deftest solar-sunrise-sunset ()
+ ;; Bug#44237: wrong sunrise time on Dec 30 and 31, 2020 for Jaipur.
+ (let ((calendar-latitude 26.9)
+ (calendar-longitude 75.8)
+ (calendar-time-zone +330)
+ (calendar-standard-time-zone-name "IST")
+ (calendar-daylight-time-zone-name "IST")
+ (epsilon (/ 60.0))) ; Minute accuracy is good enough.
+ (let* ((sunrise-sunset (solar-sunrise-sunset '(12 30 2020)))
+ (sunrise (car (nth 0 sunrise-sunset)))
+ (sunset (car (nth 1 sunrise-sunset))))
+ (should (< (abs (- sunrise 7.27)) epsilon))
+ (should (< (abs (- sunset 17.72)) epsilon)))
+ (let* ((sunrise-sunset (solar-sunrise-sunset '(12 31 2020)))
+ (sunrise (car (nth 0 sunrise-sunset)))
+ (sunset (car (nth 1 sunrise-sunset))))
+ (should (< (abs (- sunrise 7.28)) epsilon))
+ (should (< (abs (- sunset 17.72)) epsilon)))))
+
+(provide 'solar-tests)
diff --git a/test/lisp/calendar/time-date-tests.el b/test/lisp/calendar/time-date-tests.el
index 2dca11cd3dc..4568947c0b3 100644
--- a/test/lisp/calendar/time-date-tests.el
+++ b/test/lisp/calendar/time-date-tests.el
@@ -22,16 +22,73 @@
(require 'ert)
(require 'time-date)
+(ert-deftest test-obsolete-with-decoded-time-value ()
+ (with-suppressed-warnings ((obsolete with-decoded-time-value))
+ (with-decoded-time-value ((high low micro pico type '(1 2 3 4 5 6 8 8)))
+ (should (equal (list high low micro pico type) '(1 2 3 4 3))))))
+
+(ert-deftest test-obsolete-encode-time-value ()
+ (should (equal (with-suppressed-warnings ((obsolete encode-time-value))
+ (encode-time-value 1 2 3 4 0))
+ '(1 . 2)))
+ (should (equal (with-suppressed-warnings ((obsolete encode-time-value))
+ (encode-time-value 1 2 3 4 1))
+ '(1 2)))
+ (should (equal (with-suppressed-warnings ((obsolete encode-time-value))
+ (encode-time-value 1 2 3 4 2))
+ '(1 2 3)))
+ (should (equal (with-suppressed-warnings ((obsolete encode-time-value))
+ (encode-time-value 1 2 3 4 3))
+ '(1 2 3 4))))
+
(ert-deftest test-leap-year ()
(should-not (date-leap-year-p 1999))
(should-not (date-leap-year-p 1900))
(should (date-leap-year-p 2000))
(should (date-leap-year-p 2004)))
+(ert-deftest test-days-to-time ()
+ (should (equal (days-to-time 0) '(0 0)))
+ (should (equal (days-to-time 1) '(1 20864)))
+ (should (equal (days-to-time 999) '(1317 2688)))
+ (should (equal (days-to-time 0.0) '(0 0 0 0)))
+ (should (equal (days-to-time 0.5) '(0 43200 0 0)))
+ (should (equal (days-to-time 1.0) '(1 20864 0 0)))
+ (should (equal (days-to-time 999.0) '(1317 2688 0 0))))
+
+(ert-deftest test-seconds-to-string ()
+ (should (equal (seconds-to-string 0) "0s"))
+ (should (equal (seconds-to-string 9) "9.00s"))
+ (should (equal (seconds-to-string 99) "99.00s"))
+ (should (equal (seconds-to-string 999) "16.65m"))
+ (should (equal (seconds-to-string 9999) "2.78h"))
+ (should (equal (seconds-to-string 99999) "27.78h"))
+ (should (equal (seconds-to-string 999999) "11.57d"))
+ (should (equal (seconds-to-string 9999999) "115.74d"))
+ (should (equal (seconds-to-string 99999999) "3.17y"))
+ (should (equal (seconds-to-string 999999999) "31.69y")))
+
(ert-deftest test-days-in-month ()
(should (= (date-days-in-month 2004 2) 29))
(should (= (date-days-in-month 2004 3) 31))
- (should-not (= (date-days-in-month 1900 3) 28)))
+ (should (= (date-days-in-month 2019 2) 28))
+ (should (= (date-days-in-month 2020 12) 31))
+ (should-not (= (date-days-in-month 1900 3) 28))
+ (should-error (date-days-in-month 2020 0))
+ (should-error (date-days-in-month 2020 15))
+ (should-error (date-days-in-month 2020 'foo)))
+
+(ert-deftest test-format-seconds ()
+ (should (equal (format-seconds "%y %d %h %m %s %%" 0) "0 0 0 0 0 %"))
+ (should (equal (format-seconds "%y %d %h %m %s %%" 9999999) "0 115 17 46 39 %"))
+ (should (equal (format-seconds "%y %d %h %m %z %s %%" 1) " 1 %"))
+ (should (equal (format-seconds "%mm %ss" 66) "1m 6s"))
+ (should (equal (format-seconds "%mm %5ss" 66) "1m 6s"))
+ (should (equal (format-seconds "%mm %.5ss" 66.4) "1m 00006s"))
+
+ (should (equal (format-seconds "%mm %,1ss" 66.4) "1m 6.4s"))
+ (should (equal (format-seconds "%mm %5,1ss" 66.4) "1m 6.4s"))
+ (should (equal (format-seconds "%mm %.5,1ss" 66.4) "1m 006.4s")))
(ert-deftest test-ordinal ()
(should (equal (date-ordinal-to-time 2008 271)
@@ -105,6 +162,42 @@
'(12 15 14 8 7 2019 1 t 7200)))))
(ert-deftest test-time-since ()
- (should (time-equal-p 0 (time-since nil))))
+ (should (time-equal-p 0 (time-since nil)))
+ (should (= (cadr (time-since (time-subtract (current-time) 1))) 1)))
+
+(ert-deftest test-time-decoded-period ()
+ (should (equal (decoded-time-period '(nil nil 1 nil nil nil nil nil nil))
+ 3600))
+
+ (should (equal (decoded-time-period '(1 0 0 0 0 0 nil nil nil)) 1))
+ (should (equal (decoded-time-period '(0 1 0 0 0 0 nil nil nil)) 60))
+ (should (equal (decoded-time-period '(0 0 1 0 0 0 nil nil nil)) 3600))
+ (should (equal (decoded-time-period '(0 0 0 1 0 0 nil nil nil)) 86400))
+ (should (equal (decoded-time-period '(0 0 0 0 1 0 nil nil nil)) 2592000))
+ (should (equal (decoded-time-period '(0 0 0 0 0 1 nil nil nil)) 31536000))
+ (should (equal (decoded-time-period '(1 2 3 4 5 6 nil nil nil)) 202532521))
+
+ (should (equal (decoded-time-period '((135 . 10) 0 0 0 0 0 nil nil nil))
+ 13.5)))
+
+(ert-deftest test-time-wrap-addition ()
+ (should (equal (decoded-time-add '(0 0 0 1 11 2008 nil nil nil)
+ (make-decoded-time :month 1))
+ '(0 0 0 1 12 2008 nil nil nil)))
+ (should (equal (decoded-time-add '(0 0 0 1 12 2008 nil nil nil)
+ (make-decoded-time :month 1))
+ '(0 0 0 1 1 2009 nil nil nil)))
+ (should (equal (decoded-time-add '(0 0 0 1 11 2008 nil nil nil)
+ (make-decoded-time :month 12))
+ '(0 0 0 1 11 2009 nil nil nil)))
+ (should (equal (decoded-time-add '(0 0 0 1 11 2008 nil nil nil)
+ (make-decoded-time :month 13))
+ '(0 0 0 1 12 2009 nil nil nil)))
+ (should (equal (decoded-time-add '(0 0 0 30 12 2008 nil nil nil)
+ (make-decoded-time :day 1))
+ '(0 0 0 31 12 2008 nil nil nil)))
+ (should (equal (decoded-time-add '(0 0 0 30 12 2008 nil nil nil)
+ (make-decoded-time :day 2))
+ '(0 0 0 1 1 2009 nil nil nil))))
;;; time-date-tests.el ends here
diff --git a/test/lisp/calendar/todo-mode-resources/todo-test-1.todo b/test/lisp/calendar/todo-mode-resources/todo-test-1.todo
index 598d487cad9..2375772fbe7 100644
--- a/test/lisp/calendar/todo-mode-resources/todo-test-1.todo
+++ b/test/lisp/calendar/todo-mode-resources/todo-test-1.todo
@@ -1,8 +1,8 @@
-(("testcat1" . [2 0 2 1]) ("testcat2" . [3 0 1 1]) ("testcat3" . [0 0 0 0]))
+(("testcat1" . [2 0 2 1]) ("testcat2" . [3 0 1 1]) ("testcat3" . [0 0 0 0]) ("testcat4" . [1 0 0 0]))
--==-- testcat1
[May 29, 2017] testcat1 item3
- has more than one line
- to test item highlighting
+ has more than one line
+ to test item highlighting
[Jul 3, 2017] testcat1 item4
==--== DONE
@@ -18,3 +18,7 @@
--==-- testcat3
==--== DONE
+--==-- testcat4
+[Jan 1, 2020] testcat4 item1
+
+==--== DONE
diff --git a/test/lisp/calendar/todo-mode-tests.el b/test/lisp/calendar/todo-mode-tests.el
index a9ed48c4902..6fa2b9d7c35 100644
--- a/test/lisp/calendar/todo-mode-tests.el
+++ b/test/lisp/calendar/todo-mode-tests.el
@@ -28,19 +28,10 @@
(require 'ert-x)
(require 'todo-mode)
-(defvar todo-test-data-dir
- (file-truename
- (expand-file-name "todo-mode-resources/"
- (file-name-directory (or load-file-name
- buffer-file-name))))
- "Base directory of todo-mode.el test data files.")
-
-(defvar todo-test-file-1 (expand-file-name "todo-test-1.todo"
- todo-test-data-dir)
+(defvar todo-test-file-1 (ert-resource-file "todo-test-1.todo")
"Todo mode test file.")
-(defvar todo-test-archive-1 (expand-file-name "todo-test-1.toda"
- todo-test-data-dir)
+(defvar todo-test-archive-1 (ert-resource-file "todo-test-1.toda")
"Todo Archive mode test file.")
(defmacro with-todo-test (&rest body)
@@ -52,7 +43,7 @@
(abbreviated-home-dir nil)
(process-environment (cons (format "HOME=%s" todo-test-home)
process-environment))
- (todo-directory todo-test-data-dir)
+ (todo-directory (ert-resource-directory))
(todo-default-todo-file (todo-short-file-name
(car (funcall todo-files-function)))))
(unwind-protect
@@ -414,8 +405,15 @@ the top done item should be the first done item."
(should (todo-done-item-p))
(forward-line -1)
(should (looking-at todo-category-done))
- ;; Make sure marked items are no longer in first category.
- (todo-backward-category)
+ ;; Make sure marked items are no longer in first category. Since
+ ;; cat1 now contains no todo or done items but does have archived
+ ;; items, todo-backward-category would skip it by default, so
+ ;; prevent this. (FIXME: Without this let-binding,
+ ;; todo-backward-category selects the nonempty cat4 and this test
+ ;; fails as expected when run interactively but not in a batch
+ ;; run -- why?)
+ (let (todo-skip-archived-categories)
+ (todo-backward-category))
(should (eq (point-min) (point-max))) ; All todo items were moved.
;; This passes when run interactively but fails in a batch run:
;; the message is displayed but (current-message) evaluates to
@@ -808,7 +806,7 @@ buffer from which the editing command was invoked."
"Add file FILE with category CAT to todo-files and show it.
This provides a noninteractive API for todo-add-file for use in
automatic testing."
- (let ((file0 (file-truename (concat todo-test-data-dir file ".todo")))
+ (let ((file0 (ert-resource-file (concat file ".todo")))
todo-add-item-if-new-category) ; Don't need an item in cat.
(cl-letf (((symbol-function 'todo-read-file-name)
(lambda (_prompt) file0))
@@ -848,6 +846,94 @@ should display the previously current (or default) todo file."
(should (equal todo-current-todo-file todo-test-file-1))
(delete-file (concat file "~")))))
+(ert-deftest todo-test-edit-item-date-month () ; bug#42976 #3 and #4
+ "Test incrementing and decrementing the month of an item's date.
+If the change in month crosses a year boundary, the year of the
+item's date should be adjusted accordingly."
+ (with-todo-test
+ (todo-test--show 4)
+ (let ((current-prefix-arg t) ; For todo-edit-item--header.
+ (get-date (lambda ()
+ (save-excursion
+ (todo-date-string-matcher (line-end-position))
+ (buffer-substring-no-properties (match-beginning 1)
+ (match-end 0))))))
+ (should (equal (funcall get-date) "Jan 1, 2020"))
+ (todo-edit-item--header 'month 0)
+ (should (equal (funcall get-date) "Jan 1, 2020"))
+ (todo-edit-item--header 'month 1)
+ (should (equal (funcall get-date) "Feb 1, 2020"))
+ (todo-edit-item--header 'month -1)
+ (should (equal (funcall get-date) "Jan 1, 2020"))
+ (todo-edit-item--header 'month -1)
+ (should (equal (funcall get-date) "Dec 1, 2019"))
+ (todo-edit-item--header 'month 1)
+ (should (equal (funcall get-date) "Jan 1, 2020"))
+ (todo-edit-item--header 'month 12)
+ (should (equal (funcall get-date) "Jan 1, 2021"))
+ (todo-edit-item--header 'month -12)
+ (should (equal (funcall get-date) "Jan 1, 2020"))
+ (todo-edit-item--header 'month -13)
+ (should (equal (funcall get-date) "Dec 1, 2018"))
+ (todo-edit-item--header 'month 7)
+ (should (equal (funcall get-date) "Jul 1, 2019"))
+ (todo-edit-item--header 'month 6)
+ (should (equal (funcall get-date) "Jan 1, 2020"))
+ (todo-edit-item--header 'month 23)
+ (should (equal (funcall get-date) "Dec 1, 2021"))
+ (todo-edit-item--header 'month -23)
+ (should (equal (funcall get-date) "Jan 1, 2020"))
+ (todo-edit-item--header 'month 24)
+ (should (equal (funcall get-date) "Jan 1, 2022"))
+ (todo-edit-item--header 'month -24)
+ (should (equal (funcall get-date) "Jan 1, 2020"))
+ (todo-edit-item--header 'month 25)
+ (should (equal (funcall get-date) "Feb 1, 2022"))
+ (todo-edit-item--header 'month -25)
+ (should (equal (funcall get-date) "Jan 1, 2020")))))
+
+(ert-deftest todo-test-multiline-item-indentation-1 ()
+ "Test inserting a multine item containing a hard line break.
+After insertion the second line of the item should begin with a
+tab character."
+ (with-todo-test
+ (let* ((item0 "Test inserting a multine item")
+ (item1 "containing a hard line break.")
+ (item (concat item0 "\n" item1)))
+ (todo-test--show 1)
+ (todo-test--insert-item item 1)
+ (re-search-forward (concat todo-date-string-start todo-date-pattern
+ (regexp-quote todo-nondiary-end) " ")
+ (line-end-position) t)
+ (should (looking-at (regexp-quote (concat item0 "\n\t" item1)))))))
+
+(ert-deftest todo-test-multiline-item-indentation-2 () ; bug#43068
+ "Test editing an item by adding text on a new line.
+After quitting todo-edit-mode the second line of the item should
+begin with a tab character."
+ (with-todo-test
+ (todo-test--show 2)
+ (let* ((item0 (todo-item-string))
+ (item1 "Second line."))
+ (todo-edit-item--text 'multiline)
+ (insert (concat "\n" item1))
+ (todo-edit-quit)
+ (goto-char (line-beginning-position))
+ (should (looking-at (regexp-quote (concat item0 "\n\t" item1)))))))
+
+(ert-deftest todo-test-multiline-item-indentation-3 ()
+ "Test adding an unindented new line to an item using todo-edit-file.
+Attempting to quit todo-edit-mode should signal a user-error,
+since all non-initial item lines must begin with whitespace."
+ (with-todo-test
+ (todo-test--show 2)
+ (let* ((item0 (todo-item-string))
+ (item1 "Second line."))
+ (todo-edit-file)
+ (should (looking-at (regexp-quote item0)))
+ (goto-char (line-end-position))
+ (insert (concat "\n" item1))
+ (should-error (todo-edit-quit) :type 'user-error))))
(provide 'todo-mode-tests)
;;; todo-mode-tests.el ends here
diff --git a/test/lisp/cedet/semantic-utest-c.el b/test/lisp/cedet/semantic-utest-c.el
index d1c4ff8f449..a7cbe116c2e 100644
--- a/test/lisp/cedet/semantic-utest-c.el
+++ b/test/lisp/cedet/semantic-utest-c.el
@@ -1,4 +1,4 @@
-;;; semantic-utest-c.el --- C based parsing tests.
+;;; semantic-utest-c.el --- C based parsing tests. -*- lexical-binding:t -*-
;; Copyright (C) 2008-2021 Free Software Foundation, Inc.
@@ -40,11 +40,13 @@
(defvar semantic-utest-c-test-directory (expand-file-name "tests" cedet-utest-directory)
"Location of test files.")
+(defvar semantic-lex-c-nested-namespace-ignore-second)
+
;;; Code:
;;;###autoload
(ert-deftest semantic-test-c-preprocessor-simulation ()
"Run parsing test for C from the test directory."
- (interactive)
+ :tags '(:expensive-test)
(semantic-mode 1)
(dolist (fp semantic-utest-c-comparisons)
(let* ((semantic-lex-c-nested-namespace-ignore-second nil)
@@ -146,33 +148,32 @@ gcc version 2.95.2 19991024 (release)"
(ert-deftest semantic-test-gcc-output-parser ()
"Test the output parser against some collected strings."
- (let ((fail nil))
- (dolist (S semantic-gcc-test-strings)
- (let* ((fields (semantic-gcc-fields S))
- (v (cdr (assoc 'version fields)))
- (h (or (cdr (assoc 'target fields))
- (cdr (assoc '--target fields))
- (cdr (assoc '--host fields))))
- (p (cdr (assoc '--prefix fields)))
- )
- ;; No longer test for prefixes.
- (when (not (and v h))
- (let ((strs (split-string S "\n")))
- (message "Test failed on %S\nV H P:\n%S %S %S" (car strs) v h p)
- ))
- (should (and v h))
- ))
- (dolist (S semantic-gcc-test-strings-fail)
- (let* ((fields (semantic-gcc-fields S))
- (v (cdr (assoc 'version fields)))
- (h (or (cdr (assoc '--host fields))
- (cdr (assoc 'target fields))))
- (p (cdr (assoc '--prefix fields)))
- )
- ;; negative test
- (should-not (and v h p))
- ))
- ))
+ (dolist (S semantic-gcc-test-strings)
+ (let* ((fields (semantic-gcc-fields S))
+ (v (cdr (assoc 'version fields)))
+ (h (or (cdr (assoc 'target fields))
+ (cdr (assoc '--target fields))
+ (cdr (assoc '--host fields))))
+ (p (cdr (assoc '--prefix fields)))
+ )
+ ;; No longer test for prefixes.
+ (when (not (and v h))
+ (let ((strs (split-string S "\n")))
+ (message "Test failed on %S\nV H P:\n%S %S %S" (car strs) v h p)
+ ))
+ (should (and v h))
+ ))
+ (dolist (S semantic-gcc-test-strings-fail)
+ (let* ((fields (semantic-gcc-fields S))
+ (v (cdr (assoc 'version fields)))
+ (h (or (cdr (assoc '--host fields))
+ (cdr (assoc 'target fields))))
+ (p (cdr (assoc '--prefix fields)))
+ )
+ ;; negative test
+ (should-not (and v h p))
+ ))
+ )
(provide 'semantic-utest-c)
diff --git a/test/lisp/cedet/semantic-utest-fmt.el b/test/lisp/cedet/semantic-utest-fmt.el
index e0dfe3242ef..d6e5ce7a0fd 100644
--- a/test/lisp/cedet/semantic-utest-fmt.el
+++ b/test/lisp/cedet/semantic-utest-fmt.el
@@ -1,4 +1,4 @@
-;;; cedet/semantic-utest-fmt.el --- Parsing / Formatting tests
+;;; cedet/semantic-utest-fmt.el --- Parsing / Formatting tests -*- lexical-binding:t -*-
;;; Copyright (C) 2003-2004, 2007-2021 Free Software Foundation, Inc.
@@ -69,7 +69,6 @@ Files to visit are in `semantic-fmt-utest-file-list'."
;; Run the tests.
(let ((fb (find-buffer-visiting fname))
(b (semantic-find-file-noselect fname))
- (num 0)
(tags nil))
(save-current-buffer
@@ -82,7 +81,6 @@ Files to visit are in `semantic-fmt-utest-file-list'."
(semantic-clear-toplevel-cache)
;; Force the reparse
(setq tags (semantic-fetch-tags))
- (setq num (length tags))
(save-excursion
(while tags
diff --git a/test/lisp/cedet/semantic-utest-ia.el b/test/lisp/cedet/semantic-utest-ia.el
index ce01bd61896..7210f66b0a7 100644
--- a/test/lisp/cedet/semantic-utest-ia.el
+++ b/test/lisp/cedet/semantic-utest-ia.el
@@ -1,4 +1,4 @@
-;;; semantic-utest-ia.el --- Analyzer unit tests
+;;; semantic-utest-ia.el --- Analyzer unit tests -*- lexical-binding:t -*-
;; Copyright (C) 2008-2021 Free Software Foundation, Inc.
@@ -86,6 +86,7 @@
(should-not (semantic-ia-utest tst))))
(ert-deftest semantic-utest-ia-nsp.cpp ()
+ (skip-unless (executable-find "g++"))
(let ((tst (expand-file-name "testnsp.cpp" semantic-utest-test-directory)))
(should (file-exists-p tst))
(should-not (semantic-ia-utest tst))))
@@ -96,6 +97,7 @@
(should-not (semantic-ia-utest tst))))
(ert-deftest semantic-utest-ia-namespace.cpp ()
+ (skip-unless (executable-find "g++"))
(let ((tst (expand-file-name "testnsp.cpp" semantic-utest-test-directory)))
(should (file-exists-p tst))
(should-not (semantic-ia-utest tst))))
@@ -211,7 +213,7 @@
;; completions, then remove the below debug-on-error setting.
(debug-on-error nil)
(acomp
- (condition-case err
+ (condition-case _err
(semantic-analyze-possible-completions ctxt)
((error user-error) nil))
))
@@ -438,11 +440,10 @@ tag that contains point, and return that."
(let* ((ctxt (semantic-analyze-current-context))
(target (car (reverse (oref ctxt prefix))))
(tag (semantic-current-tag))
- (start (current-time))
(Lcount 0))
(when (semantic-tag-p target)
(semantic-symref-hits-in-region
- target (lambda (start end prefix) (setq Lcount (1+ Lcount)))
+ target (lambda (_start _end _prefix) (setq Lcount (1+ Lcount)))
(semantic-tag-start tag)
(semantic-tag-end tag))
Lcount)))
diff --git a/test/lisp/cedet/semantic-utest.el b/test/lisp/cedet/semantic-utest.el
index 64dcaa3dbb3..c0099386f1c 100644
--- a/test/lisp/cedet/semantic-utest.el
+++ b/test/lisp/cedet/semantic-utest.el
@@ -1,4 +1,4 @@
-;;; semantic-utest.el --- Tests for semantic's parsing system.
+;;; semantic-utest.el --- Tests for semantic's parsing system. -*- lexical-binding:t -*-
;;; Copyright (C) 2003-2004, 2007-2021 Free Software Foundation, Inc.
@@ -38,14 +38,9 @@
(defvar semantic-utest-test-directory (expand-file-name "tests" cedet-utest-directory)
"Location of test files.")
-(defvar semantic-utest-temp-directory (if (fboundp 'temp-directory)
- (temp-directory)
- temporary-file-directory)
- "Temporary directory to use when creating files.")
-
(defun semantic-utest-fname (name)
"Create a filename for NAME in /tmp."
- (expand-file-name name semantic-utest-temp-directory))
+ (expand-file-name name temporary-file-directory))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Data for C tests
@@ -537,10 +532,9 @@ Pre-fill the buffer with CONTENTS."
-(defun semantic-utest-generic (testname filename contents name-contents names-removed killme insertme)
+(defun semantic-utest-generic (filename contents name-contents names-removed killme insertme)
"Generic unit test according to template.
Should work for languages without .h files, python javascript java.
-TESTNAME is the name of the test.
FILENAME is the name of the file to create.
CONTENTS is the contents of the file to test.
NAME-CONTENTS is the list of names that should be in the contents.
@@ -564,10 +558,8 @@ INSERTME is the text to be inserted after the deletion."
(sit-for 0)
;; Run the tests.
- ;;(message "First parsing test %s." testname)
(should (semantic-utest-verify-names name-contents))
- ;;(message "Invalid tag test %s." testname)
(semantic-utest-last-invalid name-contents names-removed killme insertme)
(should (semantic-utest-verify-names name-contents))
@@ -576,16 +568,17 @@ INSERTME is the text to be inserted after the deletion."
(kill-buffer buff)
)))
+(defvar python-indent-guess-indent-offset) ; Silence byte-compiler.
(ert-deftest semantic-utest-Python()
- (skip-unless (featurep 'python-mode))
+ (skip-unless (fboundp 'python-mode))
(let ((python-indent-guess-indent-offset nil))
- (semantic-utest-generic "Python" (semantic-utest-fname "pytest.py") semantic-utest-Python-buffer-contents semantic-utest-Python-name-contents '("fun2") "#1" "#deleted line")
+ (semantic-utest-generic (semantic-utest-fname "pytest.py") semantic-utest-Python-buffer-contents semantic-utest-Python-name-contents '("fun2") "#1" "#deleted line")
))
(ert-deftest semantic-utest-Javascript()
(if (fboundp 'javascript-mode)
- (semantic-utest-generic "Javascript" (semantic-utest-fname "javascripttest.js") semantic-utest-Javascript-buffer-contents semantic-utest-Javascript-name-contents '("fun2") "//1" "//deleted line")
+ (semantic-utest-generic (semantic-utest-fname "javascripttest.js") semantic-utest-Javascript-buffer-contents semantic-utest-Javascript-name-contents '("fun2") "//1" "//deleted line")
(message "Skipping JavaScript test: NO major mode."))
)
@@ -593,34 +586,34 @@ INSERTME is the text to be inserted after the deletion."
;; If JDE is installed, it might mess things up depending on the version
;; that was installed.
(let ((auto-mode-alist '(("\\.java\\'" . java-mode))))
- (semantic-utest-generic "Java" (semantic-utest-fname "JavaTest.java") semantic-utest-Java-buffer-contents semantic-utest-Java-name-contents '("fun2") "//1" "//deleted line")
+ (semantic-utest-generic (semantic-utest-fname "JavaTest.java") semantic-utest-Java-buffer-contents semantic-utest-Java-name-contents '("fun2") "//1" "//deleted line")
))
(ert-deftest semantic-utest-Makefile()
- (semantic-utest-generic "Makefile" (semantic-utest-fname "Makefile") semantic-utest-Makefile-buffer-contents semantic-utest-Makefile-name-contents '("fun2") "#1" "#deleted line")
+ (semantic-utest-generic (semantic-utest-fname "Makefile") semantic-utest-Makefile-buffer-contents semantic-utest-Makefile-name-contents '("fun2") "#1" "#deleted line")
)
(ert-deftest semantic-utest-Scheme()
(skip-unless nil) ;; There is a bug w/ scheme parser. Skip this for now.
- (semantic-utest-generic "Scheme" (semantic-utest-fname "tst.scm") semantic-utest-Scheme-buffer-contents semantic-utest-Scheme-name-contents '("fun2") ";1" ";deleted line")
+ (semantic-utest-generic (semantic-utest-fname "tst.scm") semantic-utest-Scheme-buffer-contents semantic-utest-Scheme-name-contents '("fun2") ";1" ";deleted line")
)
-
+(defvar html-helper-build-new-buffer) ; Silence byte-compiler.
(ert-deftest semantic-utest-Html()
;; Disable html-helper auto-fill-in mode.
- (let ((html-helper-build-new-buffer nil))
- (semantic-utest-generic "HTML" (semantic-utest-fname "tst.html") semantic-utest-Html-buffer-contents semantic-utest-Html-name-contents '("fun2") "<!--1-->" "<!--deleted line-->")
+ (let ((html-helper-build-new-buffer nil)) ; FIXME: Why is this bound?
+ (semantic-utest-generic (semantic-utest-fname "tst.html") semantic-utest-Html-buffer-contents semantic-utest-Html-name-contents '("fun2") "<!--1-->" "<!--deleted line-->")
))
(ert-deftest semantic-utest-PHP()
(skip-unless (featurep 'php-mode))
- (semantic-utest-generic "PHP" (semantic-utest-fname "phptest.php") semantic-utest-PHP-buffer-contents semantic-utest-PHP-name-contents '("fun1") "fun2" "%^@")
+ (semantic-utest-generic (semantic-utest-fname "phptest.php") semantic-utest-PHP-buffer-contents semantic-utest-PHP-name-contents '("fun1") "fun2" "%^@")
)
;look at http://mfgames.com/linux/csharp-mode
(ert-deftest semantic-utest-Csharp() ;; hmm i don't even know how to edit a scharp file. need a csharp mode implementation i suppose
(skip-unless (featurep 'csharp-mode))
- (semantic-utest-generic "C#" (semantic-utest-fname "csharptest.cs") semantic-utest-Csharp-buffer-contents semantic-utest-Csharp-name-contents '("fun2") "//1" "//deleted line")
+ (semantic-utest-generic (semantic-utest-fname "csharptest.cs") semantic-utest-Csharp-buffer-contents semantic-utest-Csharp-name-contents '("fun2") "//1" "//deleted line")
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -758,7 +751,7 @@ JAVE this thing would need to be recursive to handle java and csharp"
(sit-for 0)
)
-(defun semantic-utest-last-invalid (name-contents names-removed killme insertme)
+(defun semantic-utest-last-invalid (_name-contents _names-removed killme insertme)
"Make the last fcn invalid."
(semantic-utest-kill-indicator killme insertme)
; (semantic-utest-verify-names name-contents names-removed); verify its gone ;new validator doesn't handle skipnames yet
diff --git a/test/lisp/cedet/srecode-utest-getset.el b/test/lisp/cedet/srecode-utest-getset.el
index 2a79a5cd669..0497dea505d 100644
--- a/test/lisp/cedet/srecode-utest-getset.el
+++ b/test/lisp/cedet/srecode-utest-getset.el
@@ -1,4 +1,4 @@
-;;; srecode/test-getset.el --- Test the getset inserter.
+;;; srecode/test-getset.el --- Test the getset inserter. -*- lexical-binding:t -*-
;; Copyright (C) 2008, 2009, 2011, 2019-2021 Free Software Foundation, Inc.
@@ -52,8 +52,10 @@ private:
temporary-file-directory)
"File used to do testing.")
+(defvar srecode-insert-getset-fully-automatic-flag) ; Silence byte-compiler.
(ert-deftest srecode-utest-getset-output ()
"Test various template insertion options."
+ :tags '(:expensive-test)
(save-excursion
(let ((testbuff (find-file-noselect srecode-utest-getset-testfile))
(srecode-insert-getset-fully-automatic-flag t))
diff --git a/test/lisp/cedet/srecode-utest-template.el b/test/lisp/cedet/srecode-utest-template.el
index 9faa2a3d7b0..57d8a648050 100644
--- a/test/lisp/cedet/srecode-utest-template.el
+++ b/test/lisp/cedet/srecode-utest-template.el
@@ -1,4 +1,4 @@
-;;; srecode/test.el --- SRecode Core Template tests.
+;;; srecode/test.el --- SRecode Core Template tests. -*- lexical-binding:t -*-
;; Copyright (C) 2008-2021 Free Software Foundation, Inc.
@@ -323,7 +323,6 @@ INSIDE SECTION: ARG HANDLER ONE")
(ert-deftest srecode-utest-project ()
"Test that project filtering works."
- :expected-result (if (getenv "EMACS_HYDRA_CI") :failed :passed) ; fixme
(save-excursion
(let ((testbuff (find-file-noselect srecode-utest-testfile))
(temp nil))
@@ -347,6 +346,10 @@ INSIDE SECTION: ARG HANDLER ONE")
;; Load the application templates, and make sure we can find them.
(srecode-load-tables-for-mode major-mode 'tests)
+ (dolist (table (oref (srecode-table) tables))
+ (when (gethash "test" (oref table contexthash))
+ (oset table project default-directory)))
+
(setq temp (srecode-template-get-table (srecode-table)
"test-project"
"test"
diff --git a/test/lisp/char-fold-tests.el b/test/lisp/char-fold-tests.el
index 162362f0ab3..063c893516f 100644
--- a/test/lisp/char-fold-tests.el
+++ b/test/lisp/char-fold-tests.el
@@ -4,18 +4,20 @@
;; Author: Artur Malabarba <bruce.connor.am@gmail.com>
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Code:
diff --git a/test/lisp/comint-tests.el b/test/lisp/comint-tests.el
index c9ecebae2e4..de1bc548e18 100644
--- a/test/lisp/comint-tests.el
+++ b/test/lisp/comint-tests.el
@@ -1,4 +1,4 @@
-;;; comint-testsuite.el
+;;; comint-tests.el -*- lexical-binding:t -*-
;; Copyright (C) 2010-2021 Free Software Foundation, Inc.
@@ -39,6 +39,7 @@
"Passphrase for key root@GNU.ORG: " ; plink
"[sudo] password for user:" ; Ubuntu sudo
"[sudo] user 的密码:" ; localized
+ "doas (user@host) password:" ; OpenBSD doas
"PIN for user:" ; Bug#35523
"Password (again):"
"Enter password:"
@@ -52,73 +53,41 @@
(dolist (str comint-testsuite-password-strings)
(should (string-match comint-password-prompt-regexp str))))
-(ert-deftest comint-test-no-password-function ()
- "Test that `comint-password-function' not being set does not
-alter normal password flow."
- (cl-letf
- (((symbol-function 'read-passwd)
- (lambda (_prompt &optional _confirm _default)
- "PaSsWoRd123")))
- (let ((cat (executable-find "cat")))
- (when cat
+(defun comint-tests/test-password-function (password-function)
+ "PASSWORD-FUNCTION can return nil or a string."
+ (when-let ((cat (executable-find "cat")))
+ (let ((comint-password-function password-function))
+ (cl-letf (((symbol-function 'read-passwd)
+ (lambda (&rest _args) "non-nil")))
(with-temp-buffer
(make-comint-in-buffer "test-comint-password" (current-buffer) cat)
(let ((proc (get-buffer-process (current-buffer))))
(set-process-query-on-exit-flag proc nil)
- (comint-send-string proc "Password: ")
- (comint-send-eof)
- (while (accept-process-output proc 0.1 nil t))
- (should (string-equal (buffer-substring-no-properties (point-min) (point-max))
- "Password: PaSsWoRd123\n"))
- (when (process-live-p proc)
- (kill-process proc))
- (accept-process-output proc 0 1 t)))))))
+ (set-process-query-on-exit-flag proc nil)
+ (comint-send-invisible "Password: ")
+ (accept-process-output proc 0.1)
+ (should (string-equal
+ (buffer-substring-no-properties (point-min) (point-max))
+ (concat (or (and password-function
+ (funcall password-function))
+ "non-nil")
+ "\n")))))))))
+
+(ert-deftest comint-test-no-password-function ()
+ "Test that `comint-password-function' not being set does not
+alter normal password flow."
+ (comint-tests/test-password-function nil))
(ert-deftest comint-test-password-function-with-value ()
"Test that `comint-password-function' alters normal password
flow. Hook function returns alternative password."
- (cl-letf
- (((symbol-function 'read-passwd)
- (lambda (_prompt &optional _confirm _default)
- "PaSsWoRd123")))
- (let ((cat (executable-find "cat"))
- (comint-password-function (lambda (_prompt) "MaGiC-PaSsWoRd789")))
- (when cat
- (with-temp-buffer
- (make-comint-in-buffer "test-comint-password" (current-buffer) cat)
- (let ((proc (get-buffer-process (current-buffer))))
- (set-process-query-on-exit-flag proc nil)
- (comint-send-string proc "Password: ")
- (comint-send-eof)
- (while (accept-process-output proc 0.1 nil t))
- (should (string-equal (buffer-substring-no-properties (point-min) (point-max))
- "Password: MaGiC-PaSsWoRd789\n"))
- (when (process-live-p proc)
- (kill-process proc))
- (accept-process-output proc 0 1 t)))))))
+ (comint-tests/test-password-function
+ (lambda (&rest _args) "MaGiC-PaSsWoRd789")))
(ert-deftest comint-test-password-function-with-nil ()
"Test that `comint-password-function' does not alter the normal
password flow if it returns a nil value."
- (cl-letf
- (((symbol-function 'read-passwd)
- (lambda (_prompt &optional _confirm _default)
- "PaSsWoRd456")))
- (let ((cat (executable-find "cat"))
- (comint-password-function (lambda (_prompt) nil)))
- (when cat
- (with-temp-buffer
- (make-comint-in-buffer "test-comint-password" (current-buffer) cat)
- (let ((proc (get-buffer-process (current-buffer))))
- (set-process-query-on-exit-flag proc nil)
- (comint-send-string proc "Password: ")
- (comint-send-eof)
- (while (accept-process-output proc 0.1 nil t))
- (should (string-equal (buffer-substring-no-properties (point-min) (point-max))
- "Password: PaSsWoRd456\n"))
- (when (process-live-p proc)
- (kill-process proc))
- (accept-process-output proc 0 1 t)))))))
+ (comint-tests/test-password-function #'ignore))
;; Local Variables:
;; no-byte-compile: t
diff --git a/test/lisp/completion-tests.el b/test/lisp/completion-tests.el
new file mode 100644
index 00000000000..c13fb2e44b7
--- /dev/null
+++ b/test/lisp/completion-tests.el
@@ -0,0 +1,170 @@
+;;; completion-tests.el --- Tests for completion.el -*- lexical-binding: t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+(require 'completion)
+
+(ert-deftest completion-test-cmpl-string-case-type ()
+ (should (eq (cmpl-string-case-type "123ABCDEF456") :up))
+ (should (eq (cmpl-string-case-type "123abcdef456") :down))
+ (should (eq (cmpl-string-case-type "123aBcDeF456") :mixed))
+ (should (eq (cmpl-string-case-type "123456") :neither))
+ (should (eq (cmpl-string-case-type "Abcde123") :capitalized)))
+
+(ert-deftest completion-test-cmpl-merge-string-cases ()
+ (should (equal (cmpl-merge-string-cases "AbCdEf456" "abc") "AbCdEf456"))
+ (should (equal (cmpl-merge-string-cases "abcdef456" "ABC") "ABCDEF456"))
+ (should (equal (cmpl-merge-string-cases "ABCDEF456" "Abc") "Abcdef456"))
+ (should (equal (cmpl-merge-string-cases "ABCDEF456" "abc") "abcdef456")))
+
+(ert-deftest completion-test-add-find-delete-tail ()
+ (unwind-protect
+ (progn
+ ;; - Add and Find -
+ (should (equal (add-completion-to-head "banana") '("banana" 0 nil 0)))
+ (should (equal (find-exact-completion "banana") '("banana" 0 nil 0)))
+ (should (equal (find-exact-completion "bana") nil))
+ (should (equal (car (find-cmpl-prefix-entry "ban")) '(("banana" 0 nil 0))))
+ (should (equal (cdr (find-cmpl-prefix-entry "ban")) '(("banana" 0 nil 0))))
+
+ (should (equal (add-completion-to-head "banish") '("banish" 0 nil 0)))
+ (should (equal (find-exact-completion "banish") '("banish" 0 nil 0)))
+ (should (equal (car (find-cmpl-prefix-entry "ban")) '(("banish" 0 nil 0) ("banana" 0 nil 0))))
+ (should (equal (cdr (find-cmpl-prefix-entry "ban")) '(("banana" 0 nil 0))))
+
+ (should (equal (add-completion-to-head "banana") '("banana" 0 nil 0)))
+ (should (equal (car (find-cmpl-prefix-entry "ban")) '(("banana" 0 nil 0) ("banish" 0 nil 0))))
+ (should (equal (cdr (find-cmpl-prefix-entry "ban")) '(("banish" 0 nil 0))))
+
+ ;; - Deleting -
+ (should (equal (add-completion-to-head "banner") '("banner" 0 nil 0)))
+ (delete-completion "banner")
+ (should-not (find-exact-completion "banner"))
+ (should (equal (car (find-cmpl-prefix-entry "ban")) '(("banana" 0 nil 0) ("banish" 0 nil 0))))
+ (should (equal (cdr (find-cmpl-prefix-entry "ban")) '(("banish" 0 nil 0))))
+ (should (equal (add-completion-to-head "banner") '("banner" 0 nil 0)))
+ (delete-completion "banana")
+ (should (equal (car (find-cmpl-prefix-entry "ban")) '(("banner" 0 nil 0) ("banish" 0 nil 0))))
+ (should (equal (cdr (find-cmpl-prefix-entry "ban")) '(("banish" 0 nil 0))))
+ (delete-completion "banner")
+ (delete-completion "banish")
+ (should-not (find-cmpl-prefix-entry "ban"))
+ (should-error (delete-completion "banner"))
+
+ ;; - Tail -
+ (should (equal (add-completion-to-tail-if-new "banana") '("banana" 0 nil 0)))
+ (should (equal (car (find-cmpl-prefix-entry "ban")) '(("banana" 0 nil 0))))
+ (should (equal (cdr (find-cmpl-prefix-entry "ban")) '(("banana" 0 nil 0))))
+ (add-completion-to-tail-if-new "banish") '("banish" 0 nil 0)
+ (should (equal (car (find-cmpl-prefix-entry "ban")) '(("banana" 0 nil 0) ("banish" 0 nil 0))))
+ (should (equal (cdr (find-cmpl-prefix-entry "ban")) '(("banish" 0 nil 0)))))
+ (ignore-errors (kill-completion "banana"))
+ (ignore-errors (kill-completion "banner"))
+ (ignore-errors (kill-completion "banish"))))
+
+(ert-deftest completion-test-add-find-accept-delete ()
+ (unwind-protect
+ (progn
+ ;; - Add and Find -
+ (add-completion "banana" 5 10)
+ (should (equal (find-exact-completion "banana") '("banana" 5 10 0)))
+ (add-completion "banana" 6)
+ (should (equal (find-exact-completion "banana") '("banana" 6 10 0)))
+ (add-completion "banish")
+ (should (equal (car (find-cmpl-prefix-entry "ban")) '(("banish" 0 nil 0) ("banana" 6 10 0))))
+
+ ;; - Accepting -
+ (setq completion-to-accept "banana")
+ (accept-completion)
+ (should (equal (find-exact-completion "banana") '("banana" 7 10 0)))
+ (should (equal (car (find-cmpl-prefix-entry "ban")) '(("banana" 7 10 0) ("banish" 0 nil 0))))
+ (setq completion-to-accept "banish")
+ (add-completion "banner")
+ (should (equal (car (find-cmpl-prefix-entry "ban"))
+ '(("banner" 0 nil 0) ("banish" 1 nil 0) ("banana" 7 10 0))))
+
+ ;; - Deleting -
+ (kill-completion "banish")
+ (should (equal (car (find-cmpl-prefix-entry "ban")) '(("banner" 0 nil 0) ("banana" 7 10 0)))))
+ (ignore-errors (kill-completion "banish"))
+ (ignore-errors (kill-completion "banana"))
+ (ignore-errors (kill-completion "banner"))))
+
+(ert-deftest completion-test-search ()
+ (unwind-protect
+ (progn
+ ;; - Add and Find -
+ (add-completion "banana")
+ (completion-search-reset "ban")
+ (should (equal (car (completion-search-next 0)) "banana"))
+
+ ;; - Discrimination -
+ (add-completion "cumberland")
+ (add-completion "cumberbund")
+ ;; cumbering
+ (completion-search-reset "cumb")
+ (should (equal (car (completion-search-peek t)) "cumberbund"))
+ (should (equal (car (completion-search-next 0)) "cumberbund"))
+ (should (equal (car (completion-search-peek t)) "cumberland"))
+ (should (equal (car (completion-search-next 1)) "cumberland"))
+ (should-not (completion-search-peek nil))
+
+ ;; FIXME
+ ;; (should (equal (completion-search-next 2) "cumbering")) ; {cdabbrev}
+ ;;(completion-search-next 3) --> nil or "cumming" {depends on context}
+
+ (should (equal (car (completion-search-next 1)) "cumberland"))
+
+ ;; FIXME
+ ;; (should (equal (completion-search-peek t) "cumbering")) ; {cdabbrev}
+
+ ;; - Accepting -
+ (should (equal (car (completion-search-next 1)) "cumberland"))
+ (setq completion-to-accept "cumberland")
+ (completion-search-reset "foo")
+ (completion-search-reset "cum")
+ (should (equal (car (completion-search-next 0)) "cumberland"))
+
+ ;; - Deleting -
+ (kill-completion "cumberland")
+ (add-completion "cummings")
+ (completion-search-reset "cum")
+ (should (equal (car (completion-search-next 0)) "cummings"))
+ (should (equal (car (completion-search-next 1)) "cumberbund"))
+
+ ;; - Ignoring Capitalization -
+ (completion-search-reset "CuMb")
+ (should (equal (car (completion-search-next 0)) "cumberbund")))
+ (ignore-errors (kill-completion "banana"))
+ (ignore-errors (kill-completion "cumberland"))
+ (ignore-errors (kill-completion "cumberbund"))
+ (ignore-errors (kill-completion "cummings"))))
+
+(ert-deftest completion-test-lisp-def-regexp ()
+ (should (= (and (string-match *lisp-def-regexp* "\n(defun foo") (match-end 0)) 8))
+ (should (= (and (string-match *lisp-def-regexp* "\n(si:def foo") (match-end 0)) 9))
+ (should (= (and (string-match *lisp-def-regexp* "\n(def-bar foo")(match-end 0)) 10))
+ (should (= (and (string-match *lisp-def-regexp* "\n(defun (foo") (match-end 0)) 9)))
+
+(provide 'completion-tests)
+;;; completion-tests.el ends here
diff --git a/test/lisp/cus-edit-tests.el b/test/lisp/cus-edit-tests.el
new file mode 100644
index 00000000000..95f62e0d7ea
--- /dev/null
+++ b/test/lisp/cus-edit-tests.el
@@ -0,0 +1,80 @@
+;;; cus-edit-tests.el --- Tests for cus-edit.el -*- lexical-binding: t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+(require 'ert-x)
+(eval-when-compile (require 'cl-lib))
+(require 'cus-edit)
+
+(defmacro with-cus-edit-test (buffer &rest body)
+ (declare (indent 1))
+ `(save-window-excursion
+ (unwind-protect
+ (progn ,@body)
+ (when-let ((buf (get-buffer ,buffer)))
+ (kill-buffer buf)))))
+
+
+;;;; showing/hiding obsolete options
+
+(defgroup cus-edit-tests nil "test"
+ :group 'test-group)
+
+(defcustom cus-edit-tests--obsolete-option-tag nil
+ "This should never be removed; it is obsolete for testing purposes."
+ :type 'boolean
+ :version "917.10") ; a super high version number
+(make-obsolete-variable 'cus-edit-tests--obsolete-option-tag nil "X.X-test")
+(defconst cus-edit-tests--obsolete-option-tag
+ (custom-unlispify-tag-name 'cus-edit-tests--obsolete-option-tag))
+
+(ert-deftest cus-edit-tests-customize-apropos/hide-obsolete ()
+ (with-cus-edit-test "*Customize Apropos*"
+ (customize-apropos "cus-edit-tests")
+ (should-not (search-forward cus-edit-tests--obsolete-option-tag nil t))))
+
+(ert-deftest cus-edit-tests-customize-changed-options/hide-obsolete ()
+ (with-cus-edit-test "*Customize Changed Options*"
+ (customize-changed-options "917.2") ; some future version
+ (should-not (search-forward cus-edit-tests--obsolete-option-tag nil t))))
+
+(ert-deftest cus-edit-tests-customize-group/hide-obsolete ()
+ "Check that obsolete variables do not show up."
+ (with-cus-edit-test "*Customize Group: Cus Edit Tests*"
+ (customize-group 'cus-edit-tests)
+ (should-not (search-forward cus-edit-tests--obsolete-option-tag nil t))))
+
+(ert-deftest cus-edit-tests-customize-option/show-obsolete ()
+ (with-cus-edit-test "*Customize Option: Cus Edit Tests Obsolete Option Tag*"
+ (customize-option 'cus-edit-tests--obsolete-option-tag)
+ (goto-char (point-min))
+ (should (search-forward cus-edit-tests--obsolete-option-tag nil t))))
+
+(ert-deftest cus-edit-tests-customize-saved/show-obsolete ()
+ (with-cus-edit-test "*Customize Saved*"
+ (cl-letf (((get 'cus-edit-tests--obsolete-option-tag 'saved-value) '(t)))
+ (customize-saved)
+ (should (search-forward cus-edit-tests--obsolete-option-tag nil t)))))
+
+(provide 'cus-edit-tests)
+;;; cus-edit-tests.el ends here
diff --git a/test/lisp/custom-resources/custom--test-theme.el b/test/lisp/custom-resources/custom--test-theme.el
index da9121e0a0a..4ced98a50bc 100644
--- a/test/lisp/custom-resources/custom--test-theme.el
+++ b/test/lisp/custom-resources/custom--test-theme.el
@@ -1,3 +1,5 @@
+;;; custom--test-theme.el -- A test theme. -*- lexical-binding:t -*-
+
(deftheme custom--test
"A test theme.")
diff --git a/test/lisp/custom-tests.el b/test/lisp/custom-tests.el
index 40b06cb2701..10854c71d56 100644
--- a/test/lisp/custom-tests.el
+++ b/test/lisp/custom-tests.el
@@ -20,6 +20,7 @@
;;; Code:
(require 'ert)
+(require 'ert-x)
(require 'wid-edit)
(require 'cus-edit)
@@ -99,10 +100,8 @@
;; This is demonstrating bug#34027.
(ert-deftest custom--test-theme-variables ()
"Test variables setting with enabling / disabling a custom theme."
- :expected-result :failed
;; We load custom-resources/custom--test-theme.el.
- (let ((custom-theme-load-path
- `(,(expand-file-name "custom-resources" (file-name-directory #$)))))
+ (let ((custom-theme-load-path `(,(ert-resource-directory))))
(load-theme 'custom--test 'no-confirm 'no-enable)
;; The variables have still their initial values.
(should (equal custom--test-user-option 'foo))
@@ -115,15 +114,10 @@
(should (equal custom--test-user-option 'baz))
(should (equal custom--test-variable 'baz))
+ ;; Enable and then disable.
(enable-theme 'custom--test)
- ;; The variables have the theme values.
- (should (equal custom--test-user-option 'bar))
- (should (equal custom--test-variable 'bar))
-
(disable-theme 'custom--test)
;; The variables should have the changed values, by reverting.
- ;; This doesn't work as expected. Instead, they have their
- ;; initial values `foo'.
(should (equal custom--test-user-option 'baz))
(should (equal custom--test-variable 'baz))))
@@ -151,6 +145,26 @@
(widget-apply field :value-to-internal origvalue)
"bar"))))))
+(defconst custom-test-admin-cus-test
+ (expand-file-name "admin/cus-test.el" source-directory))
+
+(declare-function cus-test-opts custom-test-admin-cus-test)
+
+(ert-deftest check-for-wrong-custom-types ()
+ :tags '(:expensive-test)
+ (skip-unless (file-readable-p custom-test-admin-cus-test))
+ (load custom-test-admin-cus-test)
+ (should (null (cus-test-opts t))))
+
+(ert-deftest custom-test-enable-theme-keeps-settings ()
+ "Test that enabling a theme doesn't change its settings."
+ (let* ((custom-theme-load-path `(,(ert-resource-directory)))
+ settings)
+ (load-theme 'custom--test 'no-confirm 'no-enable)
+ (setq settings (get 'custom--test 'theme-settings))
+ (enable-theme 'custom--test)
+ (should (equal settings (get 'custom--test 'theme-settings)))))
+
(defcustom custom--test-local-option 'initial
"Buffer-local user option for testing."
:group 'emacs
diff --git a/test/lisp/dabbrev-tests.el b/test/lisp/dabbrev-tests.el
index b71960f1303..0b20dcf9213 100644
--- a/test/lisp/dabbrev-tests.el
+++ b/test/lisp/dabbrev-tests.el
@@ -1,4 +1,4 @@
-;;; dabbrev-tests.el --- Test suite for dabbrev.
+;;; dabbrev-tests.el --- Test suite for dabbrev. -*- lexical-binding:t -*-
;; Copyright (C) 2016-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/descr-text-tests.el b/test/lisp/descr-text-tests.el
index 50e36dffb43..6ba455b50d4 100644
--- a/test/lisp/descr-text-tests.el
+++ b/test/lisp/descr-text-tests.el
@@ -75,18 +75,18 @@
(goto-char (point-min))
(should (eq ?a (following-char))) ; make sure we are where we think we are
;; Function should return nil for an ASCII character.
- (should (not (describe-char-eldoc)))
+ (should (not (describe-char-eldoc 'ignore)))
(goto-char (1+ (point)))
(should (eq ?… (following-char)))
(let ((eldoc-echo-area-use-multiline-p t))
;; Function should return description of an Unicode character.
(should (equal "U+2026: Horizontal ellipsis (Po: Punctuation, Other)"
- (describe-char-eldoc))))
+ (describe-char-eldoc 'ignore))))
(goto-char (point-max))
;; At the end of the buffer, function should return nil and not blow up.
- (should (not (describe-char-eldoc)))))
+ (should (not (describe-char-eldoc 'ignore)))))
(provide 'descr-text-test)
diff --git a/test/lisp/dired-aux-tests.el b/test/lisp/dired-aux-tests.el
index c3fe100504b..7f1743f88d7 100644
--- a/test/lisp/dired-aux-tests.el
+++ b/test/lisp/dired-aux-tests.el
@@ -28,7 +28,7 @@
(let* ((foo (make-temp-file "foo"))
(files (list foo)))
(unwind-protect
- (cl-letf (((symbol-function 'y-or-n-p) 'error))
+ (cl-letf (((symbol-function 'read-char-from-minibuffer) 'error))
(dired temporary-file-directory)
(dired-goto-file foo)
;; `dired-do-shell-command' returns nil on success.
@@ -40,7 +40,7 @@
(should-not (dired-do-shell-command "ls ? ./`?`" nil files)))
(delete-file foo))))
-;; Auxiliar macro for `dired-test-bug28834': it binds
+;; Auxiliary macro for `dired-test-bug28834': it binds
;; `dired-create-destination-dirs' to CREATE-DIRS and execute BODY.
;; If YES-OR-NO is non-nil, it binds `yes-or-no-p' to
;; to avoid the prompt.
@@ -114,6 +114,49 @@
(mapc #'delete-file `(,file1 ,file2))
(kill-buffer buf)))))
+(defun dired-test--check-highlighting (command positions)
+ (let ((start 1))
+ (dolist (pos positions)
+ (should-not (text-property-not-all start (1- pos) 'face nil command))
+ (should (equal 'warning (get-text-property pos 'face command)))
+ (setq start (1+ pos)))
+ (should-not (text-property-not-all
+ start (length command) 'face nil command))))
+
+(ert-deftest dired-test-highlight-metachar ()
+ "Check that non-isolated meta-characters are highlighted."
+ (let* ((command "sed -r -e 's/oo?/a/' -e 's/oo?/a/' ? `?`")
+ (markers " ^ ^")
+ (result (dired--highlight-no-subst-chars
+ (dired--need-confirm-positions command "?")
+ command
+ t))
+ (lines (split-string result "\n")))
+ (should (= (length lines) 2))
+ (should (string-match (regexp-quote command) (nth 0 lines)))
+ (should (string-match (regexp-quote markers) (nth 1 lines)))
+ (dired-test--check-highlighting (nth 0 lines) '(15 29)))
+ ;; Note that `?` is considered isolated, but `*` is not.
+ (let* ((command "sed -e 's/o*/a/' -e 's/o`*` /a/'")
+ (markers " ^ ^")
+ (result (dired--highlight-no-subst-chars
+ (dired--need-confirm-positions command "*")
+ command
+ t))
+ (lines (split-string result "\n")))
+ (should (= (length lines) 2))
+ (should (string-match (regexp-quote command) (nth 0 lines)))
+ (should (string-match (regexp-quote markers) (nth 1 lines)))
+ (dired-test--check-highlighting (nth 0 lines) '(11 25)))
+ (let* ((command "sed 's/\\?/!/'")
+ (result (dired--highlight-no-subst-chars
+ (dired--need-confirm-positions command "?")
+ command
+ nil))
+ (lines (split-string result "\n")))
+ (should (= (length lines) 1))
+ (should (string-match (regexp-quote command) (nth 0 lines)))
+ (dired-test--check-highlighting (nth 0 lines) '(8))))
(provide 'dired-aux-tests)
;; dired-aux-tests.el ends here
diff --git a/test/lisp/dired-tests.el b/test/lisp/dired-tests.el
index 02438a2cb28..aac78c64c69 100644
--- a/test/lisp/dired-tests.el
+++ b/test/lisp/dired-tests.el
@@ -24,11 +24,11 @@
(ert-deftest dired-autoload ()
"Tests to see whether dired-x has been autoloaded"
(should
- (fboundp 'dired-jump))
+ (fboundp 'dired-do-relsymlink))
(should
(autoloadp
(symbol-function
- 'dired-jump))))
+ 'dired-do-relsymlink))))
(ert-deftest dired-test-bug22694 ()
"Test for https://debbugs.gnu.org/22694 ."
@@ -293,6 +293,7 @@
(ert-deftest dired-test-bug27899 ()
"Test for https://debbugs.gnu.org/27899 ."
+ :tags '(:unstable)
(dired (list (expand-file-name "src" source-directory)
"cygw32.c" "alloc.c" "w32xfns.c" "xdisp.c"))
(let ((orig dired-hide-details-mode))
@@ -440,6 +441,81 @@
(should (= 6 (length (dired-get-marked-files)))) ; All empty dirs but zeta-empty-dir deleted.
(advice-remove 'read-answer 'dired-test-bug27940-advice))))
+(ert-deftest dired-test-directory-files ()
+ "Test for `directory-files'."
+ (let ((testdir (expand-file-name
+ "directory-files-test" (temporary-file-directory)))
+ (nod directory-files-no-dot-files-regexp))
+ (unwind-protect
+ (progn
+ (when (file-directory-p testdir)
+ (delete-directory testdir t))
+
+ (make-directory testdir)
+ (when (file-directory-p testdir)
+ ;; directory-empty-p: test non-existent dir
+ (should-not (directory-empty-p "some-imaginary-dir"))
+ (should (= 2 (length (directory-files testdir))))
+ ;; directory-empty-p: test empty dir
+ (should (directory-empty-p testdir))
+ (should-not (directory-files testdir nil nod t 1))
+ (dolist (file '(a b c d))
+ (make-empty-file (expand-file-name (symbol-name file) testdir)))
+ (should (= 6 (length (directory-files testdir))))
+ (should (equal "abcd" (mapconcat 'identity (directory-files
+ testdir nil nod) "")))
+ (should (= 2 (length (directory-files testdir nil "[bc]"))))
+ (should (= 3 (length (directory-files testdir nil nod nil 3))))
+ (dolist (file '(5 4 3 2 1))
+ (make-empty-file
+ (expand-file-name (number-to-string file) testdir)))
+ ;;(should (= 0 (length (directory-files testdir nil "[0-9]" t -1))))
+ (should (= 5 (length (directory-files testdir nil "[0-9]" t))))
+ (should (= 5 (length (directory-files testdir nil "[0-9]" t 50))))
+ (should-not (directory-empty-p testdir)))
+
+ (delete-directory testdir t)))))
+
+(ert-deftest dired-test-directory-files-and-attributes ()
+ "Test for `directory-files-and-attributes'."
+ (let ((testdir (expand-file-name
+ "directory-files-test" (temporary-file-directory)))
+ (nod directory-files-no-dot-files-regexp))
+
+ (unwind-protect
+ (progn
+ (when (file-directory-p testdir)
+ (delete-directory testdir t))
+
+ (make-directory testdir)
+ (when (file-directory-p testdir)
+ (should (= 2 (length (directory-files testdir))))
+ (should-not (directory-files-and-attributes testdir t nod t 1))
+ (dolist (file '(a b c d))
+ (make-directory (expand-file-name (symbol-name file) testdir)))
+ (should (= 6 (length (directory-files-and-attributes testdir))))
+ (dolist (dir (directory-files-and-attributes testdir t nod))
+ (should (file-directory-p (car dir)))
+ (should-not (file-regular-p (car dir))))
+ (should (= 2 (length
+ (directory-files-and-attributes testdir nil "[bc]"))))
+ (should (= 3 (length
+ (directory-files-and-attributes
+ testdir nil nod nil nil 3))))
+ (dolist (file '(5 4 3 2 1))
+ (make-empty-file
+ (expand-file-name (number-to-string file) testdir)))
+ ;; (should (= 0 (length (directory-files-and-attributes testdir nil
+ ;; "[0-9]" t
+ ;; nil -1))))
+ (should (= 5 (length
+ (directory-files-and-attributes
+ testdir nil "[0-9]" t))))
+ (should (= 5 (length
+ (directory-files-and-attributes
+ testdir nil "[0-9]" t nil 50))))))
+ (when (file-directory-p testdir)
+ (delete-directory testdir t)))))
(provide 'dired-tests)
;; dired-tests.el ends here
diff --git a/test/lisp/dom-tests.el b/test/lisp/dom-tests.el
index faa735f198c..dbe3a15dac1 100644
--- a/test/lisp/dom-tests.el
+++ b/test/lisp/dom-tests.el
@@ -84,6 +84,13 @@
(dom-set-attribute dom attr value)
(should (equal (dom-attr dom attr) value))))
+(ert-deftest dom-tests-remove-attribute ()
+ (let ((dom (copy-tree '(body ((foo . "bar") (zot . "foobar"))))))
+ (should (equal (dom-attr dom 'foo) "bar"))
+ (dom-remove-attribute dom 'foo)
+ (should (equal (dom-attr dom 'foo) nil))
+ (should (equal dom '(body ((zot . "foobar")))))))
+
(ert-deftest dom-tests-attr ()
(let ((dom (dom-tests--tree)))
(should-not (dom-attr dom 'id))
diff --git a/test/lisp/electric-tests.el b/test/lisp/electric-tests.el
index 8dd243f735c..1b7beeaa366 100644
--- a/test/lisp/electric-tests.el
+++ b/test/lisp/electric-tests.el
@@ -5,18 +5,20 @@
;; Author: João Távora <joaotavora@gmail.com>
;; Keywords:
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
@@ -547,6 +549,24 @@ baz\"\""
(should (equal "" (buffer-string))))))
+;;; Undoing
+(ert-deftest electric-pair-undo-unrelated-state ()
+ "Make sure `electric-pair-mode' does not confuse `undo' (bug#39680)."
+ (with-temp-buffer
+ (buffer-enable-undo)
+ (electric-pair-local-mode)
+ (let ((last-command-event ?\())
+ (ert-simulate-command '(self-insert-command 1)))
+ (undo-boundary)
+ (let ((last-command-event ?a))
+ (ert-simulate-command '(self-insert-command 1)))
+ (undo-boundary)
+ (ert-simulate-command '(undo))
+ (let ((last-command-event ?\())
+ (ert-simulate-command '(self-insert-command 1)))
+ (should (string= (buffer-string) "(())"))))
+
+
;;; Electric newlines between pairs
;;; TODO: better tests
(ert-deftest electric-pair-open-extra-newline ()
diff --git a/test/lisp/elide-head-tests.el b/test/lisp/elide-head-tests.el
new file mode 100644
index 00000000000..4b9a559ac75
--- /dev/null
+++ b/test/lisp/elide-head-tests.el
@@ -0,0 +1,62 @@
+;;; elide-head-tests.el --- Tests for elide-head.el -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+;; Author: Simen Heggestøyl <simenheg@gmail.com>
+;; Keywords:
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'elide-head)
+(require 'ert)
+
+(ert-deftest elide-head-tests-elide-head ()
+ (let ((elide-head-headers-to-hide '(("START" . "END"))))
+ (with-temp-buffer
+ (insert "foo\nSTART\nHIDDEN\nEND\nbar")
+ (elide-head)
+ (let ((o (car (overlays-at 14))))
+ (should (= (overlay-start o) 10))
+ (should (= (overlay-end o) 21))
+ (should (overlay-get o 'invisible))
+ (should (overlay-get o 'evaporate))))))
+
+(ert-deftest elide-head-tests-elide-head-with-prefix-arg ()
+ (let ((elide-head-headers-to-hide '(("START" . "END"))))
+ (with-temp-buffer
+ (insert "foo\nSTART\nHIDDEN\nEND\nbar")
+ (elide-head)
+ (should (overlays-at 14))
+ (elide-head t)
+ (should-not (overlays-at 14)))))
+
+(ert-deftest elide-head-tests-show ()
+ (let ((elide-head-headers-to-hide '(("START" . "END"))))
+ (with-temp-buffer
+ (insert "foo\nSTART\nHIDDEN\nEND\nbar")
+ (elide-head)
+ (should (overlays-at 14))
+ (elide-head-show)
+ (should-not (overlays-at 14)))))
+
+(provide 'elide-head-tests)
+;;; elide-head-tests.el ends here
diff --git a/test/lisp/emacs-lisp/bindat-tests.el b/test/lisp/emacs-lisp/bindat-tests.el
index b45cd69467b..a9a881987c0 100644
--- a/test/lisp/emacs-lisp/bindat-tests.el
+++ b/test/lisp/emacs-lisp/bindat-tests.el
@@ -1,4 +1,4 @@
-;;; bindat-tests.el --- tests for bindat.el -*- lexical-binding: t; -*-
+;;; bindat-tests.el --- tests for bindat.el -*- lexical-binding: t; coding: utf-8; -*-
;; Copyright (C) 2019-2021 Free Software Foundation, Inc.
@@ -94,6 +94,28 @@
(src-ip .
[192 168 1 101])
(dest-ip .
- [192 168 1 100]))))))
+ [192 168 1 100]))))))
+
+(ert-deftest bindat-test-pack/multibyte-string-fails ()
+ (should-error (bindat-pack nil nil "ö")))
+
+(ert-deftest bindat-test-unpack/multibyte-string-fails ()
+ (should-error (bindat-unpack nil "ö")))
+
+(ert-deftest bindat-test-format-vector ()
+ (should (equal (bindat-format-vector [1 2 3] "%d" "x" 2) "1x2"))
+ (should (equal (bindat-format-vector [1 2 3] "%d" "x") "1x2x3")))
+
+(ert-deftest bindat-test-vector-to-dec ()
+ (should (equal (bindat-vector-to-dec [1 2 3]) "1.2.3"))
+ (should (equal (bindat-vector-to-dec [2048 1024 512] ".") "2048.1024.512")))
+
+(ert-deftest bindat-test-vector-to-hex ()
+ (should (equal (bindat-vector-to-hex [1 2 3]) "01:02:03"))
+ (should (equal (bindat-vector-to-hex [2048 1024 512] ".") "800.400.200")))
+
+(ert-deftest bindat-test-ip-to-string ()
+ (should (equal (bindat-ip-to-string [192 168 0 1]) "192.168.0.1"))
+ (should (equal (bindat-ip-to-string "\300\250\0\1") "192.168.0.1")))
;;; bindat-tests.el ends here
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/error-lexical-var-with-add-hook.el b/test/lisp/emacs-lisp/bytecomp-resources/error-lexical-var-with-add-hook.el
new file mode 100644
index 00000000000..5f390898e6a
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/error-lexical-var-with-add-hook.el
@@ -0,0 +1,4 @@
+;;; -*- lexical-binding: t; -*-
+(let ((foo nil))
+ (add-hook 'foo #'next-line)
+ foo)
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/error-lexical-var-with-remove-hook.el b/test/lisp/emacs-lisp/bytecomp-resources/error-lexical-var-with-remove-hook.el
new file mode 100644
index 00000000000..eaa625eba1c
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/error-lexical-var-with-remove-hook.el
@@ -0,0 +1,4 @@
+;;; -*- lexical-binding: t; -*-
+(let ((foo nil))
+ (remove-hook 'foo #'next-line)
+ foo)
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/error-lexical-var-with-run-hook-with-args-until-failure.el b/test/lisp/emacs-lisp/bytecomp-resources/error-lexical-var-with-run-hook-with-args-until-failure.el
new file mode 100644
index 00000000000..7a116ad464b
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/error-lexical-var-with-run-hook-with-args-until-failure.el
@@ -0,0 +1,3 @@
+;;; -*- lexical-binding: t; -*-
+(let ((foo nil))
+ (run-hook-with-args-until-failure 'foo))
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/error-lexical-var-with-run-hook-with-args-until-success.el b/test/lisp/emacs-lisp/bytecomp-resources/error-lexical-var-with-run-hook-with-args-until-success.el
new file mode 100644
index 00000000000..96d10a343df
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/error-lexical-var-with-run-hook-with-args-until-success.el
@@ -0,0 +1,3 @@
+;;; -*- lexical-binding: t; -*-
+(let ((foo nil))
+ (run-hook-with-args-until-success 'foo #'next-line))
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/error-lexical-var-with-run-hook-with-args.el b/test/lisp/emacs-lisp/bytecomp-resources/error-lexical-var-with-run-hook-with-args.el
new file mode 100644
index 00000000000..bb9101bd070
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/error-lexical-var-with-run-hook-with-args.el
@@ -0,0 +1,3 @@
+;;; -*- lexical-binding: t; -*-
+(let ((foo nil))
+ (run-hook-with-args 'foo))
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/error-lexical-var-with-symbol-value.el b/test/lisp/emacs-lisp/bytecomp-resources/error-lexical-var-with-symbol-value.el
new file mode 100644
index 00000000000..5f390898e6a
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/error-lexical-var-with-symbol-value.el
@@ -0,0 +1,4 @@
+;;; -*- lexical-binding: t; -*-
+(let ((foo nil))
+ (add-hook 'foo #'next-line)
+ foo)
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-autoload-not-on-top-level.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-autoload-not-on-top-level.el
new file mode 100644
index 00000000000..f193130c6ca
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-autoload-not-on-top-level.el
@@ -0,0 +1,3 @@
+;;; -*- lexical-binding: t -*-
+(defun foo ()
+ (autoload 'bar "baz" nil nil 'macro))
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-callargs.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-callargs.el
new file mode 100644
index 00000000000..687add380b9
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-callargs.el
@@ -0,0 +1,5 @@
+;;; -*- lexical-binding: t -*-
+(defun foo (_x)
+ nil)
+(defun bar ()
+ (foo 1 2))
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-defcustom-nogroup.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-defcustom-nogroup.el
new file mode 100644
index 00000000000..a67d4f041f3
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-defcustom-nogroup.el
@@ -0,0 +1,3 @@
+;;; -*- lexical-binding: t -*-
+(defcustom foo nil
+ :type 'boolean)
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-defcustom-notype.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-defcustom-notype.el
new file mode 100644
index 00000000000..c15ab9b192a
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-defcustom-notype.el
@@ -0,0 +1,3 @@
+;;; -*- lexical-binding: t -*-
+(defcustom foo nil
+ :group 'emacs)
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-defvar-lacks-prefix.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-defvar-lacks-prefix.el
new file mode 100644
index 00000000000..9f3cbb98900
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-defvar-lacks-prefix.el
@@ -0,0 +1,2 @@
+;;; -*- lexical-binding: t -*-
+(defvar foo nil)
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-format.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-format.el
new file mode 100644
index 00000000000..a1902bc03b0
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-format.el
@@ -0,0 +1,2 @@
+;;; -*- lexical-binding: t -*-
+(message "%s" 1 2)
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-free-setq.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-free-setq.el
new file mode 100644
index 00000000000..6e187129c9b
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-free-setq.el
@@ -0,0 +1,2 @@
+;;; -*- lexical-binding: t -*-
+(setq foo 'bar)
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-free-variable-reference.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-free-variable-reference.el
new file mode 100644
index 00000000000..50a95272874
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-free-variable-reference.el
@@ -0,0 +1,4 @@
+;;; -*- lexical-binding: t -*-
+(defvar xxx-test)
+(defun foo ()
+ (setq xxx-test bar))
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-interactive-only.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-interactive-only.el
new file mode 100644
index 00000000000..9e0c99bd30b
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-interactive-only.el
@@ -0,0 +1,3 @@
+;;; -*- lexical-binding: t -*-
+(defun foo ()
+ (next-line))
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-lambda-malformed-interactive-spec.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-lambda-malformed-interactive-spec.el
new file mode 100644
index 00000000000..6bd902705ed
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-lambda-malformed-interactive-spec.el
@@ -0,0 +1,4 @@
+;;; -*- lexical-binding: t -*-
+(defun foo ()
+ (interactive "foo" "bar")
+ nil)
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-make-variable-buffer-local.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-make-variable-buffer-local.el
new file mode 100644
index 00000000000..aa1e6c0463b
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-make-variable-buffer-local.el
@@ -0,0 +1,4 @@
+;;; -*- lexical-binding: t -*-
+(defvar foobar)
+(defun foo ()
+ (make-variable-buffer-local 'foobar))
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-obsolete-defun.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-obsolete-defun.el
new file mode 100644
index 00000000000..2a7af617ac9
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-obsolete-defun.el
@@ -0,0 +1,8 @@
+;;; -*- lexical-binding: t -*-
+
+(defun foo-obsolete ()
+ (declare (obsolete nil "99.99"))
+ nil)
+
+(defun foo ()
+ (foo-obsolete))
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-obsolete-hook.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-obsolete-hook.el
new file mode 100644
index 00000000000..078e6e4a3a9
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-obsolete-hook.el
@@ -0,0 +1,3 @@
+;;; -*- lexical-binding: t -*-
+(defun foo ()
+ (add-hook 'bytecomp--tests-obsolete-var #'next-line))
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-obsolete-variable-same-file.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-obsolete-variable-same-file.el
new file mode 100644
index 00000000000..31deb6155ba
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-obsolete-variable-same-file.el
@@ -0,0 +1,13 @@
+;;; -*- lexical-binding: t -*-
+
+(defvar foo-obsolete nil)
+(make-obsolete-variable 'foo-obsolete nil "99.99")
+
+;; From bytecomp.el:
+;; If foo.el declares `toto' as obsolete, it is likely that foo.el will
+;; actually use `toto' in order for this obsolete variable to still work
+;; correctly, so paradoxically, while byte-compiling foo.el, the presence
+;; of a make-obsolete-variable call for `toto' is an indication that `toto'
+;; should not trigger obsolete-warnings in foo.el.
+(defun foo ()
+ foo-obsolete)
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-obsolete-variable.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-obsolete-variable.el
new file mode 100644
index 00000000000..9a517cc6767
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-obsolete-variable.el
@@ -0,0 +1,4 @@
+;;; -*- lexical-binding: t -*-
+
+(defun foo ()
+ bytecomp--tests-obsolete-var)
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-redefine-defun-as-macro.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-redefine-defun-as-macro.el
new file mode 100644
index 00000000000..6bd239b6598
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-redefine-defun-as-macro.el
@@ -0,0 +1,3 @@
+;;; -*- lexical-binding: t -*-
+(defun foo () nil)
+(defmacro foo () t)
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-redefine-defun.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-redefine-defun.el
new file mode 100644
index 00000000000..53e4c0ac8de
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-redefine-defun.el
@@ -0,0 +1,3 @@
+;;; -*- lexical-binding: t -*-
+(defun foo () nil)
+(defun foo () t)
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-redefine-macro-as-defun.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-redefine-macro-as-defun.el
new file mode 100644
index 00000000000..f71ae445615
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-redefine-macro-as-defun.el
@@ -0,0 +1,3 @@
+;;; -*- lexical-binding: t -*-
+(defmacro foo () t)
+(defun foo () nil)
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-save-excursion.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-save-excursion.el
new file mode 100644
index 00000000000..38185457192
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-save-excursion.el
@@ -0,0 +1,5 @@
+;;; -*- lexical-binding: t -*-
+(defun foo ()
+ (save-excursion
+ (set-buffer (current-buffer))
+ nil))
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-variable-let-bind-constant.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-variable-let-bind-constant.el
new file mode 100644
index 00000000000..cc1fb572577
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-variable-let-bind-constant.el
@@ -0,0 +1,3 @@
+;;; -*- lexical-binding: t -*-
+(defun foo ()
+ (let ((t 1)) t))
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-variable-let-bind-nonvariable.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-variable-let-bind-nonvariable.el
new file mode 100644
index 00000000000..dde2dcee6e7
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-variable-let-bind-nonvariable.el
@@ -0,0 +1,3 @@
+;;; -*- lexical-binding: t -*-
+(defun foo ()
+ (let (('t 1)) t))
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-variable-set-constant.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-variable-set-constant.el
new file mode 100644
index 00000000000..2fc0680cfab
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-variable-set-constant.el
@@ -0,0 +1,3 @@
+;;; -*- lexical-binding: t -*-
+(defun foo ()
+ (setq t nil))
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-variable-set-nonvariable.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-variable-set-nonvariable.el
new file mode 100644
index 00000000000..0c76c4d388b
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-variable-set-nonvariable.el
@@ -0,0 +1,3 @@
+;;; -*- lexical-binding: t -*-
+(defun foo ()
+ (set '(a) nil))
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-autoload.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-autoload.el
new file mode 100644
index 00000000000..96deb1bbb0a
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-autoload.el
@@ -0,0 +1,3 @@
+;;; -*- lexical-binding: t -*-
+(autoload 'foox "foo"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-custom-declare-variable.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-custom-declare-variable.el
new file mode 100644
index 00000000000..2a4700bfda5
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-custom-declare-variable.el
@@ -0,0 +1,4 @@
+;;; -*- lexical-binding: t -*-
+(custom-declare-variable
+ 'foo t
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-defalias.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-defalias.el
new file mode 100644
index 00000000000..a4235d22bd3
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-defalias.el
@@ -0,0 +1,3 @@
+;;; -*- lexical-binding: t -*-
+(defalias 'foo #'ignore
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-defconst.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-defconst.el
new file mode 100644
index 00000000000..946f01989a0
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-defconst.el
@@ -0,0 +1,3 @@
+;;; -*- lexical-binding: t -*-
+(defconst foo-bar nil
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-define-abbrev-table.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-define-abbrev-table.el
new file mode 100644
index 00000000000..3da9ccd48c6
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-define-abbrev-table.el
@@ -0,0 +1,3 @@
+;;; -*- lexical-binding: t -*-
+(define-abbrev-table 'foo ()
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-define-obsolete-function-alias.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-define-obsolete-function-alias.el
new file mode 100644
index 00000000000..fea841b12ec
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-define-obsolete-function-alias.el
@@ -0,0 +1,3 @@
+;;; -*- lexical-binding: t -*-
+(define-obsolete-function-alias 'foo #'ignore "99.1"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-define-obsolete-variable-alias.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-define-obsolete-variable-alias.el
new file mode 100644
index 00000000000..2d5f201cb65
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-define-obsolete-variable-alias.el
@@ -0,0 +1,3 @@
+;;; -*- lexical-binding: t -*-
+(define-obsolete-variable-alias 'foo 'ignore "99.1"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-defun.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-defun.el
new file mode 100644
index 00000000000..94b0e80c979
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-defun.el
@@ -0,0 +1,3 @@
+;;; -*- lexical-binding: t -*-
+(defun foo ()
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-defvar.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-defvar.el
new file mode 100644
index 00000000000..99aacd09cbd
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-defvar.el
@@ -0,0 +1,6 @@
+;;; -*- lexical-binding: t -*-
+(defvar foo-bar nil
+ "multiline
+foo
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+bar")
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-defvaralias.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-defvaralias.el
new file mode 100644
index 00000000000..52fdc17f5bf
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-defvaralias.el
@@ -0,0 +1,3 @@
+;;; -*- lexical-binding: t -*-
+(defvaralias 'foo-bar #'ignore
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-ignore-fill-column.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-ignore-fill-column.el
new file mode 100644
index 00000000000..1ff554f3704
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-ignore-fill-column.el
@@ -0,0 +1,7 @@
+;;; -*- lexical-binding: t -*-
+(defvar foo-bar nil
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
+
+;; Local Variables:
+;; fill-column: 100
+;; End:
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-ignore-override.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-ignore-override.el
new file mode 100644
index 00000000000..0bcf7b1d63b
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-ignore-override.el
@@ -0,0 +1,8 @@
+;;; -*- lexical-binding: t -*-
+(defvar foo-bar nil
+ "123456789012345")
+
+;; Local Variables:
+;; byte-compile-docstring-max-column: 10
+;; fill-column: 20
+;; End:
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-ignore.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-ignore.el
new file mode 100644
index 00000000000..c80ddd180d9
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-ignore.el
@@ -0,0 +1,7 @@
+;;; -*- lexical-binding: t -*-
+(defvar foo-bar nil
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
+
+;; Local Variables:
+;; byte-compile-docstring-max-column: 100
+;; End:
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-multiline-first.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-multiline-first.el
new file mode 100644
index 00000000000..2563dbbb3b9
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-multiline-first.el
@@ -0,0 +1,5 @@
+;;; -*- lexical-binding: t -*-
+(defvar foo-bar nil
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+This is a multiline docstring where the first line is long.
+foobar")
diff --git a/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-multiline.el b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-multiline.el
new file mode 100644
index 00000000000..9ae7bc9b9f0
--- /dev/null
+++ b/test/lisp/emacs-lisp/bytecomp-resources/warn-wide-docstring-multiline.el
@@ -0,0 +1,6 @@
+;;; -*- lexical-binding: t -*-
+(defvar foo-bar nil
+ "This is a multiline docstring.
+But it's not the first line that is long.
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+foobar")
diff --git a/test/lisp/emacs-lisp/bytecomp-tests.el b/test/lisp/emacs-lisp/bytecomp-tests.el
index 14ca149f06a..5e5f99dbdab 100644
--- a/test/lisp/emacs-lisp/bytecomp-tests.el
+++ b/test/lisp/emacs-lisp/bytecomp-tests.el
@@ -1,4 +1,4 @@
-;;; bytecomp-tests.el
+;;; bytecomp-tests.el -*- lexical-binding:t -*-
;; Copyright (C) 2008-2021 Free Software Foundation, Inc.
@@ -26,6 +26,7 @@
;;; Commentary:
(require 'ert)
+(require 'ert-x)
(require 'cl-lib)
(require 'subr-x)
(require 'bytecomp)
@@ -47,6 +48,11 @@
(let ((a 1.0)) (/ 3 a 2))
(let ((a most-positive-fixnum) (b 2.0)) (* a 2 b))
(let ((a 3) (b 2)) (/ a b 1.0))
+ (let ((a -0.0)) (+ a))
+ (let ((a -0.0)) (- a))
+ (let ((a -0.0)) (* a))
+ (let ((a -0.0)) (min a))
+ (let ((a -0.0)) (max a))
(/ 3 -1)
(+ 4 3 2 1)
(+ 4 3 2.0 1)
@@ -360,7 +366,12 @@
'(((a b)) a b (c) (d)))
(mapcar (lambda (x) (cond ((memq '(a b) x) 1)
((equal x '(c)) 2)))
- '(((a b)) a b (c) (d))))
+ '(((a b)) a b (c) (d)))
+
+ (assoc 'b '((a 1) (b 2) (c 3)))
+ (assoc "b" '(("a" 1) ("b" 2) ("c" 3)))
+ (let ((x '((a 1) (b 2) (c 3)))) (assoc 'c x))
+ (assoc 'a '((a 1) (b 2) (c 3)) (lambda (u v) (not (equal u v)))))
"List of expression for test.
Each element will be executed by interpreter and with
bytecompiled code, and their results compared.")
@@ -368,24 +379,24 @@ bytecompiled code, and their results compared.")
(defun bytecomp-check-1 (pat)
"Return non-nil if PAT is the same whether directly evalled or compiled."
(let ((warning-minimum-log-level :emergency)
- (byte-compile-warnings nil)
- (v0 (condition-case nil
+ (byte-compile-warnings nil)
+ (v0 (condition-case err
(eval pat)
- (error nil)))
- (v1 (condition-case nil
+ (error (list 'bytecomp-check-error (car err)))))
+ (v1 (condition-case err
(funcall (byte-compile (list 'lambda nil pat)))
- (error nil))))
+ (error (list 'bytecomp-check-error (car err))))))
(equal v0 v1)))
(put 'bytecomp-check-1 'ert-explainer 'bytecomp-explain-1)
(defun bytecomp-explain-1 (pat)
- (let ((v0 (condition-case nil
+ (let ((v0 (condition-case err
(eval pat)
- (error nil)))
- (v1 (condition-case nil
+ (error (list 'bytecomp-check-error (car err)))))
+ (v1 (condition-case err
(funcall (byte-compile (list 'lambda nil pat)))
- (error nil))))
+ (error (list 'bytecomp-check-error (car err))))))
(format "Expression `%s' gives `%s' if directly evalled, `%s' if compiled."
pat v0 v1)))
@@ -408,12 +419,12 @@ Subtests signal errors if something goes wrong."
(print-quoted t)
v0 v1)
(dolist (pat byte-opt-testsuite-arith-data)
- (condition-case nil
+ (condition-case err
(setq v0 (eval pat))
- (error (setq v0 nil)))
- (condition-case nil
+ (error (setq v0 (list 'bytecomp-check-error (car err)))))
+ (condition-case err
(setq v1 (funcall (byte-compile (list 'lambda nil pat))))
- (error (setq v1 nil)))
+ (error (setq v1 (list 'bytecomp-check-error (car err)))))
(insert (format "%s" pat))
(indent-to-column 65)
(if (equal v0 v1)
@@ -439,8 +450,8 @@ Subtests signal errors if something goes wrong."
(if compile
(let ((byte-compile-dest-file-function
(lambda (e) elcfile)))
- (byte-compile-file elfile t))
- (load elfile nil 'nomessage)))
+ (byte-compile-file elfile)))
+ (load elfile nil 'nomessage))
(when elfile (delete-file elfile))
(when elcfile (delete-file elcfile)))))
(put 'test-byte-comp-compile-and-load 'lisp-indent-function 1)
@@ -479,9 +490,13 @@ Subtests signal errors if something goes wrong."
(defun def () (m))))
(should (equal (funcall 'def) 4)))
+
+;;;; Warnings.
+
(ert-deftest bytecomp-tests--warnings ()
(with-current-buffer (get-buffer-create "*Compile-Log*")
(let ((inhibit-read-only t)) (erase-buffer)))
+ (mapc #'fmakunbound '(my-test0 my--test11 my--test12 my--test2))
(test-byte-comp-compile-and-load t
'(progn
(defun my-test0 ()
@@ -505,19 +520,198 @@ Subtests signal errors if something goes wrong."
;; Should not warn that mt--test2 is not known to be defined.
(should-not (re-search-forward "my--test2" nil t))))
+(defmacro bytecomp--with-warning-test (re-warning &rest form)
+ (declare (indent 1))
+ `(with-current-buffer (get-buffer-create "*Compile-Log*")
+ (let ((inhibit-read-only t)) (erase-buffer))
+ (byte-compile ,@form)
+ (ert-info ((buffer-string) :prefix "buffer: ")
+ (should (re-search-forward ,re-warning)))))
+
(ert-deftest bytecomp-warn-wrong-args ()
- (with-current-buffer (get-buffer-create "*Compile-Log*")
- (let ((inhibit-read-only t)) (erase-buffer))
- (byte-compile '(remq 1 2 3))
- (ert-info ((buffer-string) :prefix "buffer: ")
- (should (re-search-forward "remq.*3.*2")))))
+ (bytecomp--with-warning-test "remq.*3.*2"
+ '(remq 1 2 3)))
(ert-deftest bytecomp-warn-wrong-args-subr ()
- (with-current-buffer (get-buffer-create "*Compile-Log*")
- (let ((inhibit-read-only t)) (erase-buffer))
- (byte-compile '(safe-length 1 2 3))
- (ert-info ((buffer-string) :prefix "buffer: ")
- (should (re-search-forward "safe-length.*3.*1")))))
+ (bytecomp--with-warning-test "safe-length.*3.*1"
+ '(safe-length 1 2 3)))
+
+(ert-deftest bytecomp-warn-variable-lacks-prefix ()
+ (bytecomp--with-warning-test "foo.*lacks a prefix"
+ '(defvar foo nil)))
+
+(defvar bytecomp-tests--docstring (make-string 100 ?x))
+
+(ert-deftest bytecomp-warn-wide-docstring/defconst ()
+ (bytecomp--with-warning-test "defconst.*foo.*wider than.*characters"
+ `(defconst foo t ,bytecomp-tests--docstring)))
+
+(ert-deftest bytecomp-warn-wide-docstring/defvar ()
+ (bytecomp--with-warning-test "defvar.*foo.*wider than.*characters"
+ `(defvar foo t ,bytecomp-tests--docstring)))
+
+(defmacro bytecomp--define-warning-file-test (file re-warning &optional reverse)
+ `(ert-deftest ,(intern (format "bytecomp/%s" file)) ()
+ :expected-result ,(if reverse :failed :passed)
+ (with-current-buffer (get-buffer-create "*Compile-Log*")
+ (let ((inhibit-read-only t)) (erase-buffer))
+ (byte-compile-file ,(ert-resource-file file))
+ (ert-info ((buffer-string) :prefix "buffer: ")
+ (should (re-search-forward ,re-warning))))))
+
+(bytecomp--define-warning-file-test "error-lexical-var-with-add-hook.el"
+ "add-hook.*lexical var")
+
+(bytecomp--define-warning-file-test "error-lexical-var-with-remove-hook.el"
+ "remove-hook.*lexical var")
+
+(bytecomp--define-warning-file-test "error-lexical-var-with-run-hook-with-args-until-failure.el"
+ "args-until-failure.*lexical var")
+
+(bytecomp--define-warning-file-test "error-lexical-var-with-run-hook-with-args-until-success.el"
+ "args-until-success.*lexical var")
+
+(bytecomp--define-warning-file-test "error-lexical-var-with-run-hook-with-args.el"
+ "args.*lexical var")
+
+(bytecomp--define-warning-file-test "error-lexical-var-with-symbol-value.el"
+ "symbol-value.*lexical var")
+
+(bytecomp--define-warning-file-test "warn-autoload-not-on-top-level.el"
+ "compiler ignores.*autoload.*")
+
+(bytecomp--define-warning-file-test "warn-callargs.el"
+ "with 2 arguments, but accepts only 1")
+
+(bytecomp--define-warning-file-test "warn-defcustom-nogroup.el"
+ "fails to specify containing group")
+
+(bytecomp--define-warning-file-test "warn-defcustom-notype.el"
+ "fails to specify type")
+
+(bytecomp--define-warning-file-test "warn-defvar-lacks-prefix.el"
+ "var.*foo.*lacks a prefix")
+
+(bytecomp--define-warning-file-test "warn-format.el"
+ "called with 2 args to fill 1 format field")
+
+(bytecomp--define-warning-file-test "warn-free-setq.el"
+ "free.*foo")
+
+(bytecomp--define-warning-file-test "warn-free-variable-reference.el"
+ "free.*bar")
+
+(bytecomp--define-warning-file-test "warn-make-variable-buffer-local.el"
+ "make-variable-buffer-local.*not called at toplevel")
+
+(bytecomp--define-warning-file-test "warn-interactive-only.el"
+ "next-line.*interactive use only.*forward-line")
+
+(bytecomp--define-warning-file-test "warn-lambda-malformed-interactive-spec.el"
+ "malformed interactive spec")
+
+(bytecomp--define-warning-file-test "warn-obsolete-defun.el"
+ "foo-obsolete.*obsolete function.*99.99")
+
+(defvar bytecomp--tests-obsolete-var nil)
+(make-obsolete-variable 'bytecomp--tests-obsolete-var nil "99.99")
+
+(bytecomp--define-warning-file-test "warn-obsolete-hook.el"
+ "bytecomp--tests-obs.*obsolete.*99.99")
+
+(bytecomp--define-warning-file-test "warn-obsolete-variable-same-file.el"
+ "foo-obs.*obsolete.*99.99" t)
+
+(bytecomp--define-warning-file-test "warn-obsolete-variable.el"
+ "bytecomp--tests-obs.*obsolete.*99.99")
+
+(bytecomp--define-warning-file-test "warn-redefine-defun-as-macro.el"
+ "as both function and macro")
+
+(bytecomp--define-warning-file-test "warn-redefine-macro-as-defun.el"
+ "as both function and macro")
+
+(bytecomp--define-warning-file-test "warn-redefine-defun.el"
+ "defined multiple")
+
+(bytecomp--define-warning-file-test "warn-save-excursion.el"
+ "with-current.*rather than save-excursion")
+
+(bytecomp--define-warning-file-test "warn-variable-let-bind-constant.el"
+ "let-bind constant")
+
+(bytecomp--define-warning-file-test "warn-variable-let-bind-nonvariable.el"
+ "let-bind nonvariable")
+
+(bytecomp--define-warning-file-test "warn-variable-set-constant.el"
+ "variable reference to constant")
+
+(bytecomp--define-warning-file-test "warn-variable-set-nonvariable.el"
+ "variable reference to nonvariable")
+
+(bytecomp--define-warning-file-test
+ "warn-wide-docstring-autoload.el"
+ "autoload.*foox.*wider than.*characters")
+
+(bytecomp--define-warning-file-test
+ "warn-wide-docstring-custom-declare-variable.el"
+ "custom-declare-variable.*foo.*wider than.*characters")
+
+(bytecomp--define-warning-file-test
+ "warn-wide-docstring-defalias.el"
+ "defalias.*foo.*wider than.*characters")
+
+(bytecomp--define-warning-file-test
+ "warn-wide-docstring-defconst.el"
+ "defconst.*foo.*wider than.*characters")
+
+(bytecomp--define-warning-file-test
+ "warn-wide-docstring-define-abbrev-table.el"
+ "define-abbrev.*foo.*wider than.*characters")
+
+(bytecomp--define-warning-file-test
+ "warn-wide-docstring-define-obsolete-function-alias.el"
+ "defalias.*foo.*wider than.*characters")
+
+(bytecomp--define-warning-file-test
+ "warn-wide-docstring-define-obsolete-variable-alias.el"
+ "defvaralias.*foo.*wider than.*characters")
+
+;; TODO: We don't yet issue warnings for defuns.
+(bytecomp--define-warning-file-test
+ "warn-wide-docstring-defun.el"
+ "wider than.*characters" 'reverse)
+
+(bytecomp--define-warning-file-test
+ "warn-wide-docstring-defvar.el"
+ "defvar.*foo.*wider than.*characters")
+
+(bytecomp--define-warning-file-test
+ "warn-wide-docstring-defvaralias.el"
+ "defvaralias.*foo.*wider than.*characters")
+
+(bytecomp--define-warning-file-test
+ "warn-wide-docstring-ignore-fill-column.el"
+ "defvar.*foo.*wider than.*characters" 'reverse)
+
+(bytecomp--define-warning-file-test
+ "warn-wide-docstring-ignore-override.el"
+ "defvar.*foo.*wider than.*characters" 'reverse)
+
+(bytecomp--define-warning-file-test
+ "warn-wide-docstring-ignore.el"
+ "defvar.*foo.*wider than.*characters" 'reverse)
+
+(bytecomp--define-warning-file-test
+ "warn-wide-docstring-multiline-first.el"
+ "defvar.*foo.*wider than.*characters")
+
+(bytecomp--define-warning-file-test
+ "warn-wide-docstring-multiline.el"
+ "defvar.*foo.*wider than.*characters")
+
+
+;;;; Macro expansion.
(ert-deftest test-eager-load-macro-expansion ()
(test-byte-comp-compile-and-load nil
@@ -567,25 +761,25 @@ bytecompiled code, and their results compared.")
"Return non-nil if PAT is the same whether directly evalled or compiled."
(let ((warning-minimum-log-level :emergency)
(byte-compile-warnings nil)
- (v0 (condition-case nil
+ (v0 (condition-case err
(eval pat t)
- (error nil)))
- (v1 (condition-case nil
+ (error (list 'bytecomp-check-error (car err)))))
+ (v1 (condition-case err
(funcall (let ((lexical-binding t))
(byte-compile `(lambda nil ,pat))))
- (error nil))))
+ (error (list 'bytecomp-check-error (car err))))))
(equal v0 v1)))
(put 'bytecomp-lexbind-check-1 'ert-explainer 'bytecomp-lexbind-explain-1)
(defun bytecomp-lexbind-explain-1 (pat)
- (let ((v0 (condition-case nil
+ (let ((v0 (condition-case err
(eval pat t)
- (error nil)))
- (v1 (condition-case nil
+ (error (list 'bytecomp-check-error (car err)))))
+ (v1 (condition-case err
(funcall (let ((lexical-binding t))
(byte-compile (list 'lambda nil pat))))
- (error nil))))
+ (error (list 'bytecomp-check-error (car err))))))
(format "Expression `%s' gives `%s' if directly evalled, `%s' if compiled."
pat v0 v1)))
@@ -628,17 +822,6 @@ literals (Bug#20852)."
(let ((byte-compile-dest-file-function (lambda (_) destination)))
(should (byte-compile-file source)))))))
-(ert-deftest bytecomp-tests--old-style-backquotes ()
- "Check that byte compiling warns about old-style backquotes."
- (bytecomp-tests--with-temp-file source
- (write-region "(` (a b))" nil source)
- (bytecomp-tests--with-temp-file destination
- (let* ((byte-compile-dest-file-function (lambda (_) destination))
- (byte-compile-debug t)
- (err (should-error (byte-compile-file source))))
- (should (equal (cdr err) '("Old-style backquotes detected!")))))))
-
-
(ert-deftest bytecomp-tests-function-put ()
"Check `function-put' operates during compilation."
(bytecomp-tests--with-temp-file source
@@ -651,7 +834,8 @@ literals (Bug#20852)."
(setq bytecomp-tests--foobar (bytecomp-tests--foobar))))
(print form (current-buffer)))
(write-region (point-min) (point-max) source nil 'silent)
- (byte-compile-file source t)
+ (byte-compile-file source)
+ (load source)
(should (equal bytecomp-tests--foobar (cons 1 2)))))
(ert-deftest bytecomp-tests--test-no-warnings-with-advice ()
@@ -809,6 +993,12 @@ literals (Bug#20852)."
(test-suppression
'(defun zot ()
+ (next-line))
+ '((interactive-only next-line))
+ "interactive use only")
+
+ (test-suppression
+ '(defun zot ()
(mapcar #'list '(1 2 3))
nil)
'((mapcar mapcar))
@@ -828,6 +1018,90 @@ literals (Bug#20852)."
'((suspicious set-buffer))
"Warning: Use .with-current-buffer. rather than"))
+(ert-deftest bytecomp-tests--not-writable-directory ()
+ "Test that byte compilation works if the output directory isn't
+writable (Bug#44631)."
+ (let ((directory (make-temp-file "bytecomp-tests-" :directory)))
+ (unwind-protect
+ (let* ((input-file (expand-file-name "test.el" directory))
+ (output-file (expand-file-name "test.elc" directory))
+ (byte-compile-dest-file-function
+ (lambda (_) output-file))
+ (byte-compile-error-on-warn t))
+ (write-region "" nil input-file nil nil nil 'excl)
+ (write-region "" nil output-file nil nil nil 'excl)
+ (set-file-modes input-file #o400)
+ (set-file-modes output-file #o200)
+ (set-file-modes directory #o500)
+ (should (byte-compile-file input-file))
+ (should (file-regular-p output-file))
+ (should (cl-plusp (file-attribute-size
+ (file-attributes output-file)))))
+ (with-demoted-errors "Error cleaning up directory: %s"
+ (set-file-modes directory #o700)
+ (delete-directory directory :recursive)))))
+
+(ert-deftest bytecomp-tests--dest-mountpoint ()
+ "Test that byte compilation works if the destination file is a
+mountpoint (Bug#44631)."
+ (let ((bwrap (executable-find "bwrap"))
+ (emacs (expand-file-name invocation-name invocation-directory)))
+ (skip-unless bwrap)
+ (skip-unless (file-executable-p bwrap))
+ (skip-unless (not (file-remote-p bwrap)))
+ (skip-unless (file-executable-p emacs))
+ (skip-unless (not (file-remote-p emacs)))
+ (let ((directory (make-temp-file "bytecomp-tests-" :directory)))
+ (unwind-protect
+ (let* ((input-file (expand-file-name "test.el" directory))
+ (output-file (expand-file-name "test.elc" directory))
+ (unquoted-file (file-name-unquote output-file))
+ (byte-compile-dest-file-function
+ (lambda (_) output-file))
+ (byte-compile-error-on-warn t))
+ (should-not (file-remote-p input-file))
+ (should-not (file-remote-p output-file))
+ (write-region "" nil input-file nil nil nil 'excl)
+ (write-region "" nil output-file nil nil nil 'excl)
+ (set-file-modes input-file #o400)
+ (set-file-modes output-file #o200)
+ (set-file-modes directory #o500)
+ (with-temp-buffer
+ (let ((status (call-process
+ bwrap nil t nil
+ "--ro-bind" "/" "/"
+ "--bind" unquoted-file unquoted-file
+ emacs "--quick" "--batch" "--load=bytecomp"
+ (format "--eval=%S"
+ `(setq byte-compile-dest-file-function
+ (lambda (_) ,output-file)
+ byte-compile-error-on-warn t))
+ "--funcall=batch-byte-compile" input-file)))
+ (unless (eql status 0)
+ (ert-fail `((status . ,status)
+ (output . ,(buffer-string)))))))
+ (should (file-regular-p output-file))
+ (should (cl-plusp (file-attribute-size
+ (file-attributes output-file)))))
+ (with-demoted-errors "Error cleaning up directory: %s"
+ (set-file-modes directory #o700)
+ (delete-directory directory :recursive))))))
+
+(ert-deftest bytecomp-tests--target-file-no-directory ()
+ "Check that Bug#45287 is fixed."
+ (let ((directory (make-temp-file "bytecomp-tests-" :directory)))
+ (unwind-protect
+ (let* ((default-directory directory)
+ (byte-compile-dest-file-function (lambda (_) "test.elc"))
+ (byte-compile-error-on-warn t))
+ (write-region "" nil "test.el" nil nil nil 'excl)
+ (should (byte-compile-file "test.el"))
+ (should (file-regular-p "test.elc"))
+ (should (cl-plusp (file-attribute-size
+ (file-attributes "test.elc")))))
+ (with-demoted-errors "Error cleaning up directory: %s"
+ (delete-directory directory :recursive)))))
+
;; Local Variables:
;; no-byte-compile: t
;; End:
diff --git a/test/lisp/emacs-lisp/cconv-tests.el b/test/lisp/emacs-lisp/cconv-tests.el
index 30a3869b33e..517373386e3 100644
--- a/test/lisp/emacs-lisp/cconv-tests.el
+++ b/test/lisp/emacs-lisp/cconv-tests.el
@@ -20,6 +20,166 @@
;;; Commentary:
(require 'ert)
+(require 'cl-lib)
+
+(ert-deftest cconv-tests-lambda-:documentation ()
+ "Docstring for lambda can be specified with :documentation."
+ (let ((fun (lambda ()
+ (:documentation (concat "lambda" " documentation"))
+ 'lambda-result)))
+ (should (string= (documentation fun) "lambda documentation"))
+ (should (eq (funcall fun) 'lambda-result))))
+
+(ert-deftest cconv-tests-pcase-lambda-:documentation ()
+ "Docstring for pcase-lambda can be specified with :documentation."
+ (let ((fun (pcase-lambda (`(,a ,b))
+ (:documentation (concat "pcase-lambda" " documentation"))
+ (list b a))))
+ (should (string= (documentation fun) "pcase-lambda documentation"))
+ (should (equal '(2 1) (funcall fun '(1 2))))))
+
+(defun cconv-tests-defun ()
+ (:documentation (concat "defun" " documentation"))
+ 'defun-result)
+(ert-deftest cconv-tests-defun-:documentation ()
+ "Docstring for defun can be specified with :documentation."
+ (should (string= (documentation 'cconv-tests-defun)
+ "defun documentation"))
+ (should (eq (cconv-tests-defun) 'defun-result)))
+
+(cl-defun cconv-tests-cl-defun ()
+ (:documentation (concat "cl-defun" " documentation"))
+ 'cl-defun-result)
+(ert-deftest cconv-tests-cl-defun-:documentation ()
+ "Docstring for cl-defun can be specified with :documentation."
+ (should (string= (documentation 'cconv-tests-cl-defun)
+ "cl-defun documentation"))
+ (should (eq (cconv-tests-cl-defun) 'cl-defun-result)))
+
+;; FIXME: The byte-complier croaks on this. See Bug#28557.
+;; (defmacro cconv-tests-defmacro ()
+;; (:documentation (concat "defmacro" " documentation"))
+;; '(quote defmacro-result))
+;; (ert-deftest cconv-tests-defmacro-:documentation ()
+;; "Docstring for defmacro can be specified with :documentation."
+;; (should (string= (documentation 'cconv-tests-defmacro)
+;; "defmacro documentation"))
+;; (should (eq (cconv-tests-defmacro) 'defmacro-result)))
+
+;; FIXME: The byte-complier croaks on this. See Bug#28557.
+;; (cl-defmacro cconv-tests-cl-defmacro ()
+;; (:documentation (concat "cl-defmacro" " documentation"))
+;; '(quote cl-defmacro-result))
+;; (ert-deftest cconv-tests-cl-defmacro-:documentation ()
+;; "Docstring for cl-defmacro can be specified with :documentation."
+;; (should (string= (documentation 'cconv-tests-cl-defmacro)
+;; "cl-defmacro documentation"))
+;; (should (eq (cconv-tests-cl-defmacro) 'cl-defmacro-result)))
+
+(cl-iter-defun cconv-tests-cl-iter-defun ()
+ (:documentation (concat "cl-iter-defun" " documentation"))
+ (iter-yield 'cl-iter-defun-result))
+(ert-deftest cconv-tests-cl-iter-defun-:documentation ()
+ "Docstring for cl-iter-defun can be specified with :documentation."
+ ;; FIXME: See Bug#28557.
+ :tags '(:unstable)
+ :expected-result :failed
+ (should (string= (documentation 'cconv-tests-cl-iter-defun)
+ "cl-iter-defun documentation"))
+ (should (eq (iter-next (cconv-tests-cl-iter-defun))
+ 'cl-iter-defun-result)))
+
+(iter-defun cconv-tests-iter-defun ()
+ (:documentation (concat "iter-defun" " documentation"))
+ (iter-yield 'iter-defun-result))
+(ert-deftest cconv-tests-iter-defun-:documentation ()
+ "Docstring for iter-defun can be specified with :documentation."
+ ;; FIXME: See Bug#28557.
+ :tags '(:unstable)
+ :expected-result :failed
+ (should (string= (documentation 'cconv-tests-iter-defun)
+ "iter-defun documentation"))
+ (should (eq (iter-next (cconv-tests-iter-defun)) 'iter-defun-result)))
+
+(ert-deftest cconv-tests-iter-lambda-:documentation ()
+ "Docstring for iter-lambda can be specified with :documentation."
+ ;; FIXME: See Bug#28557.
+ :expected-result :failed
+ (let ((iter-fun
+ (iter-lambda ()
+ (:documentation (concat "iter-lambda" " documentation"))
+ (iter-yield 'iter-lambda-result))))
+ (should (string= (documentation iter-fun) "iter-lambda documentation"))
+ (should (eq (iter-next (funcall iter-fun)) 'iter-lambda-result))))
+
+(ert-deftest cconv-tests-cl-function-:documentation ()
+ "Docstring for cl-function can be specified with :documentation."
+ ;; FIXME: See Bug#28557.
+ :expected-result :failed
+ (let ((fun (cl-function (lambda (&key arg)
+ (:documentation (concat "cl-function"
+ " documentation"))
+ (list arg 'cl-function-result)))))
+ (should (string= (documentation fun) "cl-function documentation"))
+ (should (equal (funcall fun :arg t) '(t cl-function-result)))))
+
+(ert-deftest cconv-tests-function-:documentation ()
+ "Docstring for lambda inside function can be specified with :documentation."
+ (let ((fun #'(lambda (arg)
+ (:documentation (concat "function" " documentation"))
+ (list arg 'function-result))))
+ (should (string= (documentation fun) "function documentation"))
+ (should (equal (funcall fun t) '(t function-result)))))
+
+(fmakunbound 'cconv-tests-cl-defgeneric)
+(setplist 'cconv-tests-cl-defgeneric nil)
+(cl-defgeneric cconv-tests-cl-defgeneric (n)
+ (:documentation (concat "cl-defgeneric" " documentation")))
+(cl-defmethod cconv-tests-cl-defgeneric ((n integer))
+ (:documentation (concat "cl-defmethod" " documentation"))
+ (+ 1 n))
+(ert-deftest cconv-tests-cl-defgeneric-:documentation ()
+ "Docstring for cl-defgeneric can be specified with :documentation."
+ ;; FIXME: See Bug#28557.
+ :expected-result :failed
+ (let ((descr (describe-function 'cconv-tests-cl-defgeneric)))
+ (set-text-properties 0 (length descr) nil descr)
+ (should (string-match-p "cl-defgeneric documentation" descr))
+ (should (string-match-p "cl-defmethod documentation" descr)))
+ (should (= 11 (cconv-tests-cl-defgeneric 10))))
+
+(fmakunbound 'cconv-tests-cl-defgeneric-literal)
+(setplist 'cconv-tests-cl-defgeneric-literal nil)
+(cl-defgeneric cconv-tests-cl-defgeneric-literal (n)
+ (:documentation "cl-defgeneric-literal documentation"))
+(cl-defmethod cconv-tests-cl-defgeneric-literal ((n integer))
+ (:documentation "cl-defmethod-literal documentation")
+ (+ 1 n))
+(ert-deftest cconv-tests-cl-defgeneric-literal-:documentation ()
+ "Docstring for cl-defgeneric can be specified with :documentation."
+ (let ((descr (describe-function 'cconv-tests-cl-defgeneric-literal)))
+ (set-text-properties 0 (length descr) nil descr)
+ (should (string-match-p "cl-defgeneric-literal documentation" descr))
+ (should (string-match-p "cl-defmethod-literal documentation" descr)))
+ (should (= 11 (cconv-tests-cl-defgeneric-literal 10))))
+
+(defsubst cconv-tests-defsubst ()
+ (:documentation (concat "defsubst" " documentation"))
+ 'defsubst-result)
+(ert-deftest cconv-tests-defsubst-:documentation ()
+ "Docstring for defsubst can be specified with :documentation."
+ (should (string= (documentation 'cconv-tests-defsubst)
+ "defsubst documentation"))
+ (should (eq (cconv-tests-defsubst) 'defsubst-result)))
+
+(cl-defsubst cconv-tests-cl-defsubst ()
+ (:documentation (concat "cl-defsubst" " documentation"))
+ 'cl-defsubst-result)
+(ert-deftest cconv-tests-cl-defsubst-:documentation ()
+ "Docstring for cl-defsubst can be specified with :documentation."
+ (should (string= (documentation 'cconv-tests-cl-defsubst)
+ "cl-defsubst documentation"))
+ (should (eq (cconv-tests-cl-defsubst) 'cl-defsubst-result)))
(ert-deftest cconv-convert-lambda-lifted ()
"Bug#30872."
diff --git a/test/lisp/emacs-lisp/check-declare-tests.el b/test/lisp/emacs-lisp/check-declare-tests.el
new file mode 100644
index 00000000000..9552bf0e397
--- /dev/null
+++ b/test/lisp/emacs-lisp/check-declare-tests.el
@@ -0,0 +1,116 @@
+;;; check-declare-tests.el --- Tests for check-declare.el -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+;; Author: Simen Heggestøyl <simenheg@gmail.com>
+;; Keywords:
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'check-declare)
+(require 'ert)
+(eval-when-compile (require 'subr-x))
+
+(ert-deftest check-declare-tests-locate ()
+ (should (file-exists-p (check-declare-locate "check-declare" "")))
+ (should
+ (string-prefix-p "ext:" (check-declare-locate "ext:foo" ""))))
+
+(ert-deftest check-declare-tests-scan ()
+ (let ((file (make-temp-file "check-declare-tests-")))
+ (unwind-protect
+ (progn
+ (with-temp-file file
+ (insert
+ (string-join
+ '(";; foo comment"
+ "(declare-function ring-insert \"ring\" (ring item))"
+ "(let ((foo 'code)) foo)")
+ "\n")))
+ (let ((res (check-declare-scan file)))
+ (should (= (length res) 1))
+ (pcase-let ((`((,fnfile ,fn ,arglist ,fileonly)) res))
+ (should (string-match-p "ring" fnfile))
+ (should (equal "ring-insert" fn))
+ (should (equal '(ring item) arglist))
+ (should-not fileonly))))
+ (delete-file file))))
+
+(ert-deftest check-declare-tests-verify ()
+ (let ((file (make-temp-file "check-declare-tests-")))
+ (unwind-protect
+ (progn
+ (with-temp-file file
+ (insert
+ (string-join
+ '(";; foo comment"
+ "(defun foo-fun ())"
+ "(defun ring-insert (ring item)"
+ "\"Insert onto ring RING the item ITEM.\""
+ "nil)")
+ "\n")))
+ (should-not
+ (check-declare-verify
+ file '(("foo.el" "ring-insert" (ring item))))))
+ (delete-file file))))
+
+(ert-deftest check-declare-tests-verify-mismatch ()
+ (let ((file (make-temp-file "check-declare-tests-")))
+ (unwind-protect
+ (progn
+ (with-temp-file file
+ (insert
+ (string-join
+ '(";; foo comment"
+ "(defun foo-fun ())"
+ "(defun ring-insert (ring)"
+ "\"Insert onto ring RING the item ITEM.\""
+ "nil)")
+ "\n")))
+ (should
+ (equal
+ (check-declare-verify
+ file '(("foo.el" "ring-insert" (ring item))))
+ '(("foo.el" "ring-insert" "arglist mismatch")))))
+ (delete-file file))))
+
+(ert-deftest check-declare-tests-sort ()
+ (should-not (check-declare-sort '()))
+ (should (equal (check-declare-sort '((a (1 a)) (b (2)) (d (1 d))))
+ '((2 (b)) (1 (a a) (d d))))))
+
+(ert-deftest check-declare-tests-warn ()
+ (with-temp-buffer
+ (let ((check-declare-warning-buffer (buffer-name)))
+ (check-declare-warn
+ "foo-file" "foo-fun" "bar-file" "it wasn't" 999)
+ (let ((res (buffer-string)))
+ ;; Don't care too much about the format of the output, but
+ ;; check that key information is present.
+ (should (string-match-p "foo-file" res))
+ (should (string-match-p "foo-fun" res))
+ (should (string-match-p "bar-file" res))
+ (should (string-match-p "it wasn't" res))
+ (should (string-match-p "999" res))))))
+
+(provide 'check-declare-tests)
+;;; check-declare-tests.el ends here
diff --git a/test/lisp/emacs-lisp/cl-generic-tests.el b/test/lisp/emacs-lisp/cl-generic-tests.el
index 0648a0f8b43..4a01623cb88 100644
--- a/test/lisp/emacs-lisp/cl-generic-tests.el
+++ b/test/lisp/emacs-lisp/cl-generic-tests.el
@@ -24,6 +24,7 @@
;;; Code:
(require 'cl-generic)
+(require 'edebug)
;; Don't indirectly require `cl-lib' at run-time.
(eval-when-compile (require 'ert))
@@ -239,7 +240,7 @@
(let ((retval (cl--generic-method-files 'cl-generic-tests--generic)))
(should (equal (length retval) 2))
(mapc (lambda (x)
- (should (equal (car x) cl-generic-tests--this-file))
+ (should (equal (file-truename (car x)) cl-generic-tests--this-file))
(should (equal (cadr x) 'cl-generic-tests--generic)))
retval)
(should-not (equal (nth 0 retval) (nth 1 retval)))))
@@ -249,5 +250,42 @@
(should-not (cl--generic-method-files 'cl-generic-tests--undefined-generic))
(should-not (cl--generic-method-files 'cl-generic-tests--generic-without-methods)))
+(ert-deftest cl-defgeneric/edebug/method ()
+ "Check that `:method' forms in `cl-defgeneric' create unique
+Edebug symbols (Bug#42672)."
+ (with-temp-buffer
+ (dolist (form '((cl-defgeneric cl-defgeneric/edebug/method/1 (_)
+ (:method ((_ number)) 1)
+ (:method ((_ string)) 2)
+ (:method :around ((_ number)) 3))
+ (cl-defgeneric cl-defgeneric/edebug/method/2 (_)
+ (:method ((_ number)) 3))))
+ (print form (current-buffer)))
+ (let* ((edebug-all-defs t)
+ (edebug-initial-mode 'Go-nonstop)
+ (instrumented-names ())
+ (edebug-new-definition-function
+ (lambda (name)
+ (when (memq name instrumented-names)
+ (error "Duplicate definition of `%s'" name))
+ (push name instrumented-names)
+ (edebug-new-definition name)))
+ ;; Make generated symbols reproducible.
+ (gensym-counter 10000))
+ (eval-buffer)
+ (should (equal
+ (reverse instrumented-names)
+ ;; The generic function definitions come after the
+ ;; method definitions because their body ends later.
+ ;; FIXME: We'd rather have names such as
+ ;; `cl-defgeneric/edebug/method/1 ((_ number))', but
+ ;; that requires further changes to Edebug.
+ (list (intern "cl-generic-:method@10000 ((_ number))")
+ (intern "cl-generic-:method@10001 ((_ string))")
+ (intern "cl-generic-:method@10002 :around ((_ number))")
+ 'cl-defgeneric/edebug/method/1
+ (intern "cl-generic-:method@10003 ((_ number))")
+ 'cl-defgeneric/edebug/method/2))))))
+
(provide 'cl-generic-tests)
;;; cl-generic-tests.el ends here
diff --git a/test/lisp/emacs-lisp/cl-lib-tests.el b/test/lisp/emacs-lisp/cl-lib-tests.el
index b7b1e22b93e..97a44c43ef7 100644
--- a/test/lisp/emacs-lisp/cl-lib-tests.el
+++ b/test/lisp/emacs-lisp/cl-lib-tests.el
@@ -242,6 +242,22 @@
(should (= (cl-the integer (cl-incf side-effect)) 1))
(should (= side-effect 1))))
+(ert-deftest cl-lib-test-incf ()
+ (let ((var 0))
+ (should (= (cl-incf var) 1))
+ (should (= var 1)))
+ (let ((alist))
+ (should (= (cl-incf (alist-get 'a alist 0)) 1))
+ (should (= (alist-get 'a alist 0) 1))))
+
+(ert-deftest cl-lib-test-decf ()
+ (let ((var 1))
+ (should (= (cl-decf var) 0))
+ (should (= var 0)))
+ (let ((alist))
+ (should (= (cl-decf (alist-get 'a alist 0)) -1))
+ (should (= (alist-get 'a alist 0) -1))))
+
(ert-deftest cl-lib-test-plusp ()
(should-not (cl-plusp -1.0e+INF))
(should-not (cl-plusp -1.5e2))
diff --git a/test/lisp/emacs-lisp/cl-macs-tests.el b/test/lisp/emacs-lisp/cl-macs-tests.el
index c0f1a109e88..446983c2e3e 100644
--- a/test/lisp/emacs-lisp/cl-macs-tests.el
+++ b/test/lisp/emacs-lisp/cl-macs-tests.el
@@ -39,6 +39,15 @@
collect (list c b a))
'((4.0 2 1) (8.3 6 5) (10.4 9 8)))))
+(ert-deftest cl-macs-loop-and-arrays ()
+ "Bug#40727"
+ (should (equal (cl-loop for y = (- (or x 0)) and x across [1 2]
+ collect (cons x y))
+ '((1 . 0) (2 . -1))))
+ (should (equal (cl-loop for x across [1 2] and y = (- (or x 0))
+ collect (cons x y))
+ '((1 . 0) (2 . -1)))))
+
(ert-deftest cl-macs-loop-destructure ()
(should (equal (cl-loop for (a b c) in '((1 2 4.0) (5 6 8.3) (8 9 10.4))
collect (list c b a))
@@ -416,7 +425,9 @@ collection clause."
'(2 3 4 5 6))))
(ert-deftest cl-macs-loop-across-ref ()
- (should (equal (cl-loop with my-vec = ["one" "two" "three"]
+ (should (equal (cl-loop with my-vec = (vector (cl-copy-seq "one")
+ (cl-copy-seq "two")
+ (cl-copy-seq "three"))
for x across-ref my-vec
do (setf (aref x 0) (upcase (aref x 0)))
finally return my-vec)
@@ -498,7 +509,6 @@ collection clause."
(ert-deftest cl-macs-loop-for-as-equals-and ()
"Test for https://debbugs.gnu.org/29799 ."
- :expected-result :failed
(let ((arr (make-vector 3 0)))
(should (equal '((0 0) (1 1) (2 2))
(cl-loop for k below 3 for x = k and z = (elt arr k)
@@ -532,7 +542,6 @@ collection clause."
(ert-deftest cl-macs-loop-conditional-step-clauses ()
"These tests failed under the initial fixes in #bug#29799."
- :expected-result :failed
(should (cl-loop for i from 1 upto 100 and j = 1 then (1+ j)
if (not (= i j))
return nil
@@ -592,4 +601,13 @@ collection clause."
collect y into result1
finally return (equal (nreverse result) result1))))
+(ert-deftest cl-macs-aux-edebug ()
+ "Check that Bug#40431 is fixed."
+ (with-temp-buffer
+ (prin1 '(cl-defun cl-macs-aux-edebug-test-fun (&aux ((a . b) '(1 . 2)))
+ (list a b))
+ (current-buffer))
+ ;; Just make sure the function can be instrumented.
+ (edebug-defun)))
+
;;; cl-macs-tests.el ends here
diff --git a/test/lisp/emacs-lisp/cl-seq-tests.el b/test/lisp/emacs-lisp/cl-seq-tests.el
index 6893eb8ada8..d0fad8907d5 100644
--- a/test/lisp/emacs-lisp/cl-seq-tests.el
+++ b/test/lisp/emacs-lisp/cl-seq-tests.el
@@ -294,6 +294,7 @@ Body are forms defining the test."
(ert-deftest cl-seq-test-bug24264 ()
"Test for https://debbugs.gnu.org/24264 ."
+ :tags '(:expensive-test)
(let ((list (append (make-list 8000005 1) '(8)))
(list2 (make-list 8000005 2)))
(should (cl-position 8 list))
diff --git a/test/lisp/emacs-lisp/copyright-tests.el b/test/lisp/emacs-lisp/copyright-tests.el
new file mode 100644
index 00000000000..7deb8b53a2e
--- /dev/null
+++ b/test/lisp/emacs-lisp/copyright-tests.el
@@ -0,0 +1,50 @@
+;;; copyright-tests.el --- tests for copyright.el -*- lexical-binding: t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(require 'cl-lib)
+(require 'copyright)
+
+(defmacro with-copyright-test (orig result)
+ `(cl-letf (((symbol-function 'format-time-string) (lambda (&rest _) "2019")))
+ (let ((copyright-query nil)
+ (copyright-current-year 2019))
+ (with-temp-buffer
+ (insert ,orig)
+ (copyright-update)
+ (should (equal (buffer-string) ,result))))))
+
+(defvar copyright-tests--data
+ '((";; Copyright (C) 2017 Free Software Foundation, Inc."
+ . ";; Copyright (C) 2017, 2019 Free Software Foundation, Inc.")
+ (";; Copyright (C) 2017-2018 Free Software Foundation, Inc."
+ . ";; Copyright (C) 2017-2019 Free Software Foundation, Inc.")
+ (";; Copyright (C) 2005-2006, 2015, 2017-2018 Free Software Foundation, Inc."
+ . ";; Copyright (C) 2005-2006, 2015, 2017-2019 Free Software Foundation, Inc.")
+ (";; copyright '18 FSF"
+ . ";; copyright '18, '19 FSF")))
+
+(ert-deftest test-copyright-update ()
+ (dolist (test copyright-tests--data)
+ (with-copyright-test (car test) (cdr test))))
+
+(provide 'copyright-tests)
+;;; copyright-tests.el ends here
diff --git a/test/lisp/emacs-lisp/easy-mmode-tests.el b/test/lisp/emacs-lisp/easy-mmode-tests.el
new file mode 100644
index 00000000000..77eaed62579
--- /dev/null
+++ b/test/lisp/emacs-lisp/easy-mmode-tests.el
@@ -0,0 +1,65 @@
+;;; easy-mmode-tests.el --- tests for easy-mmode.el -*- lexical-binding: t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(require 'easy-mmode)
+(require 'message)
+
+(ert-deftest easy-mmode--globalized-predicate ()
+ (with-temp-buffer
+ (emacs-lisp-mode)
+ (should (eq (easy-mmode--globalized-predicate-p nil) nil))
+ (should (eq (easy-mmode--globalized-predicate-p t) t))
+ (should (eq (easy-mmode--globalized-predicate-p '(not text-mode)) t))
+ (should (eq (easy-mmode--globalized-predicate-p '(not text-mode)) t))
+ (should (eq (easy-mmode--globalized-predicate-p '((not text-mode))) nil))
+ (should (eq (easy-mmode--globalized-predicate-p '((not text-mode) t)) t))
+ (should (eq (easy-mmode--globalized-predicate-p
+ '(c-mode emacs-lisp-mode))
+ t))
+ (mail-mode)
+ (should (eq (easy-mmode--globalized-predicate-p
+ '(c-mode (not message-mode mail-mode) text-mode))
+ nil))
+ (text-mode)
+ (should (eq (easy-mmode--globalized-predicate-p
+ '(c-mode (not message-mode mail-mode) text-mode))
+ t))))
+
+(define-minor-mode easy-mmode-test-mode "A test.")
+
+(ert-deftest easy-mmode--minor-mode ()
+ (with-temp-buffer
+ (should (eq easy-mmode-test-mode nil))
+ (easy-mmode-test-mode nil)
+ (should (eq easy-mmode-test-mode t))
+ (easy-mmode-test-mode -33)
+ (should (eq easy-mmode-test-mode nil))
+ (easy-mmode-test-mode 33)
+ (should (eq easy-mmode-test-mode t))
+ (easy-mmode-test-mode 'toggle)
+ (should (eq easy-mmode-test-mode nil))
+ (easy-mmode-test-mode 'toggle)
+ (should (eq easy-mmode-test-mode t))))
+
+(provide 'easy-mmode-tests)
+
+;;; easy-mmode-tests.el ends here
diff --git a/test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el b/test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el
index 5ea36121748..a3010f9e354 100644
--- a/test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el
+++ b/test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el
@@ -1,4 +1,4 @@
-;;; edebug-test-code.el --- Sample code for the Edebug test suite
+;;; edebug-test-code.el --- Sample code for the Edebug test suite -*- lexical-binding:t -*-
;; Copyright (C) 2017-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/emacs-lisp/edebug-tests.el b/test/lisp/emacs-lisp/edebug-tests.el
index 73d0919904b..d60a6cb3d50 100644
--- a/test/lisp/emacs-lisp/edebug-tests.el
+++ b/test/lisp/emacs-lisp/edebug-tests.el
@@ -36,17 +36,6 @@
(require 'edebug)
(require 'kmacro)
-;; Use `eval-and-compile' because this is used by the macro
-;; `edebug-tests-deftest'.
-(eval-and-compile
- (defvar edebug-tests-sample-code-file
- (expand-file-name
- "edebug-resources/edebug-test-code.el"
- (file-name-directory (or (bound-and-true-p byte-compile-current-file)
- load-file-name
- buffer-file-name)))
- "Name of file containing code samples for Edebug tests."))
-
(defvar edebug-tests-temp-file nil
"Name of temp file containing sample code stripped of stop point symbols.")
(defvar edebug-tests-stop-points nil
@@ -108,7 +97,10 @@ back to the top level.")
;; sit-on interferes with keyboard macros.
(edebug-sit-on-break nil)
- (edebug-continue-kbd-macro t))
+ (edebug-continue-kbd-macro t)
+
+ ;; don't print backtraces, otherwise error messages don't match
+ (backtrace-on-error-noninteractive nil))
,@body))
(defmacro edebug-tests-with-normal-env (&rest body)
@@ -116,7 +108,8 @@ back to the top level.")
(declare (debug (body)))
`(edebug-tests-with-default-config
(let ((edebug-tests-failure-in-post-command nil)
- (edebug-tests-temp-file (make-temp-file "edebug-tests-" nil ".el")))
+ (edebug-tests-temp-file (make-temp-file "edebug-tests-" nil ".el"))
+ (find-file-suppress-same-file-warnings t))
(edebug-tests-setup-code-file edebug-tests-temp-file)
(ert-with-message-capture
edebug-tests-messages
@@ -221,6 +214,7 @@ be the same as every keystroke) execute the thunk at the same
index."
(let* ((edebug-tests-thunks thunks)
(edebug-tests-kbd-macro-index 0)
+ (find-file-suppress-same-file-warnings t)
saved-local-map)
(with-current-buffer (find-file-noselect edebug-tests-temp-file)
(setq saved-local-map overriding-local-map)
@@ -344,7 +338,7 @@ evaluate to \"symbol\", \"symbol-1\", \"symbol-2\", etc."
Write the loadable code to a buffer for TMPFILE, and set
`edebug-tests-stop-points' to a map from defined symbols to stop
point names to positions in the file."
- (with-current-buffer (find-file-noselect edebug-tests-sample-code-file)
+ (with-current-buffer (find-file-noselect (ert-resource-file "edebug-test-code.el"))
(let ((marked-up-code (buffer-string)))
(with-temp-file tmpfile
(insert marked-up-code))))
@@ -938,5 +932,99 @@ test and possibly others should be updated."
"g"
(should (equal edebug-tests-@-result '(0 1))))))
+(ert-deftest edebug-cl-defmethod-qualifier ()
+ "Check that secondary `cl-defmethod' forms don't stomp over
+primary ones (Bug#42671)."
+ (with-temp-buffer
+ (let* ((edebug-all-defs t)
+ (edebug-initial-mode 'Go-nonstop)
+ (defined-symbols ())
+ (edebug-new-definition-function
+ (lambda (def-name)
+ (push def-name defined-symbols)
+ (edebug-new-definition def-name))))
+ (dolist (form '((cl-defmethod edebug-cl-defmethod-qualifier ((_ number)))
+ (cl-defmethod edebug-cl-defmethod-qualifier
+ :around ((_ number)))))
+ (print form (current-buffer)))
+ (eval-buffer)
+ (should
+ (equal
+ defined-symbols
+ (list (intern "edebug-cl-defmethod-qualifier :around ((_ number))")
+ (intern "edebug-cl-defmethod-qualifier ((_ number))")))))))
+
+(ert-deftest edebug-tests-cl-flet ()
+ "Check that Edebug can instrument `cl-flet' forms without name
+clashes (Bug#41853)."
+ (with-temp-buffer
+ (dolist (form '((defun edebug-tests-cl-flet-1 ()
+ (cl-flet ((inner () 0)) (message "Hi"))
+ (cl-flet ((inner () 1)) (inner)))
+ (defun edebug-tests-cl-flet-2 ()
+ (cl-flet ((inner () 2)) (inner)))))
+ (print form (current-buffer)))
+ (let* ((edebug-all-defs t)
+ (edebug-initial-mode 'Go-nonstop)
+ (instrumented-names ())
+ (edebug-new-definition-function
+ (lambda (name)
+ (when (memq name instrumented-names)
+ (error "Duplicate definition of `%s'" name))
+ (push name instrumented-names)
+ (edebug-new-definition name)))
+ ;; Make generated symbols reproducible.
+ (gensym-counter 10000))
+ (eval-buffer)
+ (should (equal (reverse instrumented-names)
+ ;; The outer definitions come after the inner
+ ;; ones because their body ends later.
+ ;; FIXME: There are twice as many inner
+ ;; definitions as expected due to Bug#41988.
+ ;; Once that bug is fixed, remove the duplicates.
+ ;; FIXME: We'd rather have names such as
+ ;; `edebug-tests-cl-flet-1@inner@cl-flet@10000',
+ ;; but that requires further changes to Edebug.
+ '(inner@cl-flet@10000
+ inner@cl-flet@10001
+ inner@cl-flet@10002
+ inner@cl-flet@10003
+ edebug-tests-cl-flet-1
+ inner@cl-flet@10004
+ inner@cl-flet@10005
+ edebug-tests-cl-flet-2))))))
+
+(ert-deftest edebug-tests-duplicate-symbol-backtrack ()
+ "Check that Edebug doesn't create duplicate symbols when
+backtracking (Bug#42701)."
+ (with-temp-buffer
+ (dolist (form '((require 'subr-x)
+ (defun edebug-tests-duplicate-symbol-backtrack ()
+ (if-let (x (funcall (lambda (y) 1) 2)) 3 4))))
+ (print form (current-buffer)))
+ (let* ((edebug-all-defs t)
+ (edebug-initial-mode 'Go-nonstop)
+ (instrumented-names ())
+ (edebug-new-definition-function
+ (lambda (name)
+ (when (memq name instrumented-names)
+ (error "Duplicate definition of `%s'" name))
+ (push name instrumented-names)
+ (edebug-new-definition name)))
+ ;; Make generated symbols reproducible.
+ (gensym-counter 10000))
+ (eval-buffer)
+ ;; The anonymous symbols are uninterned. Use their names so we
+ ;; can perform the assertion. The names should still be unique.
+ (should (equal (mapcar #'symbol-name (reverse instrumented-names))
+ ;; The outer definition comes after the inner
+ ;; ones because its body ends later.
+ ;; FIXME: There are twice as many inner
+ ;; definitions as expected due to Bug#42701.
+ ;; Once that bug is fixed, remove the duplicates.
+ '("edebug-anon10000"
+ "edebug-anon10001"
+ "edebug-tests-duplicate-symbol-backtrack"))))))
+
(provide 'edebug-tests)
;;; edebug-tests.el ends here
diff --git a/test/lisp/emacs-lisp/eieio-tests/eieio-test-methodinvoke.el b/test/lisp/emacs-lisp/eieio-tests/eieio-test-methodinvoke.el
index cd1efd1c787..285616a7806 100644
--- a/test/lisp/emacs-lisp/eieio-tests/eieio-test-methodinvoke.el
+++ b/test/lisp/emacs-lisp/eieio-tests/eieio-test-methodinvoke.el
@@ -1,4 +1,4 @@
-;;; eieio-testsinvoke.el -- eieio tests for method invocation
+;;; eieio-testsinvoke.el -- eieio tests for method invocation -*- lexical-binding:t -*-
;; Copyright (C) 2005, 2008, 2010, 2013-2021 Free Software Foundation,
;; Inc.
@@ -83,36 +83,36 @@
(defclass eitest-B-base2 () ())
(defclass eitest-B (eitest-B-base1 eitest-B-base2) ())
-(defmethod eitest-F :BEFORE ((p eitest-B-base1))
+(defmethod eitest-F :BEFORE ((_p eitest-B-base1))
(eieio-test-method-store :BEFORE 'eitest-B-base1))
-(defmethod eitest-F :BEFORE ((p eitest-B-base2))
+(defmethod eitest-F :BEFORE ((_p eitest-B-base2))
(eieio-test-method-store :BEFORE 'eitest-B-base2))
-(defmethod eitest-F :BEFORE ((p eitest-B))
+(defmethod eitest-F :BEFORE ((_p eitest-B))
(eieio-test-method-store :BEFORE 'eitest-B))
-(defmethod eitest-F ((p eitest-B))
+(defmethod eitest-F ((_p eitest-B))
(eieio-test-method-store :PRIMARY 'eitest-B)
(call-next-method))
-(defmethod eitest-F ((p eitest-B-base1))
+(defmethod eitest-F ((_p eitest-B-base1))
(eieio-test-method-store :PRIMARY 'eitest-B-base1)
(call-next-method))
-(defmethod eitest-F ((p eitest-B-base2))
+(defmethod eitest-F ((_p eitest-B-base2))
(eieio-test-method-store :PRIMARY 'eitest-B-base2)
(when (next-method-p)
(call-next-method))
)
-(defmethod eitest-F :AFTER ((p eitest-B-base1))
+(defmethod eitest-F :AFTER ((_p eitest-B-base1))
(eieio-test-method-store :AFTER 'eitest-B-base1))
-(defmethod eitest-F :AFTER ((p eitest-B-base2))
+(defmethod eitest-F :AFTER ((_p eitest-B-base2))
(eieio-test-method-store :AFTER 'eitest-B-base2))
-(defmethod eitest-F :AFTER ((p eitest-B))
+(defmethod eitest-F :AFTER ((_p eitest-B))
(eieio-test-method-store :AFTER 'eitest-B))
(ert-deftest eieio-test-method-order-list-3 ()
@@ -136,7 +136,7 @@
;;; Test static invocation
;;
-(defmethod eitest-H :STATIC ((class eitest-A))
+(defmethod eitest-H :STATIC ((_class eitest-A))
"No need to do work in here."
'moose)
@@ -147,15 +147,15 @@
;;; Return value from :PRIMARY
;;
-(defmethod eitest-I :BEFORE ((a eitest-A))
+(defmethod eitest-I :BEFORE ((_a eitest-A))
(eieio-test-method-store :BEFORE 'eitest-A)
":before")
-(defmethod eitest-I :PRIMARY ((a eitest-A))
+(defmethod eitest-I :PRIMARY ((_a eitest-A))
(eieio-test-method-store :PRIMARY 'eitest-A)
":primary")
-(defmethod eitest-I :AFTER ((a eitest-A))
+(defmethod eitest-I :AFTER ((_a eitest-A))
(eieio-test-method-store :AFTER 'eitest-A)
":after")
@@ -174,17 +174,17 @@
(defclass C (C-base1 C-base2) ())
;; Just use the obsolete name once, to make sure it also works.
-(defmethod constructor :STATIC ((p C-base1) &rest args)
+(defmethod constructor :STATIC ((_p C-base1) &rest _args)
(eieio-test-method-store :STATIC 'C-base1)
(if (next-method-p) (call-next-method))
)
-(defmethod make-instance :STATIC ((p C-base2) &rest args)
+(defmethod make-instance :STATIC ((_p C-base2) &rest _args)
(eieio-test-method-store :STATIC 'C-base2)
(if (next-method-p) (call-next-method))
)
-(cl-defmethod make-instance ((p (subclass C)) &rest args)
+(cl-defmethod make-instance ((_p (subclass C)) &rest _args)
(eieio-test-method-store :STATIC 'C)
(cl-call-next-method)
)
@@ -213,24 +213,24 @@
(defclass D-base2 (D-base0) () :method-invocation-order :depth-first)
(defclass D (D-base1 D-base2) () :method-invocation-order :depth-first)
-(defmethod eitest-F ((p D))
+(defmethod eitest-F ((_p D))
"D"
(eieio-test-method-store :PRIMARY 'D)
(call-next-method))
-(defmethod eitest-F ((p D-base0))
+(defmethod eitest-F ((_p D-base0))
"D-base0"
(eieio-test-method-store :PRIMARY 'D-base0)
;; This should have no next
;; (when (next-method-p) (call-next-method))
)
-(defmethod eitest-F ((p D-base1))
+(defmethod eitest-F ((_p D-base1))
"D-base1"
(eieio-test-method-store :PRIMARY 'D-base1)
(call-next-method))
-(defmethod eitest-F ((p D-base2))
+(defmethod eitest-F ((_p D-base2))
"D-base2"
(eieio-test-method-store :PRIMARY 'D-base2)
(when (next-method-p)
@@ -256,21 +256,21 @@
(defclass E-base2 (E-base0) () :method-invocation-order :breadth-first)
(defclass E (E-base1 E-base2) () :method-invocation-order :breadth-first)
-(defmethod eitest-F ((p E))
+(defmethod eitest-F ((_p E))
(eieio-test-method-store :PRIMARY 'E)
(call-next-method))
-(defmethod eitest-F ((p E-base0))
+(defmethod eitest-F ((_p E-base0))
(eieio-test-method-store :PRIMARY 'E-base0)
;; This should have no next
;; (when (next-method-p) (call-next-method))
)
-(defmethod eitest-F ((p E-base1))
+(defmethod eitest-F ((_p E-base1))
(eieio-test-method-store :PRIMARY 'E-base1)
(call-next-method))
-(defmethod eitest-F ((p E-base2))
+(defmethod eitest-F ((_p E-base2))
(eieio-test-method-store :PRIMARY 'E-base2)
(when (next-method-p)
(call-next-method))
@@ -293,7 +293,7 @@
(defclass eitest-Ja ()
())
-(defmethod initialize-instance :after ((this eitest-Ja) &rest slots)
+(defmethod initialize-instance :after ((_this eitest-Ja) &rest _slots)
;(message "+Ja")
;; FIXME: Using next-method-p in an after-method is invalid!
(when (next-method-p)
@@ -304,7 +304,7 @@
(defclass eitest-Jb ()
())
-(defmethod initialize-instance :after ((this eitest-Jb) &rest slots)
+(defmethod initialize-instance :after ((_this eitest-Jb) &rest _slots)
;(message "+Jb")
;; FIXME: Using next-method-p in an after-method is invalid!
(when (next-method-p)
@@ -318,7 +318,7 @@
(defclass eitest-Jd (eitest-Jc eitest-Ja)
())
-(defmethod initialize-instance ((this eitest-Jd) &rest slots)
+(defmethod initialize-instance ((_this eitest-Jd) &rest _slots)
;(message "+Jd")
(when (next-method-p)
(call-next-method))
@@ -357,7 +357,7 @@
(call-next-method
this (cons 'CNM-1-1 args))))
-(defmethod CNM-M ((this CNM-1-2) args)
+(defmethod CNM-M ((_this CNM-1-2) args)
(push (cons 'CNM-1-2 (copy-sequence args))
eieio-test-call-next-method-arguments)
(when (next-method-p)
diff --git a/test/lisp/emacs-lisp/eieio-tests/eieio-test-persist.el b/test/lisp/emacs-lisp/eieio-tests/eieio-test-persist.el
index 5eee709d626..ddbef02c35a 100644
--- a/test/lisp/emacs-lisp/eieio-tests/eieio-test-persist.el
+++ b/test/lisp/emacs-lisp/eieio-tests/eieio-test-persist.el
@@ -1,4 +1,4 @@
-;;; eieio-test-persist.el --- Tests for eieio-persistent class
+;;; eieio-test-persist.el --- Tests for eieio-persistent class -*- lexical-binding:t -*-
;; Copyright (C) 2011-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el b/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el
index 19f4b15586e..a47fb8053b9 100644
--- a/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el
+++ b/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el
@@ -1,4 +1,4 @@
-;;; eieio-tests.el -- eieio tests routines
+;;; eieio-tests.el -- eieio test routines -*- lexical-binding: t -*-
;; Copyright (C) 1999-2003, 2005-2010, 2012-2021 Free Software
;; Foundation, Inc.
@@ -356,7 +356,7 @@ METHOD is the method that was attempting to be called."
(oset a test-tag 1))
(let ((ca (class-a)))
- (should-not (/= (oref ca test-tag) 2))))
+ (should (= (oref ca test-tag) 2))))
;;; Perform slot testing
@@ -852,6 +852,7 @@ Subclasses to override slot attributes.")
"Instance Tracker test object.")
(ert-deftest eieio-test-33-instance-tracker ()
+ (defvar IT-list)
(let (IT-list IT1)
(should (setq IT1 (IT)))
;; The instance tracker must find this
diff --git a/test/lisp/emacs-lisp/ert-tests.el b/test/lisp/emacs-lisp/ert-tests.el
index 8014c5d56eb..40cb432708e 100644
--- a/test/lisp/emacs-lisp/ert-tests.el
+++ b/test/lisp/emacs-lisp/ert-tests.el
@@ -801,6 +801,21 @@ This macro is used to test if macroexpansion in `should' works."
(should (eql 0 (ert-stats-completed-unexpected stats)))
(should (eql 1 (ert-stats-skipped stats)))))
+(ert-deftest ert-test-with-demoted-errors ()
+ "Check that ERT correctly handles `with-demoted-errors'."
+ :expected-result :failed ;; FIXME! Bug#11218
+ (should-not (with-demoted-errors (error "Foo"))))
+
+(ert-deftest ert-test-fail-inside-should ()
+ "Check that `ert-fail' inside `should' works correctly."
+ (let ((result (ert-run-test
+ (make-ert-test
+ :name 'test-1
+ :body (lambda () (should (integerp (ert-fail "Boo"))))))))
+ (should (ert-test-failed-p result))
+ (should (equal (ert-test-failed-condition result)
+ '(ert-test-failed ("Boo"))))))
+
(provide 'ert-tests)
diff --git a/test/lisp/emacs-lisp/ert-x-tests.el b/test/lisp/emacs-lisp/ert-x-tests.el
index d190df34ca1..f46fa63e4ce 100644
--- a/test/lisp/emacs-lisp/ert-x-tests.el
+++ b/test/lisp/emacs-lisp/ert-x-tests.el
@@ -1,4 +1,4 @@
-;;; ert-x-tests.el --- Tests for ert-x.el
+;;; ert-x-tests.el --- Tests for ert-x.el -*- lexical-binding:t -*-
;; Copyright (C) 2008, 2010-2021 Free Software Foundation, Inc.
@@ -187,18 +187,15 @@
"Tests `ert-describe-test'."
(save-window-excursion
(ert-with-buffer-renamed ("*Help*")
- (if (< emacs-major-version 24)
- (should (equal (should-error (ert-describe-test 'ert-describe-test))
- '(error "Requires Emacs 24")))
- (ert-describe-test 'ert-test-describe-test)
- (with-current-buffer "*Help*"
- (let ((case-fold-search nil))
- (should (string-match (concat
- "\\`ert-test-describe-test is a test"
- " defined in"
- " ['`‘]ert-x-tests.elc?['’]\\.\n\n"
- "Tests ['`‘]ert-describe-test['’]\\.\n\\'")
- (buffer-string)))))))))
+ (ert-describe-test 'ert-test-describe-test)
+ (with-current-buffer "*Help*"
+ (let ((case-fold-search nil))
+ (should (string-match (concat
+ "\\`ert-test-describe-test is a test"
+ " defined in"
+ " ['`‘]ert-x-tests.elc?['’]\\.\n\n"
+ "Tests ['`‘]ert-describe-test['’]\\.\n\\'")
+ (buffer-string))))))))
(ert-deftest ert-test-message-log-truncation ()
:tags '(:causes-redisplay)
diff --git a/test/lisp/emacs-lisp/faceup-resources/faceup-test-mode.el b/test/lisp/emacs-lisp/faceup-resources/faceup-test-mode.el
index 7fefe3b15a1..9040cc07270 100644
--- a/test/lisp/emacs-lisp/faceup-resources/faceup-test-mode.el
+++ b/test/lisp/emacs-lisp/faceup-resources/faceup-test-mode.el
@@ -1,4 +1,4 @@
-;;; faceup-test-mode.el --- Dummy major mode for testing `faceup'.
+;;; faceup-test-mode.el --- Dummy major mode for testing `faceup'. -*- lexical-binding:t -*-
;; Copyright (C) 2014-2021 Free Software Foundation, Inc.
@@ -44,7 +44,7 @@
(0 (progn
(add-text-properties (match-beginning 0)
(match-end 0)
- '(help-echo "Baloon tip: Fly smoothly!"))
+ '(help-echo "Balloon tip: Fly smoothly!"))
font-lock-warning-face))))
"Highlight rules for `faceup-test-mode'.")
@@ -67,8 +67,8 @@ If `prog-mode' is defined, inherit from it."
(faceup-test-define-prog-mode faceup-test-mode "faceup-test"
"Dummy major mode for testing `faceup', a test system for font-lock."
- (set (make-local-variable 'syntax-propertize-function)
- #'faceup-test-syntax-propertize)
+ (setq-local syntax-propertize-function
+ #'faceup-test-syntax-propertize)
(setq font-lock-defaults '(faceup-test-font-lock-keywords nil)))
(provide 'faceup-test-mode)
diff --git a/test/lisp/emacs-lisp/faceup-resources/faceup-test-this-file-directory.el b/test/lisp/emacs-lisp/faceup-resources/faceup-test-this-file-directory.el
index f859eb0688e..3303e7b178d 100644
--- a/test/lisp/emacs-lisp/faceup-resources/faceup-test-this-file-directory.el
+++ b/test/lisp/emacs-lisp/faceup-resources/faceup-test-this-file-directory.el
@@ -1,4 +1,4 @@
-;;; faceup-test-this-file-directory.el --- Support file for faceup tests
+;;; faceup-test-this-file-directory.el --- Support file for faceup tests -*- lexical-binding:t -*-
;; Copyright (C) 2014-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/emacs-lisp/faceup-resources/files/test1.txt.faceup b/test/lisp/emacs-lisp/faceup-resources/files/test1.txt.faceup
index 7d4938adf17..ec9e82148fd 100644
--- a/test/lisp/emacs-lisp/faceup-resources/files/test1.txt.faceup
+++ b/test/lisp/emacs-lisp/faceup-resources/files/test1.txt.faceup
@@ -1,7 +1,7 @@
This is a test of `faceup', a regression test system for font-lock
keywords. It should use major mode `faceup-test-mode'.
-«(help-echo):"Baloon tip: Fly smoothly!":«w:WARNING»»: The first word on this line should use
+«(help-echo):"Balloon tip: Fly smoothly!":«w:WARNING»»: The first word on this line should use
`font-lock-warning-face', and a tooltip should be displayed if the
mouse pointer is moved over it.
diff --git a/test/lisp/emacs-lisp/faceup-tests/faceup-test-basics.el b/test/lisp/emacs-lisp/faceup-tests/faceup-test-basics.el
index fa3372fa240..0c7e001cc75 100644
--- a/test/lisp/emacs-lisp/faceup-tests/faceup-test-basics.el
+++ b/test/lisp/emacs-lisp/faceup-tests/faceup-test-basics.el
@@ -1,4 +1,4 @@
-;;; faceup-test-basics.el --- Tests for the `faceup' package.
+;;; faceup-test-basics.el --- Tests for the `faceup' package. -*- lexical-binding:t -*-
;; Copyright (C) 2014-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/emacs-lisp/faceup-tests/faceup-test-files.el b/test/lisp/emacs-lisp/faceup-tests/faceup-test-files.el
index b591fe2a241..16e172692c0 100644
--- a/test/lisp/emacs-lisp/faceup-tests/faceup-test-files.el
+++ b/test/lisp/emacs-lisp/faceup-tests/faceup-test-files.el
@@ -1,4 +1,4 @@
-;;; faceup-test-files.el --- Self test of `faceup' using dummy major mode.
+;;; faceup-test-files.el --- Self test of `faceup' using dummy major mode. -*- lexical-binding:t -*-
;; Copyright (C) 2014-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/emacs-lisp/find-func-tests.el b/test/lisp/emacs-lisp/find-func-tests.el
new file mode 100644
index 00000000000..28a9a7ecda3
--- /dev/null
+++ b/test/lisp/emacs-lisp/find-func-tests.el
@@ -0,0 +1,120 @@
+;;; find-func-tests.el --- Unit tests for find-func.el -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
+;; Keywords:
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'ert-x) ;For `ert-run-keys'.
+(require 'find-func)
+
+(ert-deftest find-func-tests--library-completion () ;bug#43393
+ ;; FIXME: How can we make this work in batch (see also
+ ;; `mule-cmds--test-universal-coding-system-argument')?
+ ;; (skip-unless (not noninteractive))
+ ;; Check that `partial-completion' works when completing library names.
+ (should (equal "org/org"
+ (ert-simulate-keys
+ (kbd "o / o r g TAB RET")
+ (read-library-name))))
+ ;; Check that absolute file names also work.
+ (should (equal (expand-file-name "nxml/" data-directory)
+ (ert-simulate-keys
+ (concat data-directory (kbd "n x / TAB RET"))
+ (read-library-name)))))
+
+(ert-deftest find-func-tests--locate-symbols ()
+ (should (cdr
+ (find-function-search-for-symbol
+ #'goto-line nil "simple")))
+ (should (cdr
+ (find-function-search-for-symbol
+ 'minibuffer-history 'defvar "simple")))
+ (should (cdr
+ (find-function-search-for-symbol
+ 'with-current-buffer nil "subr")))
+ (should (cdr
+ (find-function-search-for-symbol
+ 'font-lock-warning-face 'defface "font-lock")))
+ (should-not (cdr
+ (find-function-search-for-symbol
+ 'wrong-variable 'defvar "simple")))
+ (should-not (cdr
+ (find-function-search-for-symbol
+ 'wrong-function nil "simple")))
+ (should (cdr (find-function-noselect #'goto-line)))
+ (should (cdr (find-function-noselect #'goto-char)))
+ ;; Setting LISP-ONLY and passing a primitive should error.
+ (should-error (find-function-noselect #'goto-char t))
+ (should-error (find-function-noselect 'wrong-function)))
+
+(defun test-locate-helper (func &optional expected-result)
+ "Assert on the result of `find-function-library' for FUNC.
+EXPECTED-RESULT is an alist (FUNC . LIBRARY) with the
+expected function symbol and function library, respectively."
+ (cl-destructuring-bind (orig-function . library)
+ (find-function-library func)
+ (cl-destructuring-bind (expected-func . expected-library)
+ expected-result
+ (should (eq orig-function expected-func))
+ (should (and
+ (not (string-empty-p expected-library))
+ (string-match-p expected-library library))))))
+
+(ert-deftest find-func-tests--locate-library ()
+ (test-locate-helper #'goto-line '(goto-line . "simple"))
+ (test-locate-helper #'forward-char '(forward-char . "cmds.c"))
+ (should-error (test-locate-helper 'wrong-function)))
+
+(ert-deftest find-func-tests--locate-adviced-symbols ()
+ (defun my-message ()
+ (message "Hello!"))
+ (advice-add #'mark-sexp :around 'my-message)
+ (test-locate-helper #'mark-sexp '(mark-sexp . "lisp"))
+ (advice-remove #'mark-sexp 'my-message))
+
+(ert-deftest find-func-tests--find-library-verbose ()
+ (find-function-library #'join-line nil t)
+ (with-current-buffer "*Messages*"
+ (save-excursion
+ (goto-char (point-max))
+ (skip-chars-backward "\n")
+ (should (string-match-p
+ ".join-line. is an alias for .delete-indentation."
+ (buffer-substring
+ (line-beginning-position)
+ (point)))))))
+
+;; Avoid a byte-compilation warning that may confuse people reading
+;; the result of the following test.
+(declare-function compilation--message->loc nil "compile")
+
+(ert-deftest find-func-tests--locate-macro-generated-symbols () ;bug#45443
+ (should (cdr (find-function-search-for-symbol
+ #'compilation--message->loc nil "compile")))
+ (should (cdr (find-function-search-for-symbol
+ 'c-mode-hook 'defvar "cc-mode"))))
+
+(provide 'find-func-tests)
+;;; find-func-tests.el ends here
diff --git a/test/lisp/emacs-lisp/float-sup-tests.el b/test/lisp/emacs-lisp/float-sup-tests.el
new file mode 100644
index 00000000000..9e87928c232
--- /dev/null
+++ b/test/lisp/emacs-lisp/float-sup-tests.el
@@ -0,0 +1,33 @@
+;;; float-sup-tests.el --- Tests for float-sup.el -*- lexical-binding:t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+
+(ert-deftest float-sup-degrees-and-radians ()
+ (should (equal (degrees-to-radians 180.0) float-pi))
+ (should (equal (radians-to-degrees float-pi) 180.0))
+ (should (equal (radians-to-degrees (degrees-to-radians 360.0)) 360.0))
+ (should (equal (degrees-to-radians (radians-to-degrees float-pi)) float-pi)))
+
+(provide 'float-sup-tests)
+;;; float-sup-tests.el ends here
diff --git a/test/lisp/emacs-lisp/generator-tests.el b/test/lisp/emacs-lisp/generator-tests.el
index c9ab42a7f67..ffcd16ad094 100644
--- a/test/lisp/emacs-lisp/generator-tests.el
+++ b/test/lisp/emacs-lisp/generator-tests.el
@@ -30,6 +30,8 @@
(require 'ert)
(require 'cl-lib)
+;;; Code:
+
(defun generator-list-subrs ()
(cl-loop for x being the symbols
when (and (fboundp x)
@@ -306,4 +308,13 @@ identical output."
(1+ it)))))))
-2)))
+(ert-deftest generator-tests-edebug ()
+ "Check that Bug#40434 is fixed."
+ (with-temp-buffer
+ (prin1 '(iter-defun generator-tests-edebug ()
+ (iter-yield 123))
+ (current-buffer))
+ (edebug-defun))
+ (should (eql (iter-next (generator-tests-edebug)) 123)))
+
;;; generator-tests.el ends here
diff --git a/test/lisp/emacs-lisp/gv-tests.el b/test/lisp/emacs-lisp/gv-tests.el
index 46c0ab17406..b9850eca8b9 100644
--- a/test/lisp/emacs-lisp/gv-tests.el
+++ b/test/lisp/emacs-lisp/gv-tests.el
@@ -19,6 +19,7 @@
;;; Code:
+(require 'edebug)
(require 'ert)
(eval-when-compile (require 'cl-lib))
@@ -82,7 +83,10 @@
(with-temp-buffer
(call-process (concat invocation-directory invocation-name)
nil '(t t) nil
- "-Q" "-batch" "--eval" (prin1-to-string `(byte-compile-file ,el))
+ "-Q" "-batch"
+ "--eval" (prin1-to-string
+ `(let ((backtrace-on-error-noninteractive nil))
+ (byte-compile-file ,el)))
"-l" elc)
(should (equal (buffer-string)
"Symbol's function definition is void: \\(setf\\ gv-test-foo\\)\n")))))
@@ -132,10 +136,71 @@
"-Q" "-batch" "--eval" (prin1-to-string `(byte-compile-file ,el))
"-l" elc
"--eval"
- (prin1-to-string '(progn (setf (gv-test-foo gv-test-pair) 99)
- (message "%d" (car gv-test-pair)))))
- (should (equal (buffer-string)
- "Symbol's function definition is void: \\(setf\\ gv-test-foo\\)\n")))))
+ (prin1-to-string
+ '(let ((backtrace-on-error-noninteractive nil))
+ (setf (gv-test-foo gv-test-pair) 99)
+ (message "%d" (car gv-test-pair)))))
+ (should (string-match
+ "\\`Symbol.s function definition is void: \\\\(setf\\\\ gv-test-foo\\\\)\n\\'"
+ (buffer-string))))))
+
+(ert-deftest gv-setter-edebug ()
+ "Check that a setter can be defined and edebugged together with
+its getter (Bug#41853)."
+ (with-temp-buffer
+ (let ((edebug-all-defs t)
+ (edebug-initial-mode 'Go-nonstop))
+ (dolist (form '((defun gv-setter-edebug-help (b) b)
+ (defun gv-setter-edebug-get (a b)
+ (get a (gv-setter-edebug-help b)))
+ (gv-define-setter gv-setter-edebug-get (x a b)
+ `(setf (get ,a (gv-setter-edebug-help ,b)) ,x))
+ (push 123 (gv-setter-edebug-get 'gv-setter-edebug
+ 'gv-setter-edebug-prop))))
+ (print form (current-buffer)))
+ ;; Only check whether evaluation works in general.
+ (eval-buffer)))
+ (should (equal (get 'gv-setter-edebug 'gv-setter-edebug-prop) '(123))))
+
+(ert-deftest gv-plist-get ()
+ (require 'cl-lib)
+
+ ;; Simple setf usage for plist-get.
+ (should (equal (let ((target '(:a "a" :b "b" :c "c")))
+ (setf (plist-get target :b) "modify")
+ target)
+ '(:a "a" :b "modify" :c "c")))
+
+ ;; Other function (cl-rotatef) usage for plist-get.
+ (should (equal (let ((target '(:a "a" :b "b" :c "c")))
+ (cl-rotatef (plist-get target :b) (plist-get target :c))
+ target)
+ '(:a "a" :b "c" :c "b")))
+
+ ;; Add new key value pair at top of list if setf for missing key.
+ (should (equal (let ((target '(:a "a" :b "b" :c "c")))
+ (setf (plist-get target :d) "modify")
+ target)
+ '(:d "modify" :a "a" :b "b" :c "c")))
+
+ ;; Rotate with missing value.
+ ;; The value corresponding to the missing key is assumed to be nil.
+ (should (equal (let ((target '(:a "a" :b "b" :c "c")))
+ (cl-rotatef (plist-get target :b) (plist-get target :d))
+ target)
+ '(:d "b" :a "a" :b nil :c "c")))
+
+ ;; Simple setf usage for plist-get. (symbol plist)
+ (should (equal (let ((target '(a "a" b "b" c "c")))
+ (setf (plist-get target 'b) "modify")
+ target)
+ '(a "a" b "modify" c "c")))
+
+ ;; Other function (cl-rotatef) usage for plist-get. (symbol plist)
+ (should (equal (let ((target '(a "a" b "b" c "c")))
+ (cl-rotatef (plist-get target 'b) (plist-get target 'c))
+ target)
+ '(a "a" b "c" c "b"))))
;; `ert-deftest' messes up macroexpansion when the test file itself is
;; compiled (see Bug #24402).
diff --git a/test/lisp/emacs-lisp/hierarchy-tests.el b/test/lisp/emacs-lisp/hierarchy-tests.el
new file mode 100644
index 00000000000..41d3f2f3ccf
--- /dev/null
+++ b/test/lisp/emacs-lisp/hierarchy-tests.el
@@ -0,0 +1,556 @@
+;;; hierarchy-tests.el --- Tests for hierarchy.el -*- lexical-binding:t -*-
+
+;; Copyright (C) 2017-2019 Damien Cassou
+
+;; Author: Damien Cassou <damien@cassou.me>
+;; Maintainer: emacs-devel@gnu.org
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Tests for hierarchy.el
+
+;;; Code:
+
+(require 'ert)
+(require 'hierarchy)
+
+(defun hierarchy-animals ()
+ "Create a sorted animal hierarchy."
+ (let ((parentfn (lambda (item) (cl-case item
+ (dove 'bird)
+ (pigeon 'bird)
+ (bird 'animal)
+ (dolphin 'animal)
+ (cow 'animal))))
+ (hierarchy (hierarchy-new)))
+ (hierarchy-add-tree hierarchy 'dove parentfn)
+ (hierarchy-add-tree hierarchy 'pigeon parentfn)
+ (hierarchy-add-tree hierarchy 'dolphin parentfn)
+ (hierarchy-add-tree hierarchy 'cow parentfn)
+ (hierarchy-sort hierarchy)
+ hierarchy))
+
+(ert-deftest hierarchy-add-one-root ()
+ (let ((parentfn (lambda (_) nil))
+ (hierarchy (hierarchy-new)))
+ (hierarchy-add-tree hierarchy 'animal parentfn)
+ (should (equal (hierarchy-roots hierarchy) '(animal)))))
+
+(ert-deftest hierarchy-add-one-item-with-parent ()
+ (let ((parentfn (lambda (item)
+ (cl-case item
+ (bird 'animal))))
+ (hierarchy (hierarchy-new)))
+ (hierarchy-add-tree hierarchy 'bird parentfn)
+ (should (equal (hierarchy-roots hierarchy) '(animal)))
+ (should (equal (hierarchy-children hierarchy 'animal) '(bird)))))
+
+(ert-deftest hierarchy-add-one-item-with-parent-and-grand-parent ()
+ (let ((parentfn (lambda (item)
+ (cl-case item
+ (dove 'bird)
+ (bird 'animal))))
+ (hierarchy (hierarchy-new)))
+ (hierarchy-add-tree hierarchy 'dove parentfn)
+ (should (equal (hierarchy-roots hierarchy) '(animal)))
+ (should (equal (hierarchy-children hierarchy 'animal) '(bird)))
+ (should (equal (hierarchy-children hierarchy 'bird) '(dove)))))
+
+(ert-deftest hierarchy-add-same-root-twice ()
+ (let ((parentfn (lambda (_) nil))
+ (hierarchy (hierarchy-new)))
+ (hierarchy-add-tree hierarchy 'animal parentfn)
+ (hierarchy-add-tree hierarchy 'animal parentfn)
+ (should (equal (hierarchy-roots hierarchy) '(animal)))))
+
+(ert-deftest hierarchy-add-same-child-twice ()
+ (let ((parentfn (lambda (item)
+ (cl-case item
+ (bird 'animal))))
+ (hierarchy (hierarchy-new)))
+ (hierarchy-add-tree hierarchy 'bird parentfn)
+ (hierarchy-add-tree hierarchy 'bird parentfn)
+ (should (equal (hierarchy-roots hierarchy) '(animal)))
+ (should (equal (hierarchy-children hierarchy 'animal) '(bird)))))
+
+(ert-deftest hierarchy-add-item-and-its-parent ()
+ (let ((parentfn (lambda (item)
+ (cl-case item
+ (bird 'animal))))
+ (hierarchy (hierarchy-new)))
+ (hierarchy-add-tree hierarchy 'bird parentfn)
+ (hierarchy-add-tree hierarchy 'animal parentfn)
+ (should (equal (hierarchy-roots hierarchy) '(animal)))
+ (should (equal (hierarchy-children hierarchy 'animal) '(bird)))))
+
+(ert-deftest hierarchy-add-item-and-its-child ()
+ (let ((parentfn (lambda (item)
+ (cl-case item
+ (bird 'animal))))
+ (hierarchy (hierarchy-new)))
+ (hierarchy-add-tree hierarchy 'animal parentfn)
+ (hierarchy-add-tree hierarchy 'bird parentfn)
+ (should (equal (hierarchy-roots hierarchy) '(animal)))
+ (should (equal (hierarchy-children hierarchy 'animal) '(bird)))))
+
+(ert-deftest hierarchy-add-two-items-sharing-parent ()
+ (let ((parentfn (lambda (item)
+ (cl-case item
+ (dove 'bird)
+ (pigeon 'bird))))
+ (hierarchy (hierarchy-new)))
+ (hierarchy-add-tree hierarchy 'dove parentfn)
+ (hierarchy-add-tree hierarchy 'pigeon parentfn)
+ (should (equal (hierarchy-roots hierarchy) '(bird)))
+ (should (equal (hierarchy-children hierarchy 'bird) '(dove pigeon)))))
+
+(ert-deftest hierarchy-add-two-hierarchies ()
+ (let ((parentfn (lambda (item)
+ (cl-case item
+ (dove 'bird)
+ (circle 'shape))))
+ (hierarchy (hierarchy-new)))
+ (hierarchy-add-tree hierarchy 'dove parentfn)
+ (hierarchy-add-tree hierarchy 'circle parentfn)
+ (should (equal (hierarchy-roots hierarchy) '(bird shape)))
+ (should (equal (hierarchy-children hierarchy 'bird) '(dove)))
+ (should (equal (hierarchy-children hierarchy 'shape) '(circle)))))
+
+(ert-deftest hierarchy-add-with-childrenfn ()
+ (let ((childrenfn (lambda (item)
+ (cl-case item
+ (animal '(bird))
+ (bird '(dove pigeon)))))
+ (hierarchy (hierarchy-new)))
+ (hierarchy-add-tree hierarchy 'animal nil childrenfn)
+ (should (equal (hierarchy-roots hierarchy) '(animal)))
+ (should (equal (hierarchy-children hierarchy 'animal) '(bird)))
+ (should (equal (hierarchy-children hierarchy 'bird) '(dove pigeon)))))
+
+(ert-deftest hierarchy-add-with-parentfn-and-childrenfn ()
+ (let ((parentfn (lambda (item)
+ (cl-case item
+ (bird 'animal)
+ (animal 'life-form))))
+ (childrenfn (lambda (item)
+ (cl-case item
+ (bird '(dove pigeon))
+ (pigeon '(ashy-wood-pigeon)))))
+ (hierarchy (hierarchy-new)))
+ (hierarchy-add-tree hierarchy 'bird parentfn childrenfn)
+ (should (equal (hierarchy-roots hierarchy) '(life-form)))
+ (should (equal (hierarchy-children hierarchy 'life-form) '(animal)))
+ (should (equal (hierarchy-children hierarchy 'animal) '(bird)))
+ (should (equal (hierarchy-children hierarchy 'bird) '(dove pigeon)))
+ (should (equal (hierarchy-children hierarchy 'pigeon) '(ashy-wood-pigeon)))))
+
+(ert-deftest hierarchy-add-twice-with-parentfn-and-childrenfn ()
+ (let* ((parentfn (lambda (item)
+ (cl-case item
+ (dove 'bird)
+ (bird 'animal))))
+ (childrenfn (lambda (item)
+ (cl-case item
+ (animal '(bird))
+ (bird '(dove)))))
+ (hierarchy (hierarchy-new)))
+ (hierarchy-add-tree hierarchy 'bird parentfn childrenfn)
+ (should (equal (hierarchy-children hierarchy 'animal) '(bird)))
+ (should (equal (hierarchy-children hierarchy 'bird) '(dove)))))
+
+(ert-deftest hierarchy-add-trees ()
+ (let ((parentfn (lambda (item)
+ (cl-case item
+ (dove 'bird)
+ (pigeon 'bird)
+ (bird 'animal))))
+ (hierarchy (hierarchy-new)))
+ (hierarchy-add-trees hierarchy '(dove pigeon) parentfn)
+ (should (equal (hierarchy-roots hierarchy) '(animal)))
+ (should (equal (hierarchy-children hierarchy 'animal) '(bird)))
+ (should (equal (hierarchy-children hierarchy 'bird) '(dove pigeon)))))
+
+(ert-deftest hierarchy-from-list ()
+ (let ((hierarchy (hierarchy-from-list
+ '(animal (bird (dove)
+ (pigeon))
+ (cow)
+ (dolphin)))))
+ (hierarchy-sort hierarchy (lambda (item1 item2)
+ (string< (car item1)
+ (car item2))))
+ (should (equal (hierarchy-to-string hierarchy (lambda (item) (symbol-name (car item))))
+ "animal\n bird\n dove\n pigeon\n cow\n dolphin\n"))))
+
+(ert-deftest hierarchy-from-list-with-duplicates ()
+ (let ((hierarchy (hierarchy-from-list
+ '(a (b) (b))
+ t)))
+ (hierarchy-sort hierarchy (lambda (item1 item2)
+ ;; sort by ID
+ (< (car item1) (car item2))))
+ (should (equal (hierarchy-length hierarchy) 3))
+ (should (equal (hierarchy-to-string
+ hierarchy
+ (lambda (item)
+ (format "%s(%s)"
+ (cadr item)
+ (car item))))
+ "a(1)\n b(2)\n b(3)\n"))))
+
+(ert-deftest hierarchy-from-list-with-childrenfn ()
+ (let ((hierarchy (hierarchy-from-list
+ "abc"
+ nil
+ (lambda (item)
+ (when (string= item "abc")
+ (split-string item "" t))))))
+ (hierarchy-sort hierarchy (lambda (item1 item2) (string< item1 item2)))
+ (should (equal (hierarchy-length hierarchy) 4))
+ (should (equal (hierarchy-to-string hierarchy)
+ "abc\n a\n b\n c\n"))))
+
+(ert-deftest hierarchy-add-relation-check-error-when-different-parent ()
+ (let ((parentfn (lambda (item)
+ (cl-case item
+ (bird 'animal))))
+ (hierarchy (hierarchy-new)))
+ (hierarchy-add-tree hierarchy 'bird parentfn)
+ (should-error
+ (hierarchy--add-relation hierarchy 'bird 'cow #'identity))))
+
+(ert-deftest hierarchy-empty-p-return-non-nil-for-empty ()
+ (should (hierarchy-empty-p (hierarchy-new))))
+
+(ert-deftest hierarchy-empty-p-return-nil-for-non-empty ()
+ (should-not (hierarchy-empty-p (hierarchy-animals))))
+
+(ert-deftest hierarchy-length-of-empty-is-0 ()
+ (should (equal (hierarchy-length (hierarchy-new)) 0)))
+
+(ert-deftest hierarchy-length-of-non-empty-counts-items ()
+ (let ((parentfn (lambda (item)
+ (cl-case item
+ (bird 'animal)
+ (dove 'bird)
+ (pigeon 'bird))))
+ (hierarchy (hierarchy-new)))
+ (hierarchy-add-tree hierarchy 'dove parentfn)
+ (hierarchy-add-tree hierarchy 'pigeon parentfn)
+ (should (equal (hierarchy-length hierarchy) 4))))
+
+(ert-deftest hierarchy-has-root ()
+ (let ((parentfn (lambda (item)
+ (cl-case item
+ (bird 'animal)
+ (dove 'bird)
+ (pigeon 'bird))))
+ (hierarchy (hierarchy-new)))
+ (should-not (hierarchy-has-root hierarchy 'animal))
+ (should-not (hierarchy-has-root hierarchy 'bird))
+ (hierarchy-add-tree hierarchy 'dove parentfn)
+ (hierarchy-add-tree hierarchy 'pigeon parentfn)
+ (should (hierarchy-has-root hierarchy 'animal))
+ (should-not (hierarchy-has-root hierarchy 'bird))))
+
+(ert-deftest hierarchy-leafs ()
+ (let ((animals (hierarchy-animals)))
+ (should (equal (hierarchy-leafs animals)
+ '(dove pigeon dolphin cow)))))
+
+(ert-deftest hierarchy-leafs-includes-lonely-roots ()
+ (let ((parentfn (lambda (_) nil))
+ (hierarchy (hierarchy-new)))
+ (hierarchy-add-tree hierarchy 'foo parentfn)
+ (should (equal (hierarchy-leafs hierarchy)
+ '(foo)))))
+
+(ert-deftest hierarchy-leafs-of-node ()
+ (let ((animals (hierarchy-animals)))
+ (should (equal (hierarchy-leafs animals 'cow) '()))
+ (should (equal (hierarchy-leafs animals 'animal) '(dove pigeon dolphin cow)))
+ (should (equal (hierarchy-leafs animals 'bird) '(dove pigeon)))
+ (should (equal (hierarchy-leafs animals 'dove) '()))))
+
+(ert-deftest hierarchy-child-p ()
+ (let ((animals (hierarchy-animals)))
+ (should (hierarchy-child-p animals 'dove 'bird))
+ (should (hierarchy-child-p animals 'bird 'animal))
+ (should (hierarchy-child-p animals 'cow 'animal))
+ (should-not (hierarchy-child-p animals 'cow 'bird))
+ (should-not (hierarchy-child-p animals 'bird 'cow))
+ (should-not (hierarchy-child-p animals 'animal 'dove))
+ (should-not (hierarchy-child-p animals 'animal 'bird))))
+
+(ert-deftest hierarchy-descendant ()
+ (let ((animals (hierarchy-animals)))
+ (should (hierarchy-descendant-p animals 'dove 'animal))
+ (should (hierarchy-descendant-p animals 'dove 'bird))
+ (should (hierarchy-descendant-p animals 'bird 'animal))
+ (should (hierarchy-descendant-p animals 'cow 'animal))
+ (should-not (hierarchy-descendant-p animals 'cow 'bird))
+ (should-not (hierarchy-descendant-p animals 'bird 'cow))
+ (should-not (hierarchy-descendant-p animals 'animal 'dove))
+ (should-not (hierarchy-descendant-p animals 'animal 'bird))))
+
+(ert-deftest hierarchy-descendant-if-not-same ()
+ (let ((animals (hierarchy-animals)))
+ (should-not (hierarchy-descendant-p animals 'cow 'cow))
+ (should-not (hierarchy-descendant-p animals 'dove 'dove))
+ (should-not (hierarchy-descendant-p animals 'bird 'bird))
+ (should-not (hierarchy-descendant-p animals 'animal 'animal))))
+
+;; keywords supported: :test :key
+(ert-deftest hierarchy--set-equal ()
+ (should (hierarchy--set-equal '(1 2 3) '(1 2 3)))
+ (should (hierarchy--set-equal '(1 2 3) '(3 2 1)))
+ (should (hierarchy--set-equal '(3 2 1) '(1 2 3)))
+ (should-not (hierarchy--set-equal '(2 3) '(3 2 1)))
+ (should-not (hierarchy--set-equal '(1 2 3) '(2 3)))
+ (should-not (hierarchy--set-equal '("1" "2") '("2" "1") :test #'eq))
+ (should (hierarchy--set-equal '("1" "2") '("2" "1") :test #'equal))
+ (should-not (hierarchy--set-equal '(1 2) '(-1 -2)))
+ (should (hierarchy--set-equal '(1 2) '(-1 -2) :key #'abs))
+ (should-not (hierarchy--set-equal '(("1" 1) ("2" 1)) '(("1" 2) ("2" 2))))
+ (should-not (hierarchy--set-equal '(("1" 1) ("2" 1)) '(("1" 2) ("2" 2)) :key #'car))
+ (should-not (hierarchy--set-equal '(("1" 1) ("2" 1)) '(("1" 2) ("2" 2)) :test #'equal))
+ (should (hierarchy--set-equal '(("1" 1) ("2" 1)) '(("1" 2) ("2" 2)) :key #'car :test #'equal)))
+
+(ert-deftest hierarchy-equal-returns-true-for-same-hierarchy ()
+ (let ((animals (hierarchy-animals)))
+ (should (hierarchy-equal animals animals))
+ (should (hierarchy-equal (hierarchy-animals) animals))))
+
+(ert-deftest hierarchy-equal-returns-true-for-hierarchy-copies ()
+ (let ((animals (hierarchy-animals)))
+ (should (hierarchy-equal animals (hierarchy-copy animals)))))
+
+(ert-deftest hierarchy-map-item-on-leaf ()
+ (let* ((animals (hierarchy-animals))
+ (result (hierarchy-map-item (lambda (item indent) (cons item indent))
+ 'cow
+ animals)))
+ (should (equal result '((cow . 0))))))
+
+(ert-deftest hierarchy-map-item-on-leaf-with-indent ()
+ (let* ((animals (hierarchy-animals))
+ (result (hierarchy-map-item (lambda (item indent) (cons item indent))
+ 'cow
+ animals
+ 2)))
+ (should (equal result '((cow . 2))))))
+
+(ert-deftest hierarchy-map-item-on-parent ()
+ (let* ((animals (hierarchy-animals))
+ (result (hierarchy-map-item (lambda (item indent) (cons item indent))
+ 'bird
+ animals)))
+ (should (equal result '((bird . 0) (dove . 1) (pigeon . 1))))))
+
+(ert-deftest hierarchy-map-item-on-grand-parent ()
+ (let* ((animals (hierarchy-animals))
+ (result (hierarchy-map-item (lambda (item indent) (cons item indent))
+ 'animal
+ animals)))
+ (should (equal result '((animal . 0) (bird . 1) (dove . 2) (pigeon . 2)
+ (cow . 1) (dolphin . 1))))))
+
+(ert-deftest hierarchy-map-conses ()
+ (let* ((animals (hierarchy-animals))
+ (result (hierarchy-map (lambda (item indent)
+ (cons item indent))
+ animals)))
+ (should (equal result '((animal . 0)
+ (bird . 1)
+ (dove . 2)
+ (pigeon . 2)
+ (cow . 1)
+ (dolphin . 1))))))
+
+(ert-deftest hierarchy-map-tree ()
+ (let ((animals (hierarchy-animals)))
+ (should (equal (hierarchy-map-tree (lambda (item indent children)
+ (list item indent children))
+ animals)
+ '(animal
+ 0
+ ((bird 1 ((dove 2 nil) (pigeon 2 nil)))
+ (cow 1 nil)
+ (dolphin 1 nil)))))))
+
+(ert-deftest hierarchy-map-hierarchy-keeps-hierarchy ()
+ (let* ((animals (hierarchy-animals))
+ (result (hierarchy-map-hierarchy (lambda (item _) (identity item))
+ animals)))
+ (should (hierarchy-equal animals result))))
+
+(ert-deftest hierarchy-map-applies-function ()
+ (let* ((animals (hierarchy-animals))
+ (parentfn (lambda (item)
+ (cond
+ ((equal item "bird") "animal")
+ ((equal item "dove") "bird")
+ ((equal item "pigeon") "bird")
+ ((equal item "cow") "animal")
+ ((equal item "dolphin") "animal"))))
+ (expected (hierarchy-new)))
+ (hierarchy-add-tree expected "dove" parentfn)
+ (hierarchy-add-tree expected "pigeon" parentfn)
+ (hierarchy-add-tree expected "cow" parentfn)
+ (hierarchy-add-tree expected "dolphin" parentfn)
+ (should (hierarchy-equal
+ (hierarchy-map-hierarchy (lambda (item _) (symbol-name item)) animals)
+ expected))))
+
+(ert-deftest hierarchy-extract-tree ()
+ (let* ((animals (hierarchy-animals))
+ (birds (hierarchy-extract-tree animals 'bird)))
+ (hierarchy-sort birds)
+ (should (equal (hierarchy-roots birds) '(animal)))
+ (should (equal (hierarchy-children birds 'animal) '(bird)))
+ (should (equal (hierarchy-children birds 'bird) '(dove pigeon)))))
+
+(ert-deftest hierarchy-extract-tree-nil-if-not-in-hierarchy ()
+ (let* ((animals (hierarchy-animals)))
+ (should-not (hierarchy-extract-tree animals 'foobar))))
+
+(ert-deftest hierarchy-items-of-empty-hierarchy-is-empty ()
+ (should (seq-empty-p (hierarchy-items (hierarchy-new)))))
+
+(ert-deftest hierarchy-items-returns-sequence-of-same-length ()
+ (let* ((animals (hierarchy-animals))
+ (result (hierarchy-items animals)))
+ (should (= (seq-length result) (hierarchy-length animals)))))
+
+(ert-deftest hierarchy-items-return-all-elements-of-hierarchy ()
+ (let* ((animals (hierarchy-animals))
+ (result (hierarchy-items animals)))
+ (should (equal (seq-sort #'string< result) '(animal bird cow dolphin dove pigeon)))))
+
+(ert-deftest hierarchy-labelfn-indent-no-indent-if-0 ()
+ (let* ((labelfn-base (lambda (_item _indent) (insert "foo")))
+ (labelfn (hierarchy-labelfn-indent labelfn-base)))
+ (should (equal
+ (with-temp-buffer
+ (funcall labelfn "bar" 0)
+ (buffer-substring (point-min) (point-max)))
+ "foo"))))
+
+(ert-deftest hierarchy-labelfn-indent-three-times-if-3 ()
+ (let* ((labelfn-base (lambda (_item _indent) (insert "foo")))
+ (labelfn (hierarchy-labelfn-indent labelfn-base)))
+ (should (equal
+ (with-temp-buffer
+ (funcall labelfn "bar" 3)
+ (buffer-substring (point-min) (point-max)))
+ " foo"))))
+
+(ert-deftest hierarchy-labelfn-indent-default-indent-string ()
+ (let* ((labelfn-base (lambda (_item _indent) (insert "foo")))
+ (labelfn (hierarchy-labelfn-indent labelfn-base)))
+ (should (equal
+ (with-temp-buffer
+ (funcall labelfn "bar" 1)
+ (buffer-substring (point-min) (point-max)))
+ " foo"))))
+
+(ert-deftest hierarchy-labelfn-indent-custom-indent-string ()
+ (let* ((labelfn-base (lambda (_item _indent) (insert "foo")))
+ (labelfn (hierarchy-labelfn-indent labelfn-base "###"))
+ (content (with-temp-buffer
+ (funcall labelfn "bar" 1)
+ (buffer-substring (point-min) (point-max)))))
+ (should (equal content "###foo"))))
+
+(ert-deftest hierarchy-labelfn-button-propertize ()
+ (let* ((labelfn-base (lambda (_item _indent) (insert "foo")))
+ (actionfn #'identity)
+ (labelfn (hierarchy-labelfn-button labelfn-base actionfn))
+ (properties (with-temp-buffer
+ (funcall labelfn "bar" 1)
+ (text-properties-at 1))))
+ (should (equal (car properties) 'action))))
+
+(ert-deftest hierarchy-labelfn-button-execute-labelfn ()
+ (let* ((labelfn-base (lambda (_item _indent) (insert "foo")))
+ (actionfn #'identity)
+ (labelfn (hierarchy-labelfn-button labelfn-base actionfn))
+ (content (with-temp-buffer
+ (funcall labelfn "bar" 1)
+ (buffer-substring-no-properties (point-min) (point-max)))))
+ (should (equal content "foo"))))
+
+(ert-deftest hierarchy-labelfn-button-if-does-not-button-unless-condition ()
+ (let ((labelfn-base (lambda (_item _indent) (insert "foo")))
+ (spy-count 0)
+ (condition (lambda (_item _indent) nil)))
+ (cl-letf (((symbol-function 'hierarchy-labelfn-button) (lambda (_labelfn _actionfn) (lambda (_item _indent) (cl-incf spy-count)))))
+ (funcall (hierarchy-labelfn-button-if labelfn-base condition #'identity) nil nil)
+ (should (equal spy-count 0)))))
+
+(ert-deftest hierarchy-labelfn-button-if-does-button-when-condition ()
+ (let ((labelfn-base (lambda (_item _indent) (insert "foo")))
+ (spy-count 0)
+ (condition (lambda (_item _indent) t)))
+ (cl-letf (((symbol-function 'hierarchy-labelfn-button) (lambda (_labelfn _actionfn) (lambda (_item _indent) (cl-incf spy-count)))))
+ (funcall (hierarchy-labelfn-button-if labelfn-base condition #'identity) nil nil)
+ (should (equal spy-count 1)))))
+
+(ert-deftest hierarchy-labelfn-to-string ()
+ (let ((labelfn (lambda (item _indent) (insert item))))
+ (should (equal (hierarchy-labelfn-to-string labelfn "foo" 1) "foo"))))
+
+(ert-deftest hierarchy-print ()
+ (let* ((animals (hierarchy-animals))
+ (result (with-temp-buffer
+ (hierarchy-print animals)
+ (buffer-substring-no-properties (point-min) (point-max)))))
+ (should (equal result "animal\n bird\n dove\n pigeon\n cow\n dolphin\n"))))
+
+(ert-deftest hierarchy-to-string ()
+ (let* ((animals (hierarchy-animals))
+ (result (hierarchy-to-string animals)))
+ (should (equal result "animal\n bird\n dove\n pigeon\n cow\n dolphin\n"))))
+
+(ert-deftest hierarchy-tabulated-display ()
+ (let* ((animals (hierarchy-animals))
+ (labelfn (lambda (item _indent) (insert (symbol-name item))))
+ (contents (with-temp-buffer
+ (hierarchy-tabulated-display animals labelfn (current-buffer))
+ (buffer-substring-no-properties (point-min) (point-max)))))
+ (should (equal contents "animal\nbird\ndove\npigeon\ncow\ndolphin\n"))))
+
+(ert-deftest hierarchy-sort-non-root-nodes ()
+ (let* ((animals (hierarchy-animals)))
+ (should (equal (hierarchy-roots animals) '(animal)))
+ (should (equal (hierarchy-children animals 'animal) '(bird cow dolphin)))
+ (should (equal (hierarchy-children animals 'bird) '(dove pigeon)))))
+
+(ert-deftest hierarchy-sort-roots ()
+ (let* ((organisms (hierarchy-new))
+ (parentfn (lambda (item)
+ (cl-case item
+ (oak 'plant)
+ (bird 'animal)))))
+ (hierarchy-add-tree organisms 'oak parentfn)
+ (hierarchy-add-tree organisms 'bird parentfn)
+ (hierarchy-sort organisms)
+ (should (equal (hierarchy-roots organisms) '(animal plant)))))
+
+(provide 'hierarchy-tests)
+;;; hierarchy-tests.el ends here
diff --git a/test/lisp/emacs-lisp/lisp-mode-tests.el b/test/lisp/emacs-lisp/lisp-mode-tests.el
index 12d7aafb605..85db3a00c8e 100644
--- a/test/lisp/emacs-lisp/lisp-mode-tests.el
+++ b/test/lisp/emacs-lisp/lisp-mode-tests.el
@@ -153,7 +153,7 @@ noindent\" 3
(should (equal (buffer-string) str)))))
(ert-deftest indent-sexp-stop-before-eol-non-lisp ()
- "`indent-sexp' shouldn't be too agressive in non-Lisp modes."
+ "`indent-sexp' shouldn't be too aggressive in non-Lisp modes."
;; See https://debbugs.gnu.org/35286#13.
(with-temp-buffer
(prolog-mode)
@@ -294,6 +294,18 @@ Expected initialization file: `%s'\"
(insert "\"\n")
(lisp-indent-region (point-min) (point-max))))
+(ert-deftest lisp-indent-defun ()
+ (with-temp-buffer
+ (lisp-mode)
+ (let ((orig "(defun x ()
+ (print (quote ( thingy great
+ stuff)))
+ (print (quote (thingy great
+ stuff))))"))
+ (insert orig)
+ (indent-region (point-min) (point-max))
+ (should (equal (buffer-string) orig)))))
+
;;; Fontification
diff --git a/test/lisp/emacs-lisp/lisp-tests.el b/test/lisp/emacs-lisp/lisp-tests.el
index 2ff8310cbfb..fd07011137a 100644
--- a/test/lisp/emacs-lisp/lisp-tests.el
+++ b/test/lisp/emacs-lisp/lisp-tests.el
@@ -136,8 +136,7 @@
(text-mode)
(insert "\"foo\"")
(goto-char (point-min))
- (delete-pair)
- (should (string-equal "fo\"" (buffer-string)))))
+ (should-error (delete-pair))))
(ert-deftest lisp-delete-pair-quotes-text-mode-syntax-table ()
"Test \\[delete-pair] with modified Text Mode syntax for #15014."
@@ -296,7 +295,7 @@
(lambda () (up-list 1 t t))
(or "(1 '2 ( 2' 1 '2 ) 2' 1)")
;; abcdefghijklmnopqrstuvwxy
- i k x scan-error)
+ i k x user-error)
(define-lisp-up-list-test backward-up-list-basic
(lambda () (backward-up-list))
@@ -367,6 +366,61 @@ start."
"
"Test buffer for `mark-defun'."))
+;;; end-of-defun
+
+(ert-deftest end-of-defun-twice ()
+ "Test behavior of prefix arg for `end-of-defun' (Bug#24427).
+Calling `end-of-defun' twice should be the same as a prefix arg
+of two."
+ (setq last-command nil)
+ (cl-flet ((eod2 (lambda ()
+ (goto-char (point-min))
+ (end-of-defun)
+ (end-of-defun)
+ (let ((pt-eod2 (point)))
+ (goto-char (point-min))
+ (end-of-defun 2)
+ (should (= (point) pt-eod2))))))
+ (with-temp-buffer
+ (insert "\
+\(defun a ())
+
+\(defun b ())
+
+\(defun c ())")
+ (eod2))
+ (with-temp-buffer
+ (insert "\
+\(defun a ())
+\(defun b ())
+\(defun c ())")
+ (eod2)))
+ (elisp-tests-with-temp-buffer ";; Comment header
+
+\(defun func-1 (arg)
+ \"docstring\"
+ body)
+=!p1=
+;; Comment before a defun
+\(defun func-2 (arg)
+ \"docstring\"
+ body)
+
+\(defun func-3 (arg)
+ \"docstring\"
+ body)
+=!p2=(defun func-4 (arg)
+ \"docstring\"
+ body)
+
+;; end
+"
+ (goto-char p1)
+ (end-of-defun 2)
+ (should (= (point) p2))))
+
+;;; mark-defun
+
(ert-deftest mark-defun-no-arg-region-inactive ()
"Test `mark-defun' with no prefix argument and inactive
region."
diff --git a/test/lisp/emacs-lisp/map-tests.el b/test/lisp/emacs-lisp/map-tests.el
index fe59eb6a809..9a2cd42a211 100644
--- a/test/lisp/emacs-lisp/map-tests.el
+++ b/test/lisp/emacs-lisp/map-tests.el
@@ -376,5 +376,11 @@ Evaluate BODY for each created map.
'((1 . 1) (2 . 5) (3 . 0)))
'((3 . 0) (2 . 9) (1 . 6)))))
+(ert-deftest test-map-plist-pcase ()
+ (let ((plist '(:one 1 :two 2)))
+ (should (equal (pcase-let (((map :one (:two two)) plist))
+ (list one two))
+ '(1 2)))))
+
(provide 'map-tests)
;;; map-tests.el ends here
diff --git a/test/lisp/emacs-lisp/memory-report-tests.el b/test/lisp/emacs-lisp/memory-report-tests.el
new file mode 100644
index 00000000000..da5f4f5700f
--- /dev/null
+++ b/test/lisp/emacs-lisp/memory-report-tests.el
@@ -0,0 +1,57 @@
+;;; memory-report-tests.el --- tests for memory-report.el -*- lexical-binding: t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+(require 'ert)
+(require 'memory-report)
+
+(defun setup-memory-report-tests ()
+ ;; Set the sizes on things based on a 64-bit architecture. (We're
+ ;; hard-coding this to be able to write simple tests that'll work on
+ ;; all architectures.)
+ (memory-report--set-size
+ '((conses 16 499173 99889)
+ (symbols 48 22244 3)
+ (strings 32 92719 4559)
+ (string-bytes 1 40402011)
+ (vectors 16 31919)
+ (vector-slots 8 385148 149240)
+ (floats 8 434 4519)
+ (intervals 56 24499 997)
+ (buffers 984 33))))
+
+(ert-deftest memory-report-sizes ()
+ (setup-memory-report-tests)
+ (should (equal (memory-report-object-size (cons nil nil)) 16))
+ (should (equal (memory-report-object-size (cons 1 2)) 16))
+
+ (should (equal (memory-report-object-size (list 1 2)) 32))
+ (should (equal (memory-report-object-size (list 1)) 16))
+
+ (should (equal (memory-report-object-size (list 'foo)) 16))
+
+ (should (equal (memory-report-object-size (vector 1 2 3 4)) 80))
+
+ (should (equal (memory-report-object-size "") 32))
+ (should (equal (memory-report-object-size "a") 33))
+ (should (equal (memory-report-object-size (propertize "a" 'face 'foo))
+ 81)))
+
+(provide 'memory-report-tests)
+
+;;; memory-report-tests.el ends here
diff --git a/test/lisp/emacs-lisp/nadvice-tests.el b/test/lisp/emacs-lisp/nadvice-tests.el
index afd2e2e380d..358d9025ad5 100644
--- a/test/lisp/emacs-lisp/nadvice-tests.el
+++ b/test/lisp/emacs-lisp/nadvice-tests.el
@@ -1,4 +1,4 @@
-;;; advice-tests.el --- Test suite for the new advice thingy.
+;;; nadvice-tests.el --- Test suite for the new advice thingy. -*- lexical-binding:t -*-
;; Copyright (C) 2012-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/emacs-lisp/package-resources/key.pub b/test/lisp/emacs-lisp/package-resources/key.pub
index a326d34e54f..5e2ebc55d35 100644
--- a/test/lisp/emacs-lisp/package-resources/key.pub
+++ b/test/lisp/emacs-lisp/package-resources/key.pub
@@ -1,18 +1,20 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
-Version: GnuPG v1.4.14 (GNU/Linux)
-mQENBFJNB8gBCACfbtpvYrM8V1HM0KFlIwatcEJugHqwOHpr/Z9mrCW0fxyQAW/d
-2L+3QVNsN9Tz/K9lLcBUgeR7rhVEzHNqhmhNj/HnikwGqXbIofhp+QbZmBKnAlCz
-d77kg8K9lozHtfTkm1gX/7DdPzQKmgi7WOzzi2395wGubeqJLvYaEcqVbI0Eob+E
-3CzRjNy/e/Tf3TJRW5etTcdZN6LVuIY7tNCHqlQZTwyycON/hfLTX6cLCnzDsqm/
-NxCuwn9aqP9aGRGfIu7Y+If3zTymvrXEPUN98OEID814bOKdx0uVTZRiSMbvuTGI
-8uMa/kpGX/78rqI61gbZV51RFoU7pT2tzwY/ABEBAAG0HkouIFIuIEhhY2tlciA8
-anJoQGV4YW1wbGUuY29tPokBOAQTAQIAIgUCUk0HyAIbAwYLCQgHAwIGFQgCCQoL
-BBYCAwECHgECF4AACgkQtpVAhgkYletuhQf+JAyHYhTZNxjq0UYlikuLX8EtYbXX
-PB+03J0B73SMzEai5XsiTU2ADxqxwr7pveVK1INf+IGLiiXBlQq+4DSOvQY4xLfp
-58jTOYRV1ECvlXK/JtvVOwufXREADaydf9l/MUxA5G2PPBWIuQknh3ysPSsx68OJ
-SzNHFwklLn0DKc4WloE/GLDpTzimnCg7QGzuUo3Iilpjdy8EvTdI5d3jx/mGJIwI
-goB+YZgyxSPM+GjDwh5DEwD7OexNqqa7RynnmU0epmlYyi9UufCHLwgiiEIzjpWi
-6+iF+CQ45ZAKncovByenIUv73J3ImOudrsskeAHBmahljv1he6uV9Egj2Q==
-=b5Kg
+mI0EX48EbAEEANrsWXyZ4MRZRjVbLAh5jX/+1+31oB/aJ/q/5DkH1qUHJf0La9LC
+sykUSM3H2u5VWLytX/ozrxIRYX13GR2xBxyJlUkDWB209AAVLFrjSp1yUX/Sb5SU
+Kb7p421ZAeHiOxfnLRuErFZkTfzY19mUCyw4cdamw430V3mUC9uns/d9ABEBAAG0
+LUouIFJhbmRvbSBIYWNrZXIgKFRFU1QgS0VZKSA8anJoQGV4YW1wbGUub3JnPojO
+BBMBCgA4FiEEHP310DrP36xrZ1kSMKdkJgeTYhoFAl+PBGwCGwMFCwkIBwIGFQoJ
+CAsCBBYCAwECHgECF4AACgkQMKdkJgeTYhq9MQP7BYkCk8r5G777Ilp8kWjsEIo3
+aDX9jORiNfMAGys/aLjjEajHFAlTQKfSLm/VXLDYtK28c8ACjThQagaDF46MRWqQ
+rFFiH4IAZRgj2ELj+/j1ljQZjGjKR2Yx4BCDhbumz8zeMSPL6yFT5+8LOMUAtdv4
+lEPWXW0AycylbdbE7024jQRfjwRsAQQApjTw9kONmSVouCi8ZIQwwYiA9tLzbSZv
+CYxbJ6KH0icRhBLfdb1hL/Kn8x3k+xll9A0c/ABVkMxRcbQkY98xsFck7E2GcvnC
+sY+w/NdcUUZJYMB3l2MH5ojCbOk5jSAZzxzeFcJhNAhmLqomMHg2LI6KDVey6iYU
+FxyIpIQ3SlkAEQEAAYi2BBgBCgAgFiEEHP310DrP36xrZ1kSMKdkJgeTYhoFAl+P
+BGwCGwwACgkQMKdkJgeTYhrtywQAhoCR/skBSQWWBI10N0qhtdlNxbpvK8ErSPKw
+wS74Pq407Zv0VD9ual/HC3Uet2z8LeG9ZwU4Jd23g96fmJt7AM9CQWrOhC242JYr
+YSqWxANyek8otsvppJNHtt2Stmknv7XbJFFB1JDC8WKo8lVo9/MkmzROxuEFEvOU
+Yn923VI=
+=NRtx
-----END PGP PUBLIC KEY BLOCK-----
diff --git a/test/lisp/emacs-lisp/package-resources/key.sec b/test/lisp/emacs-lisp/package-resources/key.sec
index d21e6ae9a45..dbc80f43cb7 100644
--- a/test/lisp/emacs-lisp/package-resources/key.sec
+++ b/test/lisp/emacs-lisp/package-resources/key.sec
@@ -1,33 +1,35 @@
-----BEGIN PGP PRIVATE KEY BLOCK-----
-Version: GnuPG v1.4.14 (GNU/Linux)
-lQO+BFJNB8gBCACfbtpvYrM8V1HM0KFlIwatcEJugHqwOHpr/Z9mrCW0fxyQAW/d
-2L+3QVNsN9Tz/K9lLcBUgeR7rhVEzHNqhmhNj/HnikwGqXbIofhp+QbZmBKnAlCz
-d77kg8K9lozHtfTkm1gX/7DdPzQKmgi7WOzzi2395wGubeqJLvYaEcqVbI0Eob+E
-3CzRjNy/e/Tf3TJRW5etTcdZN6LVuIY7tNCHqlQZTwyycON/hfLTX6cLCnzDsqm/
-NxCuwn9aqP9aGRGfIu7Y+If3zTymvrXEPUN98OEID814bOKdx0uVTZRiSMbvuTGI
-8uMa/kpGX/78rqI61gbZV51RFoU7pT2tzwY/ABEBAAH+AwMCKCCpPNXkXuVgF7cz
-eByuvgIO7wImDYGOdJqsASSzV4q0u1acnGtlxg7WphKDF9RnC5+1ZZ1ZcrBcv2uJ
-xZm2jHdjqM3FmgQTN70GVzO1nKEur2wxlKotG4Q+8BtaRDwHdKpQFk+QW9aInH3C
-BkNWTK97iFwZaoUGxKuRJb35qjMe3SsDE7kdbtOqO+tOeppRVeOOZCn7F33ir/6i
-j2gmIME6LFDzvBi6YAyMBSh90Ak70HJINt0QfXlZf5MtX1NaxaEcnsRmwwcNqxh9
-JvcC9q4WrR92NhHCHI+lOsAe7hbwo/VkwRjSSx0HdKkx6kvdcNj/9LeX/jykzLvg
-kEqvAqT4Jmk57W2seqvpNcAO+eUVrJ5D1OR6khsUtikPp2pQH5MDXJDGcie+ZAFb
-w6BwoWBDBjooKtfuP0LKqrdtJG2JLe6yhBhWvfqHPBlUU1SsA7a5aTCLo8FiqgEI
-Kyy60zMx/2Mi48oN1a/mAoV1MTWLhOVUWJlIHM7nVLj1OaX0316LcLX/uTLTq40p
-apHKwERanzY7f8ROiv/Fa/J+9cCsfOLKfjFAjpBVUVoOb39HsyS/vvkGMY4kgaD6
-K6r9JPdsaoYvsLkxk5HyHF7Mk2uS1z1EIArD2/3lRiX6ag+IU1Nl3XDkgfZj06K3
-juS84dGF8CmN49uOEjzAJAQZH9jTs5OKzUuZhGJF+gt0L78vLOoKRr8bu1N1GPqU
-wnS908HWruXzjJl1CAhnuCa8FnDaU+tmEKjYpWuelx85kolpMW7LT5gOFZr84MIj
-Kq3Rt2hU6qQ7Cdy1ep531YKkmyh9Y4l/Tgir1OtnQQqtNuwHI497l7qAUnKZBBHZ
-guApjS9BoHsRXkw2mgDssZ+khOwj/xJm876nFSiQeCD0aIbU/4zJ9e2HUOJAZI1r
-d7QeSi4gUi4gSGFja2VyIDxqcmhAZXhhbXBsZS5jb20+iQE4BBMBAgAiBQJSTQfI
-AhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRC2lUCGCRiV626FB/4kDIdi
-FNk3GOrRRiWKS4tfwS1htdc8H7TcnQHvdIzMRqLleyJNTYAPGrHCvum95UrUg1/4
-gYuKJcGVCr7gNI69BjjEt+nnyNM5hFXUQK+Vcr8m29U7C59dEQANrJ1/2X8xTEDk
-bY88FYi5CSeHfKw9KzHrw4lLM0cXCSUufQMpzhaWgT8YsOlPOKacKDtAbO5SjciK
-WmN3LwS9N0jl3ePH+YYkjAiCgH5hmDLFI8z4aMPCHkMTAPs57E2qprtHKeeZTR6m
-aVjKL1S58IcvCCKIQjOOlaLr6IX4JDjlkAqdyi8HJ6chS/vcnciY652uyyR4AcGZ
-qGWO/WF7q5X0SCPZ
-=5FZK
+lQIGBF+PBGwBBADa7Fl8meDEWUY1WywIeY1//tft9aAf2if6v+Q5B9alByX9C2vS
+wrMpFEjNx9ruVVi8rV/6M68SEWF9dxkdsQcciZVJA1gdtPQAFSxa40qdclF/0m+U
+lCm+6eNtWQHh4jsX5y0bhKxWZE382NfZlAssOHHWpsON9Fd5lAvbp7P3fQARAQAB
+/gcDAngNw4ppSPBe/w734cz++xNEv0TDgwxGBWp2wGSwWao04Nl1U4LkjiIy+dkc
+uUPwEZMvxXwMcq10PPH26ifP8Xfi/zANXUoLJ0DsG6rtE3BcSC9MPFe3EJENtcIP
+a0jFLsbi72aBzolNEDCZCv93znXFPekaXw/RAeeFLJz8GR2Sx6bHbTJKklXgWPHw
+C5Dw6xr/kEZktgjlhjkx280STpLGaFO4jiiGZ4Obp5ePp7kyOzDUzaimdZgJwClT
+VbZDNQMTzgQrBOP8doXlo9euW4Wo1IYBIOwgeYieM3ZA9YjJAmp4lFnk/KFYt0Ak
+0H9IWzDU8VERcU4B04PSXahzvB1Ii7C7bbHxPyuu6sAfMK8DRkrGjwgAlrhuWNLX
+M07acT/E9Pm+mBlDcdkyKB2LfwgaVb9F3C25sfcFSvc5p+sqgZp1Zx7Qg9pOhQjw
+U7Ln+96c0bUl+iQKdm3TGjOXAFUHYXbRkx2cJ4gxnMVNj0D68xBtBSm0LUouIFJh
+bmRvbSBIYWNrZXIgKFRFU1QgS0VZKSA8anJoQGV4YW1wbGUub3JnPojOBBMBCgA4
+FiEEHP310DrP36xrZ1kSMKdkJgeTYhoFAl+PBGwCGwMFCwkIBwIGFQoJCAsCBBYC
+AwECHgECF4AACgkQMKdkJgeTYhq9MQP7BYkCk8r5G777Ilp8kWjsEIo3aDX9jORi
+NfMAGys/aLjjEajHFAlTQKfSLm/VXLDYtK28c8ACjThQagaDF46MRWqQrFFiH4IA
+ZRgj2ELj+/j1ljQZjGjKR2Yx4BCDhbumz8zeMSPL6yFT5+8LOMUAtdv4lEPWXW0A
+ycylbdbE702dAgYEX48EbAEEAKY08PZDjZklaLgovGSEMMGIgPbS820mbwmMWyei
+h9InEYQS33W9YS/yp/Md5PsZZfQNHPwAVZDMUXG0JGPfMbBXJOxNhnL5wrGPsPzX
+XFFGSWDAd5djB+aIwmzpOY0gGc8c3hXCYTQIZi6qJjB4NiyOig1XsuomFBcciKSE
+N0pZABEBAAH+BwMCXeUOBwcOsxb/AY6rnHmgACNTGwIa5vgelw0qfET0ms/YzVrN
+ufikyV9dEWVxJyuTKav978wanPu7VcCh0pTjL2nTm2nZWyRJN4gb3UIC0MA1xfB2
+yPLTCmsGeJhVOqi4Af/r06mk+NOQ96ivOA2CJuw1LSpcUtuYxB5t/grGyEojYjRP
+s0Htvf2bfN9KbFJ26DGsfYzC8bCxm9szPFHBQjw4NboCigUSAHmkoTW01aWZU9Vq
+brY4cWhdmCqHgfmsQgzP3LfaAQ6kJ/bkuKef7z57lz5XmlyjMQGWcZWp5xf2n81p
+BV6unaIPyavzkKVAXizVfNiHNJgK9PoVoEOJkPLjRfMxVmFSGN/oF7lVTRWfOIwo
+68rtNPhr6UzE4ArGHYv/pK3kijUp5daWmfrySWPcwoVAaR3mIIVs/1rhd9aZrwn6
+Q07Yo5u11rH9b8anZQF3BdTcrnU9pUzLYlFPnfhtyGqhikQILtPTf0iwr8hpG9b2
+Zoi2BBgBCgAgFiEEHP310DrP36xrZ1kSMKdkJgeTYhoFAl+PBGwCGwwACgkQMKdk
+JgeTYhrtywQAhoCR/skBSQWWBI10N0qhtdlNxbpvK8ErSPKwwS74Pq407Zv0VD9u
+al/HC3Uet2z8LeG9ZwU4Jd23g96fmJt7AM9CQWrOhC242JYrYSqWxANyek8otsvp
+pJNHtt2Stmknv7XbJFFB1JDC8WKo8lVo9/MkmzROxuEFEvOUYn923VI=
+=2DW8
-----END PGP PRIVATE KEY BLOCK-----
diff --git a/test/lisp/emacs-lisp/package-resources/newer-versions/new-pkg-1.0.el b/test/lisp/emacs-lisp/package-resources/newer-versions/new-pkg-1.0.el
index 7251622fa59..61c1b045990 100644
--- a/test/lisp/emacs-lisp/package-resources/newer-versions/new-pkg-1.0.el
+++ b/test/lisp/emacs-lisp/package-resources/newer-versions/new-pkg-1.0.el
@@ -1,4 +1,4 @@
-;;; new-pkg.el --- A package only seen after "updating" archive-contents
+;;; new-pkg.el --- A package only seen after "updating" archive-contents -*- lexical-binding:t -*-
;; Author: J. R. Hacker <jrh@example.com>
;; Version: 1.0
diff --git a/test/lisp/emacs-lisp/package-resources/newer-versions/simple-single-1.4.el b/test/lisp/emacs-lisp/package-resources/newer-versions/simple-single-1.4.el
index 7b1c00c06db..301993deb30 100644
--- a/test/lisp/emacs-lisp/package-resources/newer-versions/simple-single-1.4.el
+++ b/test/lisp/emacs-lisp/package-resources/newer-versions/simple-single-1.4.el
@@ -1,4 +1,4 @@
-;;; simple-single.el --- A single-file package with no dependencies
+;;; simple-single.el --- A single-file package with no dependencies -*- lexical-binding:t -*-
;; Author: J. R. Hacker <jrh@example.com>
;; Version: 1.4
diff --git a/test/lisp/emacs-lisp/package-resources/signed/archive-contents.sig b/test/lisp/emacs-lisp/package-resources/signed/archive-contents.sig
index 658edd3f60e..dac168b0e4c 100644
--- a/test/lisp/emacs-lisp/package-resources/signed/archive-contents.sig
+++ b/test/lisp/emacs-lisp/package-resources/signed/archive-contents.sig
Binary files differ
diff --git a/test/lisp/emacs-lisp/package-resources/signed/signed-bad-1.0.el b/test/lisp/emacs-lisp/package-resources/signed/signed-bad-1.0.el
index 3734823876e..ff070c6526f 100644
--- a/test/lisp/emacs-lisp/package-resources/signed/signed-bad-1.0.el
+++ b/test/lisp/emacs-lisp/package-resources/signed/signed-bad-1.0.el
@@ -1,4 +1,4 @@
-;;; signed-bad.el --- A single-file package with bad signature
+;;; signed-bad.el --- A single-file package with bad signature -*- lexical-binding: t -*-
;; Author: J. R. Hacker <jrh@example.com>
;; Version: 1.0
diff --git a/test/lisp/emacs-lisp/package-resources/signed/signed-good-1.0.el b/test/lisp/emacs-lisp/package-resources/signed/signed-good-1.0.el
index 22718df2763..60b1b8663d9 100644
--- a/test/lisp/emacs-lisp/package-resources/signed/signed-good-1.0.el
+++ b/test/lisp/emacs-lisp/package-resources/signed/signed-good-1.0.el
@@ -1,4 +1,4 @@
-;;; signed-good.el --- A single-file package with good signature
+;;; signed-good.el --- A single-file package with good signature -*- lexical-binding: t -*-
;; Author: J. R. Hacker <jrh@example.com>
;; Version: 1.0
diff --git a/test/lisp/emacs-lisp/package-resources/signed/signed-good-1.0.el.sig b/test/lisp/emacs-lisp/package-resources/signed/signed-good-1.0.el.sig
index 747918794ca..5b1c721e32a 100644
--- a/test/lisp/emacs-lisp/package-resources/signed/signed-good-1.0.el.sig
+++ b/test/lisp/emacs-lisp/package-resources/signed/signed-good-1.0.el.sig
Binary files differ
diff --git a/test/lisp/emacs-lisp/package-resources/signed/update-signatures.sh b/test/lisp/emacs-lisp/package-resources/signed/update-signatures.sh
new file mode 100755
index 00000000000..ca16f8b27a1
--- /dev/null
+++ b/test/lisp/emacs-lisp/package-resources/signed/update-signatures.sh
@@ -0,0 +1,32 @@
+#! /bin/sh
+
+# Generate a new key and update the signatures for tests.
+
+# Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+export GPG_AGENT=""
+KEYRING="./key.ring"
+TRUSTDB="./trust.db"
+GPG="gpg --no-default-keyring --trustdb-name $TRUSTDB --keyring $KEYRING --yes"
+
+rm $KEYRING
+$GPG --full-generate-key
+$GPG --export --armor > "../key.pub"
+$GPG --export-secret-keys -armor > "../key.sec"
+$GPG --detach-sign --sign "./archive-contents"
+$GPG --detach-sign --sign "./signed-good-1.0.el"
diff --git a/test/lisp/emacs-lisp/package-resources/simple-depend-1.0.el b/test/lisp/emacs-lisp/package-resources/simple-depend-1.0.el
index b58b658d024..cb003905bb5 100644
--- a/test/lisp/emacs-lisp/package-resources/simple-depend-1.0.el
+++ b/test/lisp/emacs-lisp/package-resources/simple-depend-1.0.el
@@ -1,4 +1,4 @@
-;;; simple-depend.el --- A single-file package with a dependency.
+;;; simple-depend.el --- A single-file package with a dependency. -*- lexical-binding:t -*-
;; Author: J. R. Hacker <jrh@example.com>
;; Version: 1.0
diff --git a/test/lisp/emacs-lisp/package-resources/simple-single-1.3.el b/test/lisp/emacs-lisp/package-resources/simple-single-1.3.el
index 6756a28080b..9c3f427ff48 100644
--- a/test/lisp/emacs-lisp/package-resources/simple-single-1.3.el
+++ b/test/lisp/emacs-lisp/package-resources/simple-single-1.3.el
@@ -1,4 +1,4 @@
-;;; simple-single.el --- A single-file package with no dependencies
+;;; simple-single.el --- A single-file package with no dependencies -*- lexical-binding:t -*-
;; Author: J. R. Hacker <jrh@example.com>
;; Version: 1.3
diff --git a/test/lisp/emacs-lisp/package-resources/simple-two-depend-1.1.el b/test/lisp/emacs-lisp/package-resources/simple-two-depend-1.1.el
index 9cfe5c0d4e2..a0a9607350a 100644
--- a/test/lisp/emacs-lisp/package-resources/simple-two-depend-1.1.el
+++ b/test/lisp/emacs-lisp/package-resources/simple-two-depend-1.1.el
@@ -1,4 +1,4 @@
-;;; simple-two-depend.el --- A single-file package with two dependencies.
+;;; simple-two-depend.el --- A single-file package with two dependencies. -*- lexical-binding:t -*-
;; Author: J. R. Hacker <jrh@example.com>
;; Version: 1.1
diff --git a/test/lisp/emacs-lisp/package-tests.el b/test/lisp/emacs-lisp/package-tests.el
index 362f79f6863..67d647d3b9e 100644
--- a/test/lisp/emacs-lisp/package-tests.el
+++ b/test/lisp/emacs-lisp/package-tests.el
@@ -1,4 +1,4 @@
-;;; package-test.el --- Tests for the Emacs package system
+;;; package-tests.el --- Tests for the Emacs package system -*- lexical-binding:t -*-
;; Copyright (C) 2013-2021 Free Software Foundation, Inc.
@@ -39,6 +39,7 @@
(require 'package)
(require 'ert)
+(require 'ert-x)
(require 'cl-lib)
(setq package-menu-async nil)
@@ -102,13 +103,9 @@
(multi-file (0 1))))
"`package-desc' used for testing dependencies.")
-(defvar package-test-data-dir (expand-file-name "package-resources" package-test-file-dir)
+(defvar package-test-data-dir (ert-resource-directory)
"Base directory of package test files.")
-(defvar package-test-fake-contents-file
- (expand-file-name "archive-contents" package-test-data-dir)
- "Path to a static copy of \"archive-contents\".")
-
(cl-defmacro with-package-test ((&optional &key file
basedir
install
@@ -143,8 +140,8 @@
,(if basedir `(cd ,basedir))
(unless (file-directory-p package-user-dir)
(mkdir package-user-dir))
- (cl-letf (((symbol-function 'yes-or-no-p) (lambda (&rest r) t))
- ((symbol-function 'y-or-n-p) (lambda (&rest r) t)))
+ (cl-letf (((symbol-function 'yes-or-no-p) (lambda (&rest _) t))
+ ((symbol-function 'y-or-n-p) (lambda (&rest _) t)))
,@(when install
`((package-initialize)
(package-refresh-contents)
@@ -154,6 +151,15 @@
`(insert-file-contents ,file))
,@body)))
+ (when ,upload-base
+ (dolist (f '("archive-contents"
+ "simple-single-1.3.el"
+ "simple-single-1.4.el"
+ "simple-single-readme.txt"))
+ (ignore-errors
+ (delete-file
+ (expand-file-name f package-test-archive-upload-base))))
+ (delete-directory package-test-archive-upload-base))
(when (file-directory-p package-test-user-dir)
(delete-directory package-test-user-dir t))
@@ -175,9 +181,8 @@
(defun package-test-suffix-matches (base suffix-list)
"Return file names matching BASE concatenated with each item in SUFFIX-LIST"
- (cl-mapcan
- '(lambda (item) (file-expand-wildcards (concat base item)))
- suffix-list))
+ (mapcan (lambda (item) (file-expand-wildcards (concat base item)))
+ suffix-list))
(defvar tar-parse-info)
(declare-function tar-header-name "tar-mode" (cl-x) t) ; defstruct
@@ -216,20 +221,20 @@ Must called from within a `tar-mode' buffer."
(ert-deftest package-test-desc-from-buffer ()
"Parse an elisp buffer to get a `package-desc' object."
- (with-package-test (:basedir "package-resources" :file "simple-single-1.3.el")
+ (with-package-test (:basedir (ert-resource-directory) :file "simple-single-1.3.el")
(should (package-test--compatible-p
(package-buffer-info) simple-single-desc 'kind)))
- (with-package-test (:basedir "package-resources" :file "simple-depend-1.0.el")
+ (with-package-test (:basedir (ert-resource-directory) :file "simple-depend-1.0.el")
(should (package-test--compatible-p
(package-buffer-info) simple-depend-desc 'kind)))
- (with-package-test (:basedir "package-resources"
+ (with-package-test (:basedir (ert-resource-directory)
:file "multi-file-0.2.3.tar")
(tar-mode)
(should (equal (package-tar-file-info) multi-file-desc))))
(ert-deftest package-test-install-single ()
"Install a single file without using an archive."
- (with-package-test (:basedir "package-resources" :file "simple-single-1.3.el")
+ (with-package-test (:basedir (ert-resource-directory) :file "simple-single-1.3.el")
(should (package-install-from-buffer))
(package-initialize)
(should (package-installed-p 'simple-single))
@@ -272,7 +277,7 @@ Must called from within a `tar-mode' buffer."
(ert-deftest package-test-macro-compilation ()
"Install a package which includes a dependency."
- (with-package-test (:basedir "package-resources")
+ (with-package-test (:basedir (ert-resource-directory))
(package-install-file (expand-file-name "macro-problem-package-1.0/"))
(require 'macro-problem)
;; `macro-problem-func' uses a macro from `macro-aux'.
@@ -311,8 +316,7 @@ Must called from within a `tar-mode' buffer."
(ert-deftest package-test-install-prioritized ()
"Install a lower version from a higher-prioritized archive."
(with-package-test ()
- (let* ((newer-version (expand-file-name "package-resources/newer-versions"
- package-test-file-dir))
+ (let* ((newer-version (ert-resource-file "newer-versions"))
(package-archives `(("older" . ,package-test-data-dir)
("newer" . ,newer-version)))
(package-archive-priorities '(("older" . 100))))
@@ -327,7 +331,7 @@ Must called from within a `tar-mode' buffer."
(ert-deftest package-test-install-multifile ()
"Check properties of the installed multi-file package."
- (with-package-test (:basedir "package-resources" :install '(multi-file))
+ (with-package-test (:basedir (ert-resource-directory) :install '(multi-file))
(let ((autoload-file
(expand-file-name "multi-file-autoloads.el"
(expand-file-name
@@ -352,55 +356,128 @@ Must called from within a `tar-mode' buffer."
(goto-char (point-min))
(should (re-search-forward re nil t)))))))
+
+;;; Package Menu tests
+
+(defmacro with-package-menu-test (&rest body)
+ "Set up Package Menu (\"*Packages*\") buffer for testing."
+ (declare (indent 0) (debug (([&rest form]) body)))
+ `(with-package-test ()
+ (let ((buf (package-list-packages)))
+ (unwind-protect
+ (progn ,@body)
+ (kill-buffer buf)))))
+
(ert-deftest package-test-update-listing ()
"Ensure installed package status is updated."
- (with-package-test ()
- (let ((buf (package-list-packages)))
- (search-forward-regexp "^ +simple-single")
- (package-menu-mark-install)
- (package-menu-execute)
- (run-hooks 'post-command-hook)
- (should (package-installed-p 'simple-single))
- (switch-to-buffer "*Packages*")
- (goto-char (point-min))
- (should (re-search-forward "^\\s-+simple-single\\s-+1.3\\s-+installed" nil t))
- (goto-char (point-min))
- (should-not (re-search-forward "^\\s-+simple-single\\s-+1.3\\s-+\\(available\\|new\\)" nil t))
- (kill-buffer buf))))
+ (with-package-menu-test
+ (search-forward-regexp "^ +simple-single")
+ (package-menu-mark-install)
+ (package-menu-execute)
+ (run-hooks 'post-command-hook)
+ (should (package-installed-p 'simple-single))
+ (switch-to-buffer "*Packages*")
+ (goto-char (point-min))
+ (should (re-search-forward "^\\s-+simple-single\\s-+1.3\\s-+installed" nil t))
+ (goto-char (point-min))
+ (should-not (re-search-forward "^\\s-+simple-single\\s-+1.3\\s-+\\(available\\|new\\)" nil t))))
+
+(ert-deftest package-test-list-filter-by-archive ()
+ "Ensure package list is filtered correctly by archive version."
+ (with-package-menu-test
+ ;; TODO: Add another package archive to test filtering, because
+ ;; the testing environment currently only has one.
+ (package-menu-filter-by-archive "gnu")
+ (goto-char (point-min))
+ (should (looking-at "^\\s-+multi-file"))
+ (should (= (count-lines (point-min) (point-max)) 4))
+ (should-error (package-menu-filter-by-archive "non-existent archive"))))
+
+(ert-deftest package-test-list-filter-by-keyword ()
+ "Ensure package list is filtered correctly by package keyword."
+ (with-package-menu-test
+ (package-menu-filter-by-keyword "frobnicate")
+ (goto-char (point-min))
+ (should (re-search-forward "^\\s-+simple-single" nil t))
+ (should (= (count-lines (point-min) (point-max)) 1))
+ (should-error (package-menu-filter-by-keyword "non-existent-keyword"))))
(ert-deftest package-test-list-filter-by-name ()
"Ensure package list is filtered correctly by package name."
+ (with-package-menu-test ()
+ (package-menu-filter-by-name "ansi-color")
+ (goto-char (point-min))
+ (should (re-search-forward "^\\s-+ansi-color" nil t))
+ (should (= (count-lines (point-min) (point-max)) 1))))
+
+(ert-deftest package-test-list-filter-by-status ()
+ "Ensure package list is filtered correctly by package status."
+ (with-package-menu-test
+ (package-menu-filter-by-status "available")
+ (goto-char (point-min))
+ (should (re-search-forward "^\\s-+multi-file" nil t))
+ (should (= (count-lines (point-min) (point-max)) 4))
+ ;; No installed packages in default environment.
+ (should-error (package-menu-filter-by-status "installed"))))
+
+(ert-deftest package-test-list-filter-marked ()
+ "Ensure package list is filtered correctly by non-empty mark."
(with-package-test ()
- (let ((buf (package-list-packages)))
- (package-menu-filter-by-name "tetris")
- (goto-char (point-min))
- (should (re-search-forward "^\\s-+tetris" nil t))
- (should (= (count-lines (point-min) (point-max)) 1))
- (kill-buffer buf))))
+ (package-list-packages)
+ (revert-buffer)
+ (search-forward-regexp "^ +simple-single")
+ (package-menu-mark-install)
+ (package-menu-filter-marked)
+ (goto-char (point-min))
+ (should (re-search-forward "^I +simple-single" nil t))
+ (should (= (count-lines (point-min) (point-max)) 1))
+ (package-menu-mark-unmark)
+ ;; No marked packages in default environment.
+ (should-error (package-menu-filter-marked))))
+
+(ert-deftest package-test-list-filter-by-version ()
+ (with-package-menu-test
+ (should-error (package-menu-filter-by-version "1.1" 'unknown-symbol))) )
+
+(defun package-test-filter-by-version (version predicate name)
+ (with-package-menu-test
+ (package-menu-filter-by-version version predicate)
+ (goto-char (point-min))
+ ;; We just check that the given package is included in the
+ ;; listing. One could be more ambitious.
+ (should (re-search-forward name))))
+
+(ert-deftest package-test-list-filter-by-version-= ()
+ "Ensure package list is filtered correctly by package version (=)."
+ (package-test-filter-by-version "1.1" '= "^\\s-+simple-two-depend"))
+
+(ert-deftest package-test-list-filter-by-version-< ()
+ "Ensure package list is filtered correctly by package version (<)."
+ (package-test-filter-by-version "1.2" '< "^\\s-+simple-two-depend"))
+
+(ert-deftest package-test-list-filter-by-version-> ()
+ "Ensure package list is filtered correctly by package version (>)."
+ (package-test-filter-by-version "1.0" '> "^\\s-+simple-two-depend"))
(ert-deftest package-test-list-clear-filter ()
"Ensure package list filter is cleared correctly."
- (with-package-test ()
- (let ((buf (package-list-packages)))
- (let ((num-packages (count-lines (point-min) (point-max))))
- (should (> num-packages 1))
- (package-menu-filter-by-name "tetris")
- (should (= (count-lines (point-min) (point-max)) 1))
- (package-menu-clear-filter)
- (should (= (count-lines (point-min) (point-max)) num-packages)))
- (kill-buffer buf))))
+ (with-package-menu-test
+ (let ((num-packages (count-lines (point-min) (point-max))))
+ (package-menu-filter-by-name "ansi-color")
+ (should (= (count-lines (point-min) (point-max)) 1))
+ (package-menu-clear-filter)
+ (should (= (count-lines (point-min) (point-max)) num-packages)))))
(ert-deftest package-test-update-archives ()
"Test updating package archives."
(with-package-test ()
- (let ((buf (package-list-packages)))
+ (let ((_buf (package-list-packages)))
(revert-buffer)
(search-forward-regexp "^ +simple-single")
(package-menu-mark-install)
(package-menu-execute)
(should (package-installed-p 'simple-single))
- (let ((package-test-data-dir
- (expand-file-name "package-resources/newer-versions" package-test-file-dir)))
+ (let ((package-test-data-dir (ert-resource-file "newer-versions")))
(setq package-archives `(("gnu" . ,package-test-data-dir)))
(revert-buffer)
@@ -419,6 +496,7 @@ Must called from within a `tar-mode' buffer."
(ert-deftest package-test-update-archives-async ()
"Test updating package archives asynchronously."
+ :tags '(:expensive-test)
(skip-unless (executable-find "python2"))
(let* ((package-menu-async t)
(default-directory package-test-data-dir)
@@ -438,7 +516,7 @@ Must called from within a `tar-mode' buffer."
(when (re-search-forward "Server started, \\(.*\\)\n" nil t)
(setq addr (match-string 1))))
addr)))
- (with-package-test (:basedir package-test-data-dir :location addr)
+ (with-package-test (:basedir (ert-resource-directory) :location addr)
(list-packages)
(should package--downloads-in-progress)
(should mode-line-process)
@@ -458,8 +536,7 @@ Must called from within a `tar-mode' buffer."
(ert-deftest package-test-update-archives/ignore-nil-entry ()
"Ignore any packages that are nil. Test for Bug#28502."
(with-package-test ()
- (let* ((with-nil-entry (expand-file-name "package-resources/with-nil-entry"
- package-test-file-dir))
+ (let* ((with-nil-entry (ert-resource-file "with-nil-entry"))
(package-archives `(("with-nil-entry" . ,with-nil-entry))))
(package-initialize)
(package-refresh-contents)
@@ -537,6 +614,7 @@ Must called from within a `tar-mode' buffer."
(should (search-forward "This is a bare-bones readme file for the multi-file"
nil t)))))
+(defvar epg-config--program-alist) ; Silence byte-compiler.
(ert-deftest package-test-signed ()
"Test verifying package signature."
(skip-unless (let ((homedir (make-temp-file "package-test" t)))
@@ -559,8 +637,7 @@ Must called from within a `tar-mode' buffer."
prog-alist)))
(delete-directory homedir t))))
(let* ((keyring (expand-file-name "key.pub" package-test-data-dir))
- (package-test-data-dir
- (expand-file-name "package-resources/signed" package-test-file-dir)))
+ (package-test-data-dir (ert-resource-file "signed")))
(with-package-test ()
(package-initialize)
(package-import-keyring keyring)
@@ -577,8 +654,8 @@ Must called from within a `tar-mode' buffer."
(should (progn (package-install 'signed-good) 'noerror))
(should (progn (package-install 'signed-bad) 'noerror)))
;; Check if the installed package status is updated.
- (let ((buf (package-list-packages)))
- (revert-buffer)
+ (let ((_buf (package-list-packages)))
+ (revert-buffer)
(should (re-search-forward
"^\\s-+signed-good\\s-+\\(\\S-+\\)\\s-+\\(\\S-+\\)\\s-"
nil t))
@@ -621,7 +698,7 @@ Must called from within a `tar-mode' buffer."
(ert-deftest package-x-test-upload-buffer ()
"Test creating an \"archive-contents\" file"
- (with-package-test (:basedir "package-resources"
+ (with-package-test (:basedir (ert-resource-directory)
:file "simple-single-1.3.el"
:upload-base t)
(package-upload-buffer)
@@ -654,7 +731,7 @@ Must called from within a `tar-mode' buffer."
(ert-deftest package-x-test-upload-new-version ()
"Test uploading a new version of a package"
- (with-package-test (:basedir "package-resources"
+ (with-package-test (:basedir (ert-resource-directory)
:file "simple-single-1.3.el"
:upload-base t)
(package-upload-buffer)
@@ -731,4 +808,4 @@ Must called from within a `tar-mode' buffer."
(provide 'package-test)
-;;; package-test.el ends here
+;;; package-tests.el ends here
diff --git a/test/lisp/emacs-lisp/pcase-tests.el b/test/lisp/emacs-lisp/pcase-tests.el
index f326919b088..1b06c6e7543 100644
--- a/test/lisp/emacs-lisp/pcase-tests.el
+++ b/test/lisp/emacs-lisp/pcase-tests.el
@@ -1,4 +1,4 @@
-;;; pcase-tests.el --- Test suite for pcase macro.
+;;; pcase-tests.el --- Test suite for pcase macro. -*- lexical-binding:t -*-
;; Copyright (C) 2012-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/emacs-lisp/regexp-opt-tests.el b/test/lisp/emacs-lisp/regexp-opt-tests.el
index a4ba3e233d3..940feb5e828 100644
--- a/test/lisp/emacs-lisp/regexp-opt-tests.el
+++ b/test/lisp/emacs-lisp/regexp-opt-tests.el
@@ -25,27 +25,14 @@
(require 'regexp-opt)
-(defun regexp-opt-test--permutation (n list)
- "The Nth permutation of LIST, 0 ≤ N < (length LIST)!."
- (let ((len (length list))
- (perm-list nil))
- (dotimes (i len)
- (let* ((d (- len i))
- (k (mod n d)))
- (push (nth k list) perm-list)
- (setq list (append (butlast list (- (length list) k))
- (nthcdr (1+ k) list)))
- (setq n (/ n d))))
- (nreverse perm-list)))
-
-(defun regexp-opt-test--factorial (n)
- "N!"
- (apply #'* (number-sequence 1 n)))
-
-(defun regexp-opt-test--permutations (list)
- "All permutations of LIST."
- (mapcar (lambda (i) (regexp-opt-test--permutation i list))
- (number-sequence 0 (1- (regexp-opt-test--factorial (length list))))))
+(defun regexp-opt-test--permutations (l)
+ "All permutations of L, assuming no duplicates."
+ (if (cdr l)
+ (mapcan (lambda (x)
+ (mapcar (lambda (p) (cons x p))
+ (regexp-opt-test--permutations (remove x l))))
+ l)
+ (list l)))
(ert-deftest regexp-opt-longest-match ()
"Check that the regexp always matches as much as possible."
diff --git a/test/lisp/emacs-lisp/rmc-tests.el b/test/lisp/emacs-lisp/rmc-tests.el
index 34d513b1416..9d8f3d48014 100644
--- a/test/lisp/emacs-lisp/rmc-tests.el
+++ b/test/lisp/emacs-lisp/rmc-tests.el
@@ -5,18 +5,20 @@
;; Author: Tino Calancha <tino.calancha@gmail.com>
;; Keywords:
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
diff --git a/test/lisp/emacs-lisp/rx-tests.el b/test/lisp/emacs-lisp/rx-tests.el
index e000604d0de..63d7c7b91ea 100644
--- a/test/lisp/emacs-lisp/rx-tests.el
+++ b/test/lisp/emacs-lisp/rx-tests.el
@@ -56,13 +56,17 @@
(ert-deftest rx-def-in-or ()
(rx-let ((a b)
(b (or "abc" c))
- (c ?a))
+ (c ?a)
+ (d (any "a-z")))
(should (equal (rx (or a (| "ab" "abcde") "abcd"))
- "\\(?:a\\(?:b\\(?:c\\(?:de?\\)?\\)?\\)?\\)"))))
+ "\\(?:a\\(?:b\\(?:c\\(?:de?\\)?\\)?\\)?\\)"))
+ (should (equal (rx (or ?m (not d)))
+ "[^a-ln-z]"))))
(ert-deftest rx-char-any ()
"Test character alternatives with `]' and `-' (Bug#25123)."
(should (equal
+ ;; relint suppression: Range .<-]. overlaps previous .]-{
(rx string-start (1+ (char (?\] . ?\{) (?< . ?\]) (?- . ?:)))
string-end)
"\\`[.-:<-{-]+\\'")))
@@ -127,8 +131,12 @@
"[[:lower:][:upper:]-][^[:lower:][:upper:]-]"))
(should (equal (rx (any "]" lower upper) (not (any "]" lower upper)))
"[][:lower:][:upper:]][^][:lower:][:upper:]]"))
- (should (equal (rx (any "-a" "c-" "f-f" "--/*--"))
- "[*-/acf]"))
+ ;; relint suppression: Duplicated character .-.
+ ;; relint suppression: Single-character range .f-f
+ ;; relint suppression: Range .--/. overlaps previous .-
+ ;; relint suppression: Range .\*--. overlaps previous .--/
+ (should (equal (rx (any "-a" "c-" "f-f" "--/*--") (any "," "-" "A"))
+ "[*-/acf][,A-]"))
(should (equal (rx (any "]-a" ?-) (not (any "]-a" ?-)))
"[]-a-][^]-a-]"))
(should (equal (rx (any "--]") (not (any "--]"))
@@ -140,6 +148,7 @@
"\\`a\\`[^z-a]"))
(should (equal (rx (any "") (not (any "")))
"\\`a\\`[^z-a]"))
+ ;; relint suppression: Duplicated class .space.
(should (equal (rx (any space ?a digit space))
"[a[:space:][:digit:]]"))
(should (equal (rx (not "\n") (not ?\n) (not (any "\n")) (not-char ?\n)
@@ -392,6 +401,8 @@
"ab")))
(ert-deftest rx-literal ()
+ (should (equal (rx (literal "$a"))
+ "\\$a"))
(should (equal (rx (literal (char-to-string 42)) nonl)
"\\*."))
(let ((x "a+b"))
@@ -532,6 +543,9 @@
(ert-deftest rx-compat ()
"Test old symbol retained for compatibility (bug#37517)."
- (should (equal (rx-submatch-n '(group-n 3 (+ nonl) eol)) "\\(?3:.+$\\)")))
+ (should (equal
+ (with-no-warnings
+ (rx-submatch-n '(group-n 3 (+ nonl) eol)))
+ "\\(?3:.+$\\)")))
(provide 'rx-tests)
diff --git a/test/lisp/emacs-lisp/seq-tests.el b/test/lisp/emacs-lisp/seq-tests.el
index 97499ff4ea0..670398354a6 100644
--- a/test/lisp/emacs-lisp/seq-tests.el
+++ b/test/lisp/emacs-lisp/seq-tests.el
@@ -1,4 +1,4 @@
-;;; seq-tests.el --- Tests for sequences.el
+;;; seq-tests.el --- Tests for seq.el -*- lexical-binding:t -*-
;; Copyright (C) 2014-2021 Free Software Foundation, Inc.
@@ -126,7 +126,7 @@ Evaluate BODY for each created sequence.
(with-test-sequences (seq '(6 7 8 9 10))
(should (equal (seq-filter #'test-sequences-evenp seq) '(6 8 10)))
(should (equal (seq-filter #'test-sequences-oddp seq) '(7 9)))
- (should (equal (seq-filter (lambda (elt) nil) seq) '())))
+ (should (equal (seq-filter (lambda (_) nil) seq) '())))
(with-test-sequences (seq '())
(should (equal (seq-filter #'test-sequences-evenp seq) '()))))
@@ -134,7 +134,7 @@ Evaluate BODY for each created sequence.
(with-test-sequences (seq '(6 7 8 9 10))
(should (equal (seq-remove #'test-sequences-evenp seq) '(7 9)))
(should (equal (seq-remove #'test-sequences-oddp seq) '(6 8 10)))
- (should (same-contents-p (seq-remove (lambda (elt) nil) seq) seq)))
+ (should (same-contents-p (seq-remove (lambda (_) nil) seq) seq)))
(with-test-sequences (seq '())
(should (equal (seq-remove #'test-sequences-evenp seq) '()))))
@@ -142,7 +142,7 @@ Evaluate BODY for each created sequence.
(with-test-sequences (seq '(6 7 8 9 10))
(should (equal (seq-count #'test-sequences-evenp seq) 3))
(should (equal (seq-count #'test-sequences-oddp seq) 2))
- (should (equal (seq-count (lambda (elt) nil) seq) 0)))
+ (should (equal (seq-count (lambda (_) nil) seq) 0)))
(with-test-sequences (seq '())
(should (equal (seq-count #'test-sequences-evenp seq) 0))))
@@ -199,7 +199,7 @@ Evaluate BODY for each created sequence.
(ert-deftest test-seq-every-p ()
(with-test-sequences (seq '(43 54 22 1))
- (should (seq-every-p (lambda (elt) t) seq))
+ (should (seq-every-p (lambda (_) t) seq))
(should-not (seq-every-p #'test-sequences-oddp seq))
(should-not (seq-every-p #'test-sequences-evenp seq)))
(with-test-sequences (seq '(42 54 22 2))
diff --git a/test/lisp/emacs-lisp/shadow-resources/p1/foo.el b/test/lisp/emacs-lisp/shadow-resources/p1/foo.el
index 465038bee5e..ffe68f9356f 100644
--- a/test/lisp/emacs-lisp/shadow-resources/p1/foo.el
+++ b/test/lisp/emacs-lisp/shadow-resources/p1/foo.el
@@ -1 +1 @@
-;;; This file intentionally left blank.
+;;; This file intentionally left blank. -*- lexical-binding:t -*-
diff --git a/test/lisp/emacs-lisp/shadow-resources/p2/FOO.el b/test/lisp/emacs-lisp/shadow-resources/p2/FOO.el
index 465038bee5e..ffe68f9356f 100644
--- a/test/lisp/emacs-lisp/shadow-resources/p2/FOO.el
+++ b/test/lisp/emacs-lisp/shadow-resources/p2/FOO.el
@@ -1 +1 @@
-;;; This file intentionally left blank.
+;;; This file intentionally left blank. -*- lexical-binding:t -*-
diff --git a/test/lisp/emacs-lisp/shadow-tests.el b/test/lisp/emacs-lisp/shadow-tests.el
index ffb3c9bf189..52d1d21cee1 100644
--- a/test/lisp/emacs-lisp/shadow-tests.el
+++ b/test/lisp/emacs-lisp/shadow-tests.el
@@ -20,30 +20,23 @@
;;; Code:
(require 'ert)
+(require 'ert-x)
(require 'shadow)
(eval-when-compile (require 'cl-lib))
-(defconst shadow-tests-data-directory
- (expand-file-name "lisp/emacs-lisp/shadow-resources"
- (or (getenv "EMACS_TEST_DIRECTORY")
- (expand-file-name "../../.."
- (or load-file-name
- buffer-file-name))))
- "Directory for shadow test files.")
-
(ert-deftest shadow-case-insensitive ()
"Test shadowing for case insensitive filenames."
;; Override `file-name-case-insensitive-p' so we test the same thing
;; regardless of what file system we're running on.
(cl-letf (((symbol-function 'file-name-case-insensitive-p) (lambda (_f) t)))
- (should (equal (list (expand-file-name "p1/foo" shadow-tests-data-directory)
- (expand-file-name "p2/FOO" shadow-tests-data-directory))
+ (should (equal (list (ert-resource-file "p1/foo")
+ (ert-resource-file "p2/FOO"))
(load-path-shadows-find
- (list (expand-file-name "p1/" shadow-tests-data-directory)
- (expand-file-name "p2/" shadow-tests-data-directory))))))
+ (list (ert-resource-file "p1/")
+ (ert-resource-file "p2/"))))))
(cl-letf (((symbol-function 'file-name-case-insensitive-p) (lambda (_f) nil)))
(should-not (load-path-shadows-find
- (list (expand-file-name "p1/" shadow-tests-data-directory)
- (expand-file-name "p2/" shadow-tests-data-directory))))))
+ (list (ert-resource-file "p1/")
+ (ert-resource-file "p2/"))))))
;;; shadow-tests.el ends here.
diff --git a/test/lisp/emacs-lisp/subr-x-tests.el b/test/lisp/emacs-lisp/subr-x-tests.el
index 666af298752..112f3c1dac1 100644
--- a/test/lisp/emacs-lisp/subr-x-tests.el
+++ b/test/lisp/emacs-lisp/subr-x-tests.el
@@ -1,22 +1,24 @@
-;;; subr-x-tests.el --- Testing the extended lisp routines
+;;; subr-x-tests.el --- Testing the extended lisp routines -*- lexical-binding:t -*-
;; Copyright (C) 2014-2021 Free Software Foundation, Inc.
;; Author: Fabián E. Gallina <fgallina@gnu.org>
;; Keywords:
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
@@ -580,5 +582,58 @@
(should (equal (string-remove-suffix "a" "aa") "a"))
(should (equal (string-remove-suffix "a" "ba") "b")))
+(ert-deftest subr-clean-whitespace ()
+ (should (equal (string-clean-whitespace " foo ") "foo"))
+ (should (equal (string-clean-whitespace " foo \r\n\t  Bar") "foo Bar")))
+
+(ert-deftest subr-string-fill ()
+ (should (equal (string-fill "foo" 10) "foo"))
+ (should (equal (string-fill "foobar" 5) "foobar"))
+ (should (equal (string-fill "foo bar zot" 5) "foo\nbar\nzot"))
+ (should (equal (string-fill "foo bar zot" 7) "foo bar\nzot")))
+
+(ert-deftest subr-string-limit ()
+ (should (equal (string-limit "foo" 10) "foo"))
+ (should (equal (string-limit "foo" 2) "fo"))
+ (should (equal (string-limit "foo" 2 t) "oo"))
+ (should (equal (string-limit "abc" 10 t) "abc"))
+ (should (equal (string-limit "foo" 0) ""))
+ (should-error (string-limit "foo" -1)))
+
+(ert-deftest subr-string-limit-coding ()
+ (should (not (multibyte-string-p (string-limit "foó" 10 nil 'utf-8))))
+ (should (equal (string-limit "foó" 10 nil 'utf-8) "fo\303\263"))
+ (should (equal (string-limit "foó" 3 nil 'utf-8) "fo"))
+ (should (equal (string-limit "foó" 4 nil 'utf-8) "fo\303\263"))
+ (should (equal (string-limit "foóa" 4 nil 'utf-8) "fo\303\263"))
+ (should (equal (string-limit "foóá" 4 nil 'utf-8) "fo\303\263"))
+ (should (equal (string-limit "foóa" 4 nil 'iso-8859-1) "fo\363a"))
+ (should (equal (string-limit "foóá" 4 nil 'iso-8859-1) "fo\363\341"))
+ (should (equal (string-limit "foóá" 4 nil 'utf-16) "\376\377\000f"))
+
+ (should (equal (string-limit "foó" 10 t 'utf-8) "fo\303\263"))
+ (should (equal (string-limit "foó" 3 t 'utf-8) "o\303\263"))
+ (should (equal (string-limit "foó" 4 t 'utf-8) "fo\303\263"))
+ (should (equal (string-limit "foóa" 4 t 'utf-8) "o\303\263a"))
+ (should (equal (string-limit "foóá" 4 t 'utf-8) "\303\263\303\241"))
+ (should (equal (string-limit "foóa" 4 t 'iso-8859-1) "fo\363a"))
+ (should (equal (string-limit "foóá" 4 t 'iso-8859-1) "fo\363\341"))
+ (should (equal (string-limit "foóá" 4 t 'utf-16) "\376\377\000\341")))
+
+(ert-deftest subr-string-lines ()
+ (should (equal (string-lines "foo") '("foo")))
+ (should (equal (string-lines "foo \nbar") '("foo " "bar"))))
+
+(ert-deftest subr-string-pad ()
+ (should (equal (string-pad "foo" 5) "foo "))
+ (should (equal (string-pad "foo" 5 ?-) "foo--"))
+ (should (equal (string-pad "foo" 5 ?- t) "--foo"))
+ (should (equal (string-pad "foo" 2 ?-) "foo")))
+
+(ert-deftest subr-string-chop-newline ()
+ (should (equal (string-chop-newline "foo\n") "foo"))
+ (should (equal (string-chop-newline "foo\nbar\n") "foo\nbar"))
+ (should (equal (string-chop-newline "foo\nbar") "foo\nbar")))
+
(provide 'subr-x-tests)
;;; subr-x-tests.el ends here
diff --git a/test/lisp/emacs-lisp/syntax-tests.el b/test/lisp/emacs-lisp/syntax-tests.el
new file mode 100644
index 00000000000..1ae1cbc93ff
--- /dev/null
+++ b/test/lisp/emacs-lisp/syntax-tests.el
@@ -0,0 +1,67 @@
+;;; syntax-tests.el --- tests for syntax.el -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(require 'syntax)
+
+(ert-deftest syntax-propertize--shift-groups-and-backrefs ()
+ "Test shifting of numbered groups and back-references in regexps."
+ ;; A numbered group must be shifted.
+ (should
+ (string=
+ (syntax-propertize--shift-groups-and-backrefs
+ "\\(?2:[abc]+\\)foobar" 2)
+ "\\(?4:[abc]+\\)foobar"))
+ ;; A back-reference \1 on a normal sub-regexp context must be
+ ;; shifted.
+ (should
+ (string=
+ (syntax-propertize--shift-groups-and-backrefs "\\(a\\)\\1" 2)
+ "\\(a\\)\\3"))
+ ;; Shifting must not happen if the \1 appears in a character class,
+ ;; or in a \{\} repetition construct (although \1 isn't valid there
+ ;; anyway).
+ (let ((rx-with-class "\\(a\\)[\\1-2]")
+ (rx-with-rep "\\(a\\)\\{1,\\1\\}"))
+ (should
+ (string=
+ (syntax-propertize--shift-groups-and-backrefs rx-with-class 2)
+ rx-with-class))
+ (should
+ (string=
+ (syntax-propertize--shift-groups-and-backrefs rx-with-rep 2)
+ rx-with-rep)))
+ ;; Now numbered groups and back-references in combination.
+ (should
+ (string=
+ (syntax-propertize--shift-groups-and-backrefs
+ "\\(?2:[abc]+\\)foo\\(\\2\\)" 2)
+ "\\(?4:[abc]+\\)foo\\(\\4\\)"))
+ ;; Emacs supports only the back-references \1,...,\9, so when a
+ ;; shift would result in \10 or more, an error must be signalled.
+ (should-error
+ (syntax-propertize--shift-groups-and-backrefs "\\(a\\)\\3" 7)))
+
+;; Local Variables:
+;; no-byte-compile: t
+;; End:
+
+;;; syntax-tests.el ends here.
diff --git a/test/lisp/emacs-lisp/testcover-tests.el b/test/lisp/emacs-lisp/testcover-tests.el
index 626769b1482..9f0312d85ff 100644
--- a/test/lisp/emacs-lisp/testcover-tests.el
+++ b/test/lisp/emacs-lisp/testcover-tests.el
@@ -31,26 +31,10 @@
;;; Code:
(require 'ert)
+(require 'ert-x)
(require 'testcover)
(require 'skeleton)
-;; Use `eval-and-compile' around all these definitions because they're
-;; used by the macro `testcover-tests-define-tests'.
-
-(eval-and-compile
- (defvar testcover-tests-file-dir
- (expand-file-name
- "testcover-resources/"
- (file-name-directory (or (bound-and-true-p byte-compile-current-file)
- load-file-name
- buffer-file-name)))
- "Directory of the \"testcover-tests.el\" file."))
-
-(eval-and-compile
- (defvar testcover-tests-test-cases
- (expand-file-name "testcases.el" testcover-tests-file-dir)
- "File containing marked up code to instrument and check."))
-
;; Convert Testcover's overlays to plain text.
(eval-and-compile
@@ -62,6 +46,7 @@ is working correctly on a code sample. OPTARGS are optional
arguments for `testcover-start'."
(interactive "r")
(let ((tempfile (make-temp-file "testcover-tests-" nil ".el"))
+ (find-file-suppress-same-file-warnings t)
(code (buffer-substring beg end))
(marked-up-code))
(unwind-protect
@@ -114,7 +99,8 @@ arguments for `testcover-start'."
(eval-and-compile
(defun testcover-tests-run-test-case (marked-up-code)
"Test the operation of Testcover on the string MARKED-UP-CODE."
- (let ((tempfile (make-temp-file "testcover-tests-" nil ".el")))
+ (let ((tempfile (make-temp-file "testcover-tests-" nil ".el"))
+ (find-file-suppress-same-file-warnings t))
(unwind-protect
(progn
(with-temp-file tempfile
@@ -149,7 +135,7 @@ Construct and return a list of `ert-deftest' forms. See testcases.el
for documentation of the test definition format."
(let (results)
(with-temp-buffer
- (insert-file-contents testcover-tests-test-cases)
+ (insert-file-contents (ert-resource-file "testcases.el"))
(goto-char (point-min))
(while (re-search-forward
(concat "^;; ==== \\([^ ]+?\\) ====\n"
diff --git a/test/lisp/emacs-lisp/text-property-search-tests.el b/test/lisp/emacs-lisp/text-property-search-tests.el
index 93ab4219c17..90f06c3c4c0 100644
--- a/test/lisp/emacs-lisp/text-property-search-tests.el
+++ b/test/lisp/emacs-lisp/text-property-search-tests.el
@@ -1,22 +1,24 @@
-;;; text-property-search-tests.el --- Testing text-property-search
+;;; text-property-search-tests.el --- Testing text-property-search -*- lexical-binding:t -*-
;; Copyright (C) 2018-2021 Free Software Foundation, Inc.
;; Author: Lars Ingebrigtsen <larsi@gnus.org>
;; Keywords:
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
@@ -151,6 +153,24 @@
46 57 nil
(point-max)))
+
+;;;; Position after search.
+
+(defun text-property-search--pos-test (fun pos &optional reverse)
+ (with-temp-buffer
+ (insert (concat "foo "
+ (propertize "bar" 'x t)
+ " baz"))
+ (goto-char (if reverse (point-max) (point-min)))
+ (funcall fun 'x t)
+ (should (= (point) pos))))
+
+(ert-deftest text-property-search-forward-point-at-beginning ()
+ (text-property-search--pos-test #'text-property-search-forward 5))
+
+(ert-deftest text-property-search-backward-point-at-end ()
+ (text-property-search--pos-test #'text-property-search-backward 8 t))
+
(provide 'text-property-search-tests)
;;; text-property-search-tests.el ends here
diff --git a/test/lisp/emacs-lisp/unsafep-tests.el b/test/lisp/emacs-lisp/unsafep-tests.el
new file mode 100644
index 00000000000..b2a48d80675
--- /dev/null
+++ b/test/lisp/emacs-lisp/unsafep-tests.el
@@ -0,0 +1,154 @@
+;;; unsafep-tests.el --- tests for unsafep.el -*- lexical-binding: t; -*-
+
+;; Author: Jonathan Yavner <jyavner@member.fsf.org>
+
+;; Copyright (C) 2002-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(require 'unsafep)
+
+(defvar safe-functions)
+
+;;; These forms are all considered safe
+(defconst unsafep-tests--safe
+ '(((lambda (x) (* x 2)) 14)
+ (apply 'cdr (mapcar (lambda (x) (car x)) y))
+ (cond ((= x 4) 5) (t 27))
+ (condition-case x (car y) (error (car x)))
+ (let (x) (dolist (y '(1 2 3) (1+ y)) (push y x)))
+ (let (x) (apply (lambda (x) (* x 2)) 14))
+ (let ((x '(2))) (push 1 x) (pop x) (add-to-list 'x 2))
+ (let ((x 1) (y 2)) (setq x (+ x y)))
+ (let ((x 1)) (let ((y (+ x 3))) (* x y)))
+ (let* nil (current-time))
+ (let* ((x 1) (y (+ x 3))) (* x y))
+ (mapcar (lambda (x &optional y &rest z) (setq y (+ x 2)) (* y 3)) '(1 2 3))
+ (mapconcat #'(lambda (var) (propertize var 'face 'bold)) '("1" "2") ", ")
+ (setq buffer-display-count 14 mark-active t)
+ ;;This is not safe if you insert it into a buffer!
+ (propertize "x" 'display '(height (progn (delete-file "x") 1))))
+ "List of forms that `unsafep' should decide are safe.")
+
+;;; These forms are considered unsafe
+(defconst unsafep-tests--unsafe
+ '(( (add-to-list x y)
+ . (unquoted x))
+ ( (add-to-list y x)
+ . (unquoted y))
+ ( (add-to-list 'y x)
+ . (global-variable y))
+ ( (not (delete-file "unsafep.el"))
+ . (function delete-file))
+ ( (cond (t (aset local-abbrev-table 0 0)))
+ . (function aset))
+ ( (cond (t (setq unsafep-vars "")))
+ . (risky-local-variable unsafep-vars))
+ ( (condition-case format-alist 1)
+ . (risky-local-variable format-alist))
+ ( (condition-case x 1 (error (setq format-alist "")))
+ . (risky-local-variable format-alist))
+ ( (dolist (x (sort globalvar 'car)) (princ x))
+ . (function sort))
+ ( (dotimes (x 14) (delete-file "x"))
+ . (function delete-file))
+ ( (let ((post-command-hook "/tmp/")) 1)
+ . (risky-local-variable post-command-hook))
+ ( (let ((x (delete-file "x"))) 2)
+ . (function delete-file))
+ ( (let (x) (add-to-list 'x (delete-file "x")))
+ . (function delete-file))
+ ( (let (x) (condition-case y (setq x 1 z 2)))
+ . (global-variable z))
+ ( (let (x) (condition-case z 1 (error (delete-file "x"))))
+ . (function delete-file))
+ ( (let (x) (mapc (lambda (x) (setcar x 1)) '((1 . 2) (3 . 4))))
+ . (function setcar))
+ ( (let (y) (push (delete-file "x") y))
+ . (function delete-file))
+ ( (let* ((x 1)) (setq y 14))
+ . (global-variable y))
+ ( (mapc 'car (list '(1 . 2) (cons 3 4) (kill-buffer "unsafep.el")))
+ . (function kill-buffer))
+ ( (mapcar x y)
+ . (unquoted x))
+ ( (mapcar (lambda (x) (rename-file x "x")) '("unsafep.el"))
+ . (function rename-file))
+ ( (mapconcat x1 x2 " ")
+ . (unquoted x1))
+ ( (pop format-alist)
+ . (risky-local-variable format-alist))
+ ( (push 1 format-alist)
+ . (risky-local-variable format-alist))
+ ( (setq buffer-display-count (delete-file "x"))
+ . (function delete-file))
+ ;;These are actually safe (they signal errors)
+ ( (apply '(x) '(1 2 3))
+ . (function (x)))
+ ( (let (((x))) 1)
+ . (variable (x)))
+ ( (let (1) 2)
+ . (variable 1))
+ ( (error "asdf")
+ . #'error)
+ ( (signal 'error "asdf")
+ . #'signal)
+ ( (throw 'asdf)
+ . #'throw)
+ ( (catch 'asdf 17)
+ . #'catch)
+ ( (play-sound-file "asdf")
+ . #'play-sound-file)
+ ( (replace-regexp-in-string "a" "b")
+ . #'replace-regexp-in-string)
+ )
+ "A-list of (FORM . REASON)... that `unsafep' should decide are unsafe.")
+
+(ert-deftest test-unsafep/safe ()
+ "Check safe forms with safe-functions nil."
+ (let (safe-functions)
+ (dolist (x unsafep-tests--safe)
+ (should-not (unsafep x)))))
+
+(ert-deftest test-unsafep/message ()
+ "Check that message is considered unsafe."
+ (should (unsafep '(dolist (x y) (message "here: %s" x))))
+ (should (unsafep '(dotimes (x 14 (* x 2)) (message "here: %d" x)))))
+
+(ert-deftest test-unsafep/unsafe ()
+ "Check unsafe forms with safe-functions nil."
+ (let (safe-functions)
+ (dolist (x unsafep-tests--unsafe)
+ (should (equal (unsafep (car x)) (cdr x))))))
+
+(ert-deftest test-unsafep/safe-functions-t ()
+ "safe-functions=t should allow delete-file"
+ (let ((safe-functions t))
+ (should-not (unsafep '(delete-file "x")))
+ (should-not (unsafep-function 'delete-file))))
+
+(ert-deftest test-unsafep/safe-functions-setcar ()
+ "safe-functions=(setcar) should allow setcar but not setcdr"
+ (let ((safe-functions '(setcar)))
+ (should-not (unsafep '(setcar x 1)))
+ (should (unsafep '(setcdr x 1)))))
+
+(provide 'unsafep-tests)
+
+;;; unsafep-tests.el ends here
diff --git a/test/lisp/emacs-lisp/warnings-tests.el b/test/lisp/emacs-lisp/warnings-tests.el
new file mode 100644
index 00000000000..aa394634827
--- /dev/null
+++ b/test/lisp/emacs-lisp/warnings-tests.el
@@ -0,0 +1,60 @@
+;;; warnings-tests.el --- tests for warnings.el -*- lexical-binding: t; -*-
+
+;; Author: Stefan Kangas <stefankangas@gmail.com>
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(require 'warnings)
+
+(ert-deftest test-warning-suppress-p ()
+ (should (warning-suppress-p 'foo '((foo))))
+ (should (warning-suppress-p '(foo bar) '((foo bar))))
+ (should (warning-suppress-p '(foo bar baz) '((foo bar))))
+ (should-not (warning-suppress-p '(foo bar baz) '((foo bax))))
+ (should-not (warning-suppress-p 'foobar nil)))
+
+(ert-deftest test-display-warning ()
+ (dolist (level '(:emergency :error :warning))
+ (with-temp-buffer
+ (display-warning '(foo) "Hello123" level (current-buffer))
+ (should (string-match "foo" (buffer-string)))
+ (should (string-match "Hello123" (buffer-string))))
+ (with-current-buffer "*Messages*"
+ (should (string-match "Hello123" (buffer-string))))))
+
+(ert-deftest test-display-warning/warning-minimum-level ()
+ ;; This test only works interactively:
+ :expected-result :failed
+ (let ((warning-minimum-level :emergency))
+ (with-temp-buffer
+ (display-warning '(foo) "baz" :warning (current-buffer)))
+ (with-current-buffer "*Messages*"
+ (should-not (string-match "baz" (buffer-string))))))
+
+(ert-deftest test-display-warning/warning-minimum-log-level ()
+ (let ((warning-minimum-log-level :error))
+ (with-temp-buffer
+ (display-warning '(foo) "hello" :warning (current-buffer))
+ (should-not (string-match "hello" (buffer-string))))))
+
+(provide 'warnings-tests)
+
+;;; warnings-tests.el ends here
diff --git a/test/lisp/emulation/viper-tests.el b/test/lisp/emulation/viper-tests.el
index 9b9a8e514b3..0d999763b61 100644
--- a/test/lisp/emulation/viper-tests.el
+++ b/test/lisp/emulation/viper-tests.el
@@ -1,4 +1,4 @@
-;;; viper-tests.el --- tests for viper.
+;;; viper-tests.el --- tests for viper. -*- lexical-binding:t -*-
;; Copyright (C) 2016-2021 Free Software Foundation, Inc.
diff --git a/test/data/epg/dummy-pinentry b/test/lisp/epg-resources/dummy-pinentry
index 2228dfb0c6d..2228dfb0c6d 100755
--- a/test/data/epg/dummy-pinentry
+++ b/test/lisp/epg-resources/dummy-pinentry
diff --git a/test/data/epg/pubkey.asc b/test/lisp/epg-resources/pubkey.asc
index c0bf28f6200..c0bf28f6200 100644
--- a/test/data/epg/pubkey.asc
+++ b/test/lisp/epg-resources/pubkey.asc
diff --git a/test/data/epg/seckey.asc b/test/lisp/epg-resources/seckey.asc
index 4ac7ba4a502..4ac7ba4a502 100644
--- a/test/data/epg/seckey.asc
+++ b/test/lisp/epg-resources/seckey.asc
diff --git a/test/lisp/epg-tests.el b/test/lisp/epg-tests.el
index 29c02588e1f..741574f0adf 100644
--- a/test/lisp/epg-tests.el
+++ b/test/lisp/epg-tests.el
@@ -22,14 +22,11 @@
;;; Code:
(require 'ert)
+(require 'ert-x)
(require 'epg)
(defvar epg-tests-context nil)
-(defvar epg-tests-data-directory
- (expand-file-name "data/epg" (getenv "EMACS_TEST_DIRECTORY"))
- "Directory containing epg test data.")
-
(defconst epg-tests--config-program-alist
;; The default `epg-config--program-alist' requires gpg2 2.1 or
;; greater due to some practical problems with pinentry. But most
@@ -85,8 +82,7 @@
'(with-temp-file (expand-file-name
"gpg-agent.conf" epg-tests-home-directory)
(insert "pinentry-program "
- (expand-file-name "dummy-pinentry"
- epg-tests-data-directory)
+ (ert-resource-file "dummy-pinentry")
"\n")
(epg-context-set-passphrase-callback
context
@@ -94,14 +90,13 @@
,(if require-public-key
'(epg-import-keys-from-file
context
- (expand-file-name "pubkey.asc" epg-tests-data-directory)))
+ (ert-resource-file "pubkey.asc")))
,(if require-secret-key
'(epg-import-keys-from-file
context
- (expand-file-name "seckey.asc" epg-tests-data-directory)))
+ (ert-resource-file "seckey.asc")))
(with-temp-buffer
- (make-local-variable 'epg-tests-context)
- (setq epg-tests-context context)
+ (setq-local epg-tests-context context)
,@body))
(when (file-directory-p epg-tests-home-directory)
(delete-directory epg-tests-home-directory t)))))
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el
new file mode 100644
index 00000000000..26e14b98e91
--- /dev/null
+++ b/test/lisp/erc/erc-tests.el
@@ -0,0 +1,47 @@
+;;; erc-tests.el --- Tests for erc. -*- lexical-binding:t -*-
+
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+;; Author: Lars Ingebrigtsen <larsi@gnus.org>
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(require 'erc)
+
+(ert-deftest erc--read-time-period ()
+ (cl-letf (((symbol-function 'read-string) (lambda (&rest _) "")))
+ (should (equal (erc--read-time-period "foo: ") nil)))
+
+ (cl-letf (((symbol-function 'read-string) (lambda (&rest _) " ")))
+ (should (equal (erc--read-time-period "foo: ") nil)))
+
+ (cl-letf (((symbol-function 'read-string) (lambda (&rest _) " 432 ")))
+ (should (equal (erc--read-time-period "foo: ") 432)))
+
+ (cl-letf (((symbol-function 'read-string) (lambda (&rest _) "432")))
+ (should (equal (erc--read-time-period "foo: ") 432)))
+
+ (cl-letf (((symbol-function 'read-string) (lambda (&rest _) "1h")))
+ (should (equal (erc--read-time-period "foo: ") 3600)))
+
+ (cl-letf (((symbol-function 'read-string) (lambda (&rest _) "1h10s")))
+ (should (equal (erc--read-time-period "foo: ") 3610)))
+
+ (cl-letf (((symbol-function 'read-string) (lambda (&rest _) "1d")))
+ (should (equal (erc--read-time-period "foo: ") 86400))))
diff --git a/test/lisp/erc/erc-track-tests.el b/test/lisp/erc/erc-track-tests.el
index a9726876304..0ce93bd45c6 100644
--- a/test/lisp/erc/erc-track-tests.el
+++ b/test/lisp/erc/erc-track-tests.el
@@ -1,4 +1,4 @@
-;;; erc-track-tests.el --- Tests for erc-track.
+;;; erc-track-tests.el --- Tests for erc-track. -*- lexical-binding:t -*-
;; Copyright (C) 2016-2021 Free Software Foundation, Inc.
@@ -24,7 +24,6 @@
(require 'ert)
(require 'erc-track)
-(require 'font-core)
(ert-deftest erc-track--shorten-aggressive-nil ()
"Test non-aggressive erc track buffer name shortening."
@@ -107,8 +106,8 @@
(ert-deftest erc-track--erc-faces-in ()
"`erc-faces-in' should pick up both 'face and 'font-lock-face properties."
- (let ((str0 "is bold")
- (str1 "is bold"))
+ (let ((str0 (copy-sequence "is bold"))
+ (str1 (copy-sequence "is bold")))
;; Turn on Font Lock mode: this initialize `char-property-alias-alist'
;; to '((face font-lock-face)). Note that `font-lock-mode' don't
;; turn on the mode if the test is run on batch mode or if the
diff --git a/test/lisp/eshell/em-hist-tests.el b/test/lisp/eshell/em-hist-tests.el
index b66e7b58624..ec65397fd63 100644
--- a/test/lisp/eshell/em-hist-tests.el
+++ b/test/lisp/eshell/em-hist-tests.el
@@ -1,4 +1,4 @@
-;;; tests/em-hist-tests.el --- em-hist test suite
+;;; tests/em-hist-tests.el --- em-hist test suite -*- lexical-binding:t -*-
;; Copyright (C) 2017-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/eshell/em-ls-tests.el b/test/lisp/eshell/em-ls-tests.el
index a357f71d585..fc2cd9c8e14 100644
--- a/test/lisp/eshell/em-ls-tests.el
+++ b/test/lisp/eshell/em-ls-tests.el
@@ -1,4 +1,4 @@
-;;; tests/em-ls-tests.el --- em-ls test suite
+;;; tests/em-ls-tests.el --- em-ls test suite -*- lexical-binding:t -*-
;; Copyright (C) 2017-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/eshell/esh-opt-tests.el b/test/lisp/eshell/esh-opt-tests.el
index 82cddb345fa..0c99da64b2e 100644
--- a/test/lisp/eshell/esh-opt-tests.el
+++ b/test/lisp/eshell/esh-opt-tests.el
@@ -1,4 +1,4 @@
-;;; tests/esh-opt-tests.el --- esh-opt test suite
+;;; tests/esh-opt-tests.el --- esh-opt test suite -*- lexical-binding:t -*-
;; Copyright (C) 2018-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/eshell/eshell-tests.el b/test/lisp/eshell/eshell-tests.el
index a7522bc4e0a..4dac7024f41 100644
--- a/test/lisp/eshell/eshell-tests.el
+++ b/test/lisp/eshell/eshell-tests.el
@@ -1,4 +1,4 @@
-;;; tests/eshell-tests.el --- Eshell test suite
+;;; tests/eshell-tests.el --- Eshell test suite -*- lexical-binding:t -*-
;; Copyright (C) 1999-2021 Free Software Foundation, Inc.
@@ -61,6 +61,8 @@
(eshell-insert-command text func)
(eshell-match-result regexp))
+(defvar eshell-history-file-name)
+
(defun eshell-test-command-result (command)
"Like `eshell-command-result', but not using HOME."
(let ((eshell-directory-name (make-temp-file "eshell" t))
@@ -170,6 +172,13 @@ e.g. \"{(+ 1 2)} 3\" => 3"
(eshell-command-result-p "+ 1 2; + $_ 4"
"3\n6\n")))
+(ert-deftest eshell-test/inside-emacs-var ()
+ "Test presence of \"INSIDE_EMACS\" in subprocesses"
+ (with-temp-eshell
+ (eshell-command-result-p "env"
+ (format "INSIDE_EMACS=%s,eshell"
+ emacs-version))))
+
(ert-deftest eshell-test/escape-nonspecial ()
"Test that \"\\c\" and \"c\" are equivalent when \"c\" is not a
special character."
diff --git a/test/data/themes/faces-test-dark-theme.el b/test/lisp/faces-resources/faces-test-dark-theme.el
index acf03507ee1..f3ef6b67fa7 100644
--- a/test/data/themes/faces-test-dark-theme.el
+++ b/test/lisp/faces-resources/faces-test-dark-theme.el
@@ -2,18 +2,20 @@
;; Copyright (C) 2019-2021 Free Software Foundation, Inc.
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
diff --git a/test/data/themes/faces-test-light-theme.el b/test/lisp/faces-resources/faces-test-light-theme.el
index 78d3b9e017f..390b8461644 100644
--- a/test/data/themes/faces-test-light-theme.el
+++ b/test/lisp/faces-resources/faces-test-light-theme.el
@@ -2,18 +2,20 @@
;; Copyright (C) 2019-2021 Free Software Foundation, Inc.
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
diff --git a/test/lisp/faces-tests.el b/test/lisp/faces-tests.el
index 0850aae394f..6e77259fe1b 100644
--- a/test/lisp/faces-tests.el
+++ b/test/lisp/faces-tests.el
@@ -5,28 +5,25 @@
;; Author: Artur Malabarba <bruce.connor.am@gmail.com>
;; Keywords:
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Code:
(require 'ert)
-(require 'faces)
-
-(defvar faces--test-data-dir
- (expand-file-name "../data/"
- (file-name-directory (or load-file-name
- buffer-file-name))))
+(require 'ert-x)
(defgroup faces--test nil ""
:group 'faces--test)
@@ -120,7 +117,7 @@
(should (equal (face-attribute 'spiff-changed-face :extend) t))
(should (equal (face-attribute 'spiff-added :extend) 'unspecified))
(should (equal (face-attribute 'spiff-file-header-face :extend) nil))
- (add-to-list 'custom-theme-load-path (concat faces--test-data-dir "themes"))
+ (add-to-list 'custom-theme-load-path (ert-resource-directory))
(load-theme 'faces-test-dark t t)
(load-theme 'faces-test-light t t)
(should (equal (face-attribute 'faces--test-inherit-extend :extend)
diff --git a/test/lisp/ffap-tests.el b/test/lisp/ffap-tests.el
index 6ac26435eb2..3ceb392d7fb 100644
--- a/test/lisp/ffap-tests.el
+++ b/test/lisp/ffap-tests.el
@@ -74,9 +74,55 @@ left alone when opening a URL in an external browser."
(urls nil)
(ffap-url-fetcher (lambda (url) (push url urls) nil)))
(should-not (ffap-other-window "https://www.gnu.org"))
- (should (equal (current-window-configuration) old))
+ (should (compare-window-configurations (current-window-configuration) old))
(should (equal urls '("https://www.gnu.org")))))
+(defun ffap-test-string (space string)
+ (let ((ffap-file-name-with-spaces space))
+ (with-temp-buffer
+ (insert string)
+ (goto-char (point-min))
+ (forward-char 10)
+ (ffap-string-at-point))))
+
+(ert-deftest ffap-test-with-spaces ()
+ (should
+ (equal
+ (ffap-test-string
+ t "c:/Program Files/Open Text Evaluation Media/Open Text Exceed 14 x86/Program here.txt")
+ "/Program Files/Open Text Evaluation Media/Open Text Exceed 14 x86/Program here.txt"))
+ (should
+ (equal
+ (ffap-test-string
+ nil "c:/Program Files/Open Text Evaluation Media/Open Text Exceed 14 x86/Program here.txt")
+ "c:/Program"))
+ (should
+ (equal
+ (ffap-test-string
+ t "c:/Program Files/Open Text Evaluation Media/Open Text Exceed 14 x86/Program Files/Hummingbird/")
+ "/Program Files/Open Text Evaluation Media/Open Text Exceed 14 x86/Program Files/Hummingbird/"))
+ (should
+ (equal
+ (ffap-test-string
+ t "c:\\Program Files\\Open Text Evaluation Media\\Open Text Exceed 14 x86\\Program Files\\Hummingbird\\")
+ "\\Program Files\\Open Text Evaluation Media\\Open Text Exceed 14 x86\\Program Files\\Hummingbird\\"))
+ (should
+ (equal
+ (ffap-test-string
+ t "c:\\Program Files\\Freescale\\CW for MPC55xx and MPC56xx 2.10\\PowerPC_EABI_Tools\\Command_Line_Tools\\CLT_Usage_Notes.txt")
+ "\\Program Files\\Freescale\\CW for MPC55xx and MPC56xx 2.10\\PowerPC_EABI_Tools\\Command_Line_Tools\\CLT_Usage_Notes.txt"))
+ (should
+ (equal
+ (ffap-test-string
+ t "C:\\temp\\program.log on Windows or /var/log/program.log on Unix.")
+ "\\temp\\program.log")))
+
+(ert-deftest ffap-test-no-newlines ()
+ (should-not
+ (with-temp-buffer
+ (save-excursion (insert "type="))
+ (ffap-guess-file-name-at-point))))
+
(provide 'ffap-tests)
;;; ffap-tests.el ends here
diff --git a/test/lisp/filenotify-tests.el b/test/lisp/filenotify-tests.el
index a7ceeddb416..047109a96a2 100644
--- a/test/lisp/filenotify-tests.el
+++ b/test/lisp/filenotify-tests.el
@@ -4,18 +4,20 @@
;; Author: Michael Albinus <michael.albinus@gmx.de>
-;; This program is free software: you can redistribute it and/or
+;; 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.
;;
-;; This program is distributed in the hope that it will be useful, but
+;; 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 `https://www.gnu.org/licenses/'.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
@@ -106,11 +108,8 @@ There are different timeouts for local and remote file notification libraries."
;; gio/gpollfilemonitor.c declares POLL_TIME_SECS 5. So we must
;; wait at least this time in the GPollFileMonitor case. A
;; similar timeout seems to be needed in the GFamFileMonitor case,
- ;; at least on Cygwin.
- ((and (string-equal (file-notify--test-library) "gfilenotify")
- (memq (file-notify--test-monitor)
- '(GFamFileMonitor GPollFileMonitor)))
- 7)
+ ;; at least on cygwin.
+ ((memq (file-notify--test-monitor) '(GFamFileMonitor GPollFileMonitor)) 7)
((string-equal (file-notify--test-library) "gvfs-monitor-dir.exe") 1)
((file-remote-p temporary-file-directory) 0.1)
(t 0.01))))
@@ -200,8 +199,7 @@ Return nil when any other file notification watch is still active."
(setq file-notify-debug nil
password-cache-expiry nil
- tramp-verbose 0
- tramp-message-show-message nil)
+ tramp-verbose 0)
;; This should happen on hydra only.
(when (getenv "EMACS_HYDRA_CI")
@@ -220,7 +218,8 @@ remote case we return always t."
(or file-notify--library
(file-remote-p temporary-file-directory)))
-(defvar file-notify--test-remote-enabled-checked nil
+(defvar file-notify--test-remote-enabled-checked
+ (if (getenv "EMACS_HYDRA_CI") '(t . nil))
"Cached result of `file-notify--test-remote-enabled'.
If the function did run, the value is a cons cell, the `cdr'
being the result.")
@@ -262,13 +261,19 @@ This returns only for the local case and gfilenotify; otherwise it is nil.
;; We cache the result, because after `file-notify-rm-watch',
;; `gfile-monitor-name' does not return a proper result anymore.
;; But we still need this information.
- (unless (file-remote-p temporary-file-directory)
- (or (cdr (assq file-notify--test-desc file-notify--test-monitors))
- (when (functionp 'gfile-monitor-name)
- (add-to-list 'file-notify--test-monitors
- (cons file-notify--test-desc
- (gfile-monitor-name file-notify--test-desc)))
- (cdr (assq file-notify--test-desc file-notify--test-monitors))))))
+ ;; So far, we know the monitors GFamFileMonitor, GFenFileMonitor,
+ ;; GInotifyFileMonitor, GKqueueFileMonitor and GPollFileMonitor.
+ (or (cdr (assq file-notify--test-desc file-notify--test-monitors))
+ (progn
+ (add-to-list
+ 'file-notify--test-monitors
+ (cons file-notify--test-desc
+ (if (file-remote-p temporary-file-directory)
+ (tramp-get-connection-property
+ file-notify--test-desc "gio-file-monitor" nil)
+ (and (functionp 'gfile-monitor-name)
+ (gfile-monitor-name file-notify--test-desc)))))
+ (cdr (assq file-notify--test-desc file-notify--test-monitors)))))
(defmacro file-notify--deftest-remote (test docstring &optional unstable)
"Define ert `TEST-remote' for remote files.
@@ -455,7 +460,7 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'."
(unwind-protect
;; Check, that removing watch descriptors out of order do not
- ;; harm. This fails on Cygwin because of timing issues unless a
+ ;; harm. This fails on cygwin because of timing issues unless a
;; long `sit-for' is added before the call to
;; `file-notify--test-read-event'.
(unless (eq system-type 'cygwin)
@@ -611,6 +616,7 @@ delivered."
(ert-deftest file-notify-test03-events ()
"Check file creation/change/removal notifications."
+ :tags '(:expensive-test)
(skip-unless (file-notify--test-local-enabled))
(unwind-protect
@@ -628,13 +634,15 @@ delivered."
(cond
;; gvfs-monitor-dir on cygwin does not detect the
;; `created' event reliably.
- ((string-equal
- (file-notify--test-library) "gvfs-monitor-dir.exe")
+ ((string-equal (file-notify--test-library) "gvfs-monitor-dir.exe")
'((deleted stopped)
(created deleted stopped)))
;; cygwin does not raise a `changed' event.
((eq system-type 'cygwin)
'(created deleted stopped))
+ ;; GKqueueFileMonitor does not report the `changed' event.
+ ((equal (file-notify--test-monitor) 'GKqueueFileMonitor)
+ '(created deleted stopped))
(t '(created changed deleted stopped)))
(write-region
"another text" nil file-notify--test-tmpfile nil 'no-message)
@@ -665,6 +673,9 @@ delivered."
((string-equal (file-notify--test-library) "gvfs-monitor-dir.exe")
'((deleted stopped)
(changed deleted stopped)))
+ ;; GKqueueFileMonitor does not report the `changed' event.
+ ((equal (file-notify--test-monitor) 'GKqueueFileMonitor)
+ '(deleted stopped))
;; There could be one or two `changed' events.
(t '((changed deleted stopped)
(changed changed deleted stopped))))
@@ -715,6 +726,9 @@ delivered."
'(created deleted stopped))
((string-equal (file-notify--test-library) "kqueue")
'(created changed deleted stopped))
+ ;; GKqueueFileMonitor does not report the `changed' event.
+ ((equal (file-notify--test-monitor) 'GKqueueFileMonitor)
+ '(created deleted deleted stopped))
(t '(created changed deleted deleted stopped)))
(write-region
"any text" nil file-notify--test-tmpfile nil 'no-message)
@@ -764,6 +778,9 @@ delivered."
;; directory are not detected.
((getenv "EMACS_EMBA_CI")
'(created changed created changed deleted deleted))
+ ;; GKqueueFileMonitor does not report the `changed' event.
+ ((equal (file-notify--test-monitor) 'GKqueueFileMonitor)
+ '(created created deleted deleted deleted stopped))
(t '(created changed created changed
deleted deleted deleted stopped)))
(write-region
@@ -772,9 +789,9 @@ delivered."
(copy-file file-notify--test-tmpfile file-notify--test-tmpfile1)
;; The next two events shall not be visible.
(file-notify--test-read-event)
- (set-file-modes file-notify--test-tmpfile 000)
+ (set-file-modes file-notify--test-tmpfile 000 'nofollow)
(file-notify--test-read-event)
- (set-file-times file-notify--test-tmpfile '(0 0))
+ (set-file-times file-notify--test-tmpfile '(0 0) 'nofollow)
(file-notify--test-read-event)
(delete-directory file-notify--test-tmpdir 'recursive))
(file-notify-rm-watch file-notify--test-desc)
@@ -820,6 +837,9 @@ delivered."
'(created created deleted deleted stopped))
((string-equal (file-notify--test-library) "kqueue")
'(created changed renamed deleted stopped))
+ ;; GKqueueFileMonitor does not report the `changed' event.
+ ((equal (file-notify--test-monitor) 'GKqueueFileMonitor)
+ '(created renamed deleted deleted stopped))
(t '(created changed renamed deleted deleted stopped)))
(write-region
"any text" nil file-notify--test-tmpfile nil 'no-message)
@@ -856,6 +876,8 @@ delivered."
((string-equal (file-notify--test-library) "w32notify")
'((changed changed)
(changed changed changed changed)))
+ ;; GKqueueFileMonitor does not report the `attribute-changed' event.
+ ((equal (file-notify--test-monitor) 'GKqueueFileMonitor) nil)
;; For kqueue and in the remote case, `write-region'
;; raises also an `attribute-changed' event.
((or (string-equal (file-notify--test-library) "kqueue")
@@ -865,9 +887,9 @@ delivered."
(write-region
"any text" nil file-notify--test-tmpfile nil 'no-message)
(file-notify--test-read-event)
- (set-file-modes file-notify--test-tmpfile 000)
+ (set-file-modes file-notify--test-tmpfile 000 'nofollow)
(file-notify--test-read-event)
- (set-file-times file-notify--test-tmpfile '(0 0))
+ (set-file-times file-notify--test-tmpfile '(0 0) 'nofollow)
(file-notify--test-read-event)
(delete-file file-notify--test-tmpfile))
(file-notify-rm-watch file-notify--test-desc)
@@ -888,6 +910,7 @@ delivered."
(ert-deftest file-notify-test04-autorevert ()
"Check autorevert via file notification."
+ :tags '(:expensive-test)
(skip-unless (file-notify--test-local-enabled))
;; `auto-revert-buffers' runs every 5". And we must wait, until the
@@ -921,6 +944,10 @@ delivered."
;; timeouts.
(setq file-notify--test-desc auto-revert-notify-watch-descriptor)
+ ;; GKqueueFileMonitor does not report the `changed' event.
+ (skip-unless
+ (not (equal (file-notify--test-monitor) 'GKqueueFileMonitor)))
+
;; Check, that file notification has been used.
(should auto-revert-mode)
(should auto-revert-use-notify)
@@ -929,17 +956,18 @@ delivered."
;; Modify file. We wait for a second, in order to have
;; another timestamp.
(ert-with-message-capture captured-messages
- (sleep-for 1)
- (write-region
- "another text" nil file-notify--test-tmpfile nil 'no-message)
-
- ;; Check, that the buffer has been reverted.
- (file-notify--test-wait-for-events
- timeout
- (string-match
- (format-message "Reverting buffer `%s'." (buffer-name buf))
- captured-messages))
- (should (string-match "another text" (buffer-string))))
+ (let ((inhibit-message t))
+ (sleep-for 1)
+ (write-region
+ "another text" nil file-notify--test-tmpfile nil 'no-message)
+
+ ;; Check, that the buffer has been reverted.
+ (file-notify--test-wait-for-events
+ timeout
+ (string-match
+ (format-message "Reverting buffer `%s'." (buffer-name buf))
+ captured-messages))
+ (should (string-match "another text" (buffer-string)))))
;; Stop file notification. Autorevert shall still work via polling.
(file-notify-rm-watch auto-revert-notify-watch-descriptor)
@@ -951,19 +979,20 @@ delivered."
;; Modify file. We wait for two seconds, in order to
;; have another timestamp. One second seems to be too
- ;; short. And Cygwin sporadically requires more than two.
+ ;; short. And cygwin sporadically requires more than two.
(ert-with-message-capture captured-messages
- (sleep-for (if (eq system-type 'cygwin) 3 2))
- (write-region
- "foo bla" nil file-notify--test-tmpfile nil 'no-message)
-
- ;; Check, that the buffer has been reverted.
- (file-notify--test-wait-for-events
- timeout
- (string-match
- (format-message "Reverting buffer `%s'." (buffer-name buf))
- captured-messages))
- (should (string-match "foo bla" (buffer-string))))
+ (let ((inhibit-message t))
+ (sleep-for (if (eq system-type 'cygwin) 3 2))
+ (write-region
+ "foo bla" nil file-notify--test-tmpfile nil 'no-message)
+
+ ;; Check, that the buffer has been reverted.
+ (file-notify--test-wait-for-events
+ timeout
+ (string-match
+ (format-message "Reverting buffer `%s'." (buffer-name buf))
+ captured-messages))
+ (should (string-match "foo bla" (buffer-string)))))
;; Stop autorevert, in order to cleanup descriptor.
(auto-revert-mode -1))
@@ -981,6 +1010,7 @@ delivered."
(ert-deftest file-notify-test05-file-validity ()
"Check `file-notify-valid-p' for files."
+ :tags '(:expensive-test)
(skip-unless (file-notify--test-local-enabled))
(unwind-protect
@@ -1021,6 +1051,9 @@ delivered."
((string-equal (file-notify--test-library) "gvfs-monitor-dir.exe")
'((deleted stopped)
(changed deleted stopped)))
+ ;; GKqueueFileMonitor does not report the `changed' event.
+ ((equal (file-notify--test-monitor) 'GKqueueFileMonitor)
+ '(deleted stopped))
;; There could be one or two `changed' events.
(t '((changed deleted stopped)
(changed changed deleted stopped))))
@@ -1070,6 +1103,9 @@ delivered."
'(created deleted stopped))
((string-equal (file-notify--test-library) "kqueue")
'(created changed deleted stopped))
+ ;; GKqueueFileMonitor does not report the `changed' event.
+ ((equal (file-notify--test-monitor) 'GKqueueFileMonitor)
+ '(created deleted deleted stopped))
(t '(created changed deleted deleted stopped)))
(write-region
"any text" nil file-notify--test-tmpfile nil 'no-message)
@@ -1233,6 +1269,7 @@ delivered."
(ert-deftest file-notify-test08-backup ()
"Check that backup keeps file notification."
+ :tags '(:expensive-test)
(skip-unless (file-notify--test-local-enabled))
(unwind-protect
@@ -1246,9 +1283,12 @@ delivered."
'(change) #'file-notify--test-event-handler)))
(should (file-notify-valid-p file-notify--test-desc))
(file-notify--test-with-actions
- ;; There could be one or two `changed' events.
- '((changed)
- (changed changed))
+ (cond
+ ;; GKqueueFileMonitor does not report the `changed' event.
+ ((equal (file-notify--test-monitor) 'GKqueueFileMonitor) nil)
+ ;; There could be one or two `changed' events.
+ (t '((changed)
+ (changed changed))))
;; There shouldn't be any problem, because the file is kept.
(with-temp-buffer
(let ((buffer-file-name file-notify--test-tmpfile)
@@ -1286,6 +1326,9 @@ delivered."
;; On cygwin we only get the `changed' event.
((eq system-type 'cygwin)
'(changed))
+ ;; GKqueueFileMonitor does not report the `changed' event.
+ ((equal (file-notify--test-monitor) 'GKqueueFileMonitor)
+ '(renamed created))
(t '(renamed created changed)))
;; The file is renamed when creating a backup. It shall
;; still be watched.
@@ -1383,7 +1426,12 @@ the file watch."
(make-list (/ n 2) 'changed)
;; Just the directory monitor.
(make-list (/ n 2) 'created)
- (make-list (/ n 2) 'changed)))
+ (make-list (/ n 2) 'changed))
+ (append
+ '(:random)
+ ;; Just the directory monitor. GKqueueFileMonitor
+ ;; does not report the `changed' event.
+ (make-list (/ n 2) 'created)))
(dotimes (i n)
(file-notify--test-read-event)
(if (zerop (mod i 2))
diff --git a/test/data/files-bug18141.el.gz b/test/lisp/files-resources/files-bug18141.el.gz
index 53d463e85b5..53d463e85b5 100644
--- a/test/data/files-bug18141.el.gz
+++ b/test/lisp/files-resources/files-bug18141.el.gz
Binary files differ
diff --git a/test/lisp/files-tests.el b/test/lisp/files-tests.el
index 1fc80073529..149cc689ae9 100644
--- a/test/lisp/files-tests.el
+++ b/test/lisp/files-tests.el
@@ -20,6 +20,7 @@
;;; Code:
(require 'ert)
+(require 'ert-x)
(require 'nadvice)
(eval-when-compile (require 'cl-lib))
(require 'bytecomp) ; `byte-compiler-base-file-name'.
@@ -151,7 +152,7 @@ form.")
(should (file-test--do-local-variables-test str subtest)))))))
(defvar files-test-bug-18141-file
- (expand-file-name "data/files-bug18141.el.gz" (getenv "EMACS_TEST_DIRECTORY"))
+ (ert-resource-file "files-bug18141.el.gz")
"Test file for bug#18141.")
(ert-deftest files-tests-bug-18141 ()
@@ -190,7 +191,6 @@ form.")
(ert-deftest files-tests-bug-21454 ()
"Test for https://debbugs.gnu.org/21454 ."
- :expected-result :failed
(let ((input-result
'(("/foo/bar//baz/:/bar/foo/baz//" nil ("/foo/bar/baz/" "/bar/foo/baz/"))
("/foo/bar/:/bar/qux/:/qux/foo" nil ("/foo/bar/" "/bar/qux/" "/qux/foo/"))
@@ -1003,9 +1003,9 @@ unquoted file names."
(ert-deftest files-tests-file-name-non-special-set-file-times ()
(files-tests--with-temp-non-special (tmpfile nospecial)
- (set-file-times nospecial))
+ (set-file-times nospecial nil 'nofollow))
(files-tests--with-temp-non-special-and-file-name-handler (tmpfile nospecial)
- (should-error (set-file-times nospecial))))
+ (should-error (set-file-times nospecial nil 'nofollow))))
(ert-deftest files-tests-file-name-non-special-set-visited-file-modtime ()
(files-tests--with-temp-non-special (tmpfile nospecial)
@@ -1164,6 +1164,42 @@ works as expected if the default directory is quoted."
(should-not (make-directory a/b t))
(delete-directory dir 'recursive)))
+(ert-deftest files-tests-file-modes-symbolic-to-number ()
+ (let ((alist (list (cons "a=rwx" #o777)
+ (cons "o=t" #o1000)
+ (cons "o=xt" #o1001)
+ (cons "o=tx" #o1001) ; Order doesn't matter.
+ (cons "u=rwx,g=rx,o=rx" #o755)
+ (cons "u=rwx,g=,o=" #o700)
+ (cons "u=rwx" #o700) ; Empty permissions can be ignored.
+ (cons "u=rw,g=r,o=r" #o644)
+ (cons "u=rw,g=r,o=t" #o1640)
+ (cons "u=rw,g=r,o=xt" #o1641)
+ (cons "u=rwxs,g=rs,o=xt" #o7741)
+ (cons "u=rws,g=rs,o=t" #o7640)
+ (cons "u=rws,g=rs,o=r" #o6644)
+ (cons "a=r" #o444)
+ (cons "u=S" nil)
+ (cons "u=T" nil)
+ (cons "u=Z" nil))))
+ (dolist (x alist)
+ (if (cdr-safe x)
+ (should (equal (cdr x) (file-modes-symbolic-to-number (car x))))
+ (should-error (file-modes-symbolic-to-number (car x)))))))
+
+(ert-deftest files-tests-file-modes-number-to-symbolic ()
+ (let ((alist (list (cons #o755 "-rwxr-xr-x")
+ (cons #o700 "-rwx------")
+ (cons #o644 "-rw-r--r--")
+ (cons #o1640 "-rw-r----T")
+ (cons #o1641 "-rw-r----t")
+ (cons #o7741 "-rwsr-S--t")
+ (cons #o7640 "-rwSr-S--T")
+ (cons #o6644 "-rwSr-Sr--")
+ (cons #o444 "-r--r--r--"))))
+ (dolist (x alist)
+ (should (equal (cdr x) (file-modes-number-to-symbolic (car x)))))))
+
(ert-deftest files-tests-no-file-write-contents ()
"Test that `write-contents-functions' permits saving a file.
Usually `basic-save-buffer' will prompt for a file name if the
@@ -1326,5 +1362,75 @@ See <https://debbugs.gnu.org/36401>."
(normal-mode)
(should (not (eq major-mode 'text-mode))))))
+(ert-deftest files-colon-path ()
+ (should (equal (parse-colon-path "/foo//bar/baz")
+ '("/foo/bar/baz/"))))
+
+(ert-deftest files-test-magic-mode-alist-doctype ()
+ "Test that DOCTYPE and variants put files in mhtml-mode."
+ (with-temp-buffer
+ (goto-char (point-min))
+ (insert "<!DOCTYPE html>")
+ (normal-mode)
+ (should (eq major-mode 'mhtml-mode))
+ (erase-buffer)
+ (insert "<!doctype html>")
+ (normal-mode)
+ (should (eq major-mode 'mhtml-mode))))
+
+(defvar files-tests-lao "The Way that can be told of is not the eternal Way;
+The name that can be named is not the eternal name.
+The Nameless is the origin of Heaven and Earth;
+The Named is the mother of all things.
+Therefore let there always be non-being,
+ so we may see their subtlety,
+And let there always be being,
+ so we may see their outcome.
+The two are the same,
+But after they are produced,
+ they have different names.
+")
+
+(defvar files-tests-tzu "The Nameless is the origin of Heaven and Earth;
+The named is the mother of all things.
+
+Therefore let there always be non-being,
+ so we may see their subtlety,
+And let there always be being,
+ so we may see their outcome.
+The two are the same,
+But after they are produced,
+ they have different names.
+They both may be called deep and profound.
+Deeper and more profound,
+The door of all subtleties!
+")
+
+(ert-deftest files-tests-revert-buffer ()
+ "Test that revert-buffer is successful."
+ (files-tests--with-temp-file temp-file-name
+ (with-temp-buffer
+ (insert files-tests-lao)
+ (write-file temp-file-name)
+ (erase-buffer)
+ (insert files-tests-tzu)
+ (revert-buffer t t t)
+ (should (compare-strings files-tests-lao nil nil
+ (buffer-substring (point-min) (point-max))
+ nil nil)))))
+
+(ert-deftest files-tests-revert-buffer-with-fine-grain ()
+ "Test that revert-buffer-with-fine-grain is successful."
+ (files-tests--with-temp-file temp-file-name
+ (with-temp-buffer
+ (insert files-tests-lao)
+ (write-file temp-file-name)
+ (erase-buffer)
+ (insert files-tests-tzu)
+ (should (revert-buffer-with-fine-grain t t))
+ (should (compare-strings files-tests-lao nil nil
+ (buffer-substring (point-min) (point-max))
+ nil nil)))))
+
(provide 'files-tests)
;;; files-tests.el ends here
diff --git a/test/lisp/files-x-tests.el b/test/lisp/files-x-tests.el
index 8830f12e58c..e97e2c325ec 100644
--- a/test/lisp/files-x-tests.el
+++ b/test/lisp/files-x-tests.el
@@ -1,4 +1,4 @@
-;;; files-x-tests.el --- tests for files-x.el.
+;;; files-x-tests.el --- tests for files-x.el. -*- lexical-binding: t -*-
;; Copyright (C) 2016-2021 Free Software Foundation, Inc.
@@ -35,6 +35,7 @@
'((remote-null-device . "/dev/null")))
(defconst files-x-test--variables4
'((remote-null-device . "null")))
+(defvar remote-null-device)
(put 'remote-shell-file-name 'safe-local-variable #'identity)
(put 'remote-shell-command-switch 'safe-local-variable #'identity)
(put 'remote-shell-interactive-switch 'safe-local-variable #'identity)
@@ -273,7 +274,8 @@
(should-not (local-variable-p 'remote-shell-file-name))
(should-not (boundp 'remote-shell-file-name))))))
-(defvar tramp-connection-local-default-profile)
+(defvar tramp-connection-local-default-shell-variables)
+(defvar tramp-connection-local-default-system-variables)
(ert-deftest files-x-test-with-connection-local-variables ()
"Test setting connection-local variables."
@@ -334,7 +336,10 @@
(append
(nreverse (copy-tree files-x-test--variables3))
(nreverse (copy-tree files-x-test--variables2))
- (nreverse (copy-tree tramp-connection-local-default-profile)))))
+ (nreverse
+ (copy-tree tramp-connection-local-default-shell-variables))
+ (nreverse
+ (copy-tree tramp-connection-local-default-system-variables)))))
;; The variables exist also as local variables.
(should (local-variable-p 'remote-shell-file-name))
(should (local-variable-p 'remote-null-device))
diff --git a/test/lisp/format-spec-tests.el b/test/lisp/format-spec-tests.el
index 452b445413f..ff2abdeaad5 100644
--- a/test/lisp/format-spec-tests.el
+++ b/test/lisp/format-spec-tests.el
@@ -22,22 +22,145 @@
(require 'ert)
(require 'format-spec)
-(ert-deftest test-format-spec ()
+(ert-deftest format-spec-make ()
+ "Test `format-spec-make'."
+ (should-not (format-spec-make))
+ (should-error (format-spec-make ?b))
+ (should (equal (format-spec-make ?b "b") '((?b . "b"))))
+ (should-error (format-spec-make ?b "b" ?a))
+ (should (equal (format-spec-make ?b "b" ?a 'a)
+ '((?b . "b")
+ (?a . a)))))
+
+(ert-deftest format-spec-parse-flags ()
+ "Test `format-spec--parse-flags'."
+ (should-not (format-spec--parse-flags nil))
+ (should-not (format-spec--parse-flags ""))
+ (should (equal (format-spec--parse-flags "-") '(:pad-right)))
+ (should (equal (format-spec--parse-flags " 0") '(:pad-zero)))
+ (should (equal (format-spec--parse-flags " -x0y< >^_z ")
+ '(:pad-right :pad-zero :chop-left :chop-right
+ :upcase :downcase))))
+
+(ert-deftest format-spec-do-flags ()
+ "Test `format-spec--do-flags'."
+ (should (equal (format-spec--do-flags "" () nil nil) ""))
+ (dolist (flag '(:pad-zero :pad-right :upcase :downcase
+ :chop-left :chop-right))
+ (should (equal (format-spec--do-flags "" (list flag) nil nil) "")))
+ (should (equal (format-spec--do-flags "FOOBAR" '(:downcase :chop-right) 5 2)
+ " fo"))
+ (should (equal (format-spec--do-flags
+ "foobar" '(:pad-zero :pad-right :upcase :chop-left) 5 2)
+ "AR000")))
+
+(ert-deftest format-spec-do-flags-truncate ()
+ "Test `format-spec--do-flags' truncation."
+ (let (flags)
+ (should (equal (format-spec--do-flags "" flags nil 0) ""))
+ (should (equal (format-spec--do-flags "" flags nil 1) ""))
+ (should (equal (format-spec--do-flags "a" flags nil 0) ""))
+ (should (equal (format-spec--do-flags "a" flags nil 1) "a"))
+ (should (equal (format-spec--do-flags "a" flags nil 2) "a"))
+ (should (equal (format-spec--do-flags "asd" flags nil 0) ""))
+ (should (equal (format-spec--do-flags "asd" flags nil 1) "a")))
+ (let ((flags '(:chop-left)))
+ (should (equal (format-spec--do-flags "" flags nil 0) ""))
+ (should (equal (format-spec--do-flags "" flags nil 1) ""))
+ (should (equal (format-spec--do-flags "a" flags nil 0) ""))
+ (should (equal (format-spec--do-flags "a" flags nil 1) "a"))
+ (should (equal (format-spec--do-flags "a" flags nil 2) "a"))
+ (should (equal (format-spec--do-flags "asd" flags nil 0) ""))
+ (should (equal (format-spec--do-flags "asd" flags nil 1) "d"))))
+
+(ert-deftest format-spec-do-flags-pad ()
+ "Test `format-spec--do-flags' padding."
+ (let (flags)
+ (should (equal (format-spec--do-flags "" flags 0 nil) ""))
+ (should (equal (format-spec--do-flags "" flags 1 nil) " "))
+ (should (equal (format-spec--do-flags "a" flags 0 nil) "a"))
+ (should (equal (format-spec--do-flags "a" flags 1 nil) "a"))
+ (should (equal (format-spec--do-flags "a" flags 2 nil) " a")))
+ (let ((flags '(:pad-zero)))
+ (should (equal (format-spec--do-flags "" flags 0 nil) ""))
+ (should (equal (format-spec--do-flags "" flags 1 nil) "0"))
+ (should (equal (format-spec--do-flags "a" flags 0 nil) "a"))
+ (should (equal (format-spec--do-flags "a" flags 1 nil) "a"))
+ (should (equal (format-spec--do-flags "a" flags 2 nil) "0a")))
+ (let ((flags '(:pad-right)))
+ (should (equal (format-spec--do-flags "" flags 0 nil) ""))
+ (should (equal (format-spec--do-flags "" flags 1 nil) " "))
+ (should (equal (format-spec--do-flags "a" flags 0 nil) "a"))
+ (should (equal (format-spec--do-flags "a" flags 1 nil) "a"))
+ (should (equal (format-spec--do-flags "a" flags 2 nil) "a ")))
+ (let ((flags '(:pad-right :pad-zero)))
+ (should (equal (format-spec--do-flags "" flags 0 nil) ""))
+ (should (equal (format-spec--do-flags "" flags 1 nil) "0"))
+ (should (equal (format-spec--do-flags "a" flags 0 nil) "a"))
+ (should (equal (format-spec--do-flags "a" flags 1 nil) "a"))
+ (should (equal (format-spec--do-flags "a" flags 2 nil) "a0"))))
+
+(ert-deftest format-spec-do-flags-chop ()
+ "Test `format-spec--do-flags' chopping."
+ (let ((flags '(:chop-left)))
+ (should (equal (format-spec--do-flags "a" flags 0 nil) ""))
+ (should (equal (format-spec--do-flags "a" flags 1 nil) "a"))
+ (should (equal (format-spec--do-flags "asd" flags 0 nil) ""))
+ (should (equal (format-spec--do-flags "asd" flags 1 nil) "d")))
+ (let ((flags '(:chop-right)))
+ (should (equal (format-spec--do-flags "a" flags 0 nil) ""))
+ (should (equal (format-spec--do-flags "a" flags 1 nil) "a"))
+ (should (equal (format-spec--do-flags "asd" flags 0 nil) ""))
+ (should (equal (format-spec--do-flags "asd" flags 1 nil) "a"))))
+
+(ert-deftest format-spec-do-flags-case ()
+ "Test `format-spec--do-flags' case fiddling."
+ (dolist (flag '(:pad-zero :pad-right :chop-left :chop-right))
+ (let ((flags (list flag)))
+ (should (equal (format-spec--do-flags "a" flags nil nil) "a"))
+ (should (equal (format-spec--do-flags "A" flags nil nil) "A")))
+ (let ((flags (list flag :downcase)))
+ (should (equal (format-spec--do-flags "a" flags nil nil) "a"))
+ (should (equal (format-spec--do-flags "A" flags nil nil) "a")))
+ (let ((flags (list flag :upcase)))
+ (should (equal (format-spec--do-flags "a" flags nil nil) "A"))
+ (should (equal (format-spec--do-flags "A" flags nil nil) "A")))))
+
+(ert-deftest format-spec ()
+ (should (equal (format-spec "" ()) ""))
+ (should (equal (format-spec "a" ()) "a"))
+ (should (equal (format-spec "b" '((?b . "bar"))) "b"))
+ (should (equal (format-spec "%%%b%%b%b%%" '((?b . "bar"))) "%bar%bbar%"))
(should (equal (format-spec "foo %b zot" `((?b . "bar")))
"foo bar zot"))
(should (equal (format-spec "foo %-10b zot" '((?b . "bar")))
"foo bar zot"))
(should (equal (format-spec "foo %10b zot" '((?b . "bar")))
- "foo bar zot")))
+ "foo bar zot"))
+ (should (equal-including-properties
+ (format-spec (propertize "a" 'a 'b) '((?a . "foo")))
+ #("a" 0 1 (a b))))
+ (let ((fmt (concat (propertize "%a" 'a 'b)
+ (propertize "%%" 'c 'd)
+ "%b"
+ (propertize "%b" 'e 'f))))
+ (should (equal-including-properties
+ (format-spec fmt '((?b . "asd") (?a . "fgh")))
+ #("fgh%asdasd" 0 3 (a b) 3 4 (c d) 7 10 (e f))))))
-(ert-deftest test-format-unknown ()
+(ert-deftest format-spec-unknown ()
(should-error (format-spec "foo %b %z zot" '((?b . "bar"))))
+ (should-error (format-spec "foo %b %%%z zot" '((?b . "bar"))))
(should (equal (format-spec "foo %b %z zot" '((?b . "bar")) t)
"foo bar %z zot"))
- (should (equal (format-spec "foo %b %z %% zot" '((?b . "bar")) t)
- "foo bar %z %% zot")))
+ (should (equal (format-spec "foo %4b %%%4z %%4 zot" '((?b . "bar")) t)
+ "foo bar %%%4z %%4 zot"))
+ (should (equal (format-spec "foo %4b %%%4z %%4 zot" '((?b . "bar")) 'ignore)
+ "foo bar %%4z %4 zot"))
+ (should (equal (format-spec "foo %4b %%%4z %%4 zot" '((?b . "bar")) 'delete)
+ "foo bar % %4 zot")))
-(ert-deftest test-format-modifiers ()
+(ert-deftest format-spec-flags ()
(should (equal (format-spec "foo %10b zot" '((?b . "bar")))
"foo bar zot"))
(should (equal (format-spec "foo % 10b zot" '((?b . "bar")))
@@ -55,4 +178,14 @@
(should (equal (format-spec "foo %>4b zot" '((?b . "longbar")))
"foo long zot")))
+(ert-deftest format-spec-split ()
+ (should (equal (format-spec "foo %b bar" '((?b . "zot")) nil t)
+ '("foo " "zot" " bar")))
+ (should (equal (format-spec "%b bar" '((?b . "zot")) nil t)
+ '("zot" " bar")))
+ (should (equal (format-spec "%b" '((?b . "zot")) nil t)
+ '("zot")))
+ (should (equal (format-spec "foo %b" '((?b . "zot")) nil t)
+ '("foo " "zot"))))
+
;;; format-spec-tests.el ends here
diff --git a/test/lisp/gnus/gnus-icalendar-tests.el b/test/lisp/gnus/gnus-icalendar-tests.el
new file mode 100644
index 00000000000..90c3a34a5c0
--- /dev/null
+++ b/test/lisp/gnus/gnus-icalendar-tests.el
@@ -0,0 +1,259 @@
+;;; gnus-icalendar-tests.el --- tests -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+;; Author: Jan Tatarik <jan.tatarik@gmail.com>
+;; Keywords:
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'ert)
+(require 'gnus-icalendar)
+
+
+(defun gnus-icalendar-tests--get-ical-event (ical-string &optional participant)
+ "Return gnus-icalendar event for ICAL-STRING."
+ (let (event)
+ (with-temp-buffer
+ (insert ical-string)
+ (setq event (gnus-icalendar-event-from-buffer (buffer-name) participant)))
+ event))
+
+(ert-deftest gnus-icalendar-parse ()
+ "test"
+ (let ((tz (getenv "TZ"))
+ (event (gnus-icalendar-tests--get-ical-event "\
+BEGIN:VCALENDAR
+PRODID:-//Google Inc//Google Calendar 70.9054//EN
+VERSION:2.0
+CALSCALE:GREGORIAN
+METHOD:REQUEST
+BEGIN:VTIMEZONE
+TZID:America/New_York
+X-LIC-LOCATION:America/New_York
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+TZNAME:EDT
+DTSTART:19700308T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+TZNAME:EST
+DTSTART:19701101T020000
+RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTART;TZID=America/New_York:20201208T090000
+DTEND;TZID=America/New_York:20201208T100000
+DTSTAMP:20200728T182853Z
+ORGANIZER;CN=Company Events:mailto:anoncompany.com_3bm6fh805bme9uoeliqcle1sa
+ g@group.calendar.google.com
+UID:iipdt88slddpeu7hheuu09sfmd@google.com
+X-MICROSOFT-CDO-OWNERAPPTID:-362490173
+RECURRENCE-ID;TZID=America/New_York:20201208T091500
+CREATED:20200309T134939Z
+DESCRIPTION:In this meeting\\, we will cover topics from product and enginee
+ ring presentations and demos to new hire announcements to watching the late
+LAST-MODIFIED:20200728T182852Z
+LOCATION:New York-22-Town Hall Space (250) [Chrome Box]
+SEQUENCE:4
+STATUS:CONFIRMED
+SUMMARY:Townhall | All Company Meeting
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
+")))
+
+ (unwind-protect
+ (progn
+ ;; Use this form so as not to rely on system tz database.
+ ;; Eg hydra.nixos.org.
+ (setenv "TZ" "CET-1CEST,M3.5.0/2,M10.5.0/3")
+ (should (eq (eieio-object-class event) 'gnus-icalendar-event-request))
+ (should (not (gnus-icalendar-event:recurring-p event)))
+ (should (string= (gnus-icalendar-event:start event) "2020-12-08 15:00"))
+ (with-slots (organizer summary description location end-time uid rsvp participation-type) event
+ (should (string= organizer "anoncompany.com_3bm6fh805bme9uoeliqcle1sag@group.calendar.google.com"))
+ (should (string= summary "Townhall | All Company Meeting"))
+ (should (string= description "In this meeting, we will cover topics from product and engineering presentations and demos to new hire announcements to watching the late"))
+ (should (string= location "New York-22-Town Hall Space (250) [Chrome Box]"))
+ (should (string= (format-time-string "%Y-%m-%d %H:%M" end-time) "2020-12-08 16:00"))
+ (should (string= uid "iipdt88slddpeu7hheuu09sfmd@google.com"))
+ (should (not rsvp))
+ (should (eq participation-type 'non-participant))))
+ (setenv "TZ" tz))))
+
+(ert-deftest gnus-icalendary-byday ()
+ ""
+ (let ((tz (getenv "TZ"))
+ (event (gnus-icalendar-tests--get-ical-event "\
+BEGIN:VCALENDAR
+PRODID:Zimbra-Calendar-Provider
+VERSION:2.0
+METHOD:REQUEST
+BEGIN:VTIMEZONE
+TZID:America/New_York
+BEGIN:STANDARD
+DTSTART:16010101T020000
+TZOFFSETTO:-0500
+TZOFFSETFROM:-0400
+RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=11;BYDAY=1SU
+TZNAME:EST
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:16010101T020000
+TZOFFSETTO:-0400
+TZOFFSETFROM:-0500
+RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=3;BYDAY=2SU
+TZNAME:EDT
+END:DAYLIGHT
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:903a5415-9067-4f63-b499-1b6205f49c88
+RRULE:FREQ=DAILY;UNTIL=20200825T035959Z;INTERVAL=1;BYDAY=MO,TU,WE,TH,FR
+SUMMARY:appointment every weekday\\, start jul 24\\, 2020\\, end aug 24\\, 2020
+ATTENDEE;CN=Mark Hershberger;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP
+ =TRUE:mailto:hexmode <at> gmail.com
+ORGANIZER;CN=Mark A. Hershberger:mailto:mah <at> nichework.com
+DTSTART;TZID=\"America/New_York\":20200724T090000
+DTEND;TZID=\"America/New_York\":20200724T093000
+STATUS:CONFIRMED
+CLASS:PUBLIC
+X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY
+TRANSP:OPAQUE
+LAST-MODIFIED:20200719T150815Z
+DTSTAMP:20200719T150815Z
+SEQUENCE:0
+DESCRIPTION:The following is a new meeting request:
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER;RELATED=START:-PT5M
+DESCRIPTION:Reminder
+END:VALARM
+END:VEVENT
+END:VCALENDAR" (list "Mark Hershberger"))))
+
+ (unwind-protect
+ (progn
+ ;; Use this form so as not to rely on system tz database.
+ ;; Eg hydra.nixos.org.
+ (setenv "TZ" "CET-1CEST,M3.5.0/2,M10.5.0/3")
+ (should (eq (eieio-object-class event) 'gnus-icalendar-event-request))
+ (should (gnus-icalendar-event:recurring-p event))
+ (should (string= (gnus-icalendar-event:recurring-interval event) "1"))
+ (should (string= (gnus-icalendar-event:start event) "2020-07-24 15:00"))
+ (with-slots (organizer summary description location end-time uid rsvp participation-type) event
+ (should (string= organizer "mah <at> nichework.com"))
+ (should (string= summary "appointment every weekday, start jul 24, 2020, end aug 24, 2020"))
+ (should (string= description "The following is a new meeting request:"))
+ (should (null location))
+ (should (string= (format-time-string "%Y-%m-%d %H:%M" end-time) "2020-07-24 15:30"))
+ (should (string= uid "903a5415-9067-4f63-b499-1b6205f49c88"))
+ (should rsvp)
+ (should (eq participation-type 'required)))
+ (should (equal (gnus-icalendar-event:recurring-days event) '(1 2 3 4 5)))
+ (should (string= (gnus-icalendar-event:org-timestamp event) "<2020-07-24 15:00-15:30 +1w>
+<2020-07-27 15:00-15:30 +1w>
+<2020-07-28 15:00-15:30 +1w>
+<2020-07-29 15:00-15:30 +1w>
+<2020-07-30 15:00-15:30 +1w>")))
+ (setenv "TZ" tz))))
+
+(ert-deftest gnus-icalendary-weekly-byday ()
+ ""
+ (let ((tz (getenv "TZ"))
+ (event (gnus-icalendar-tests--get-ical-event "\
+BEGIN:VCALENDAR
+PRODID:-//Google Inc//Google Calendar 70.9054//EN
+VERSION:2.0
+CALSCALE:GREGORIAN
+METHOD:REQUEST
+BEGIN:VTIMEZONE
+TZID:Europe/Berlin
+X-LIC-LOCATION:Europe/Berlin
+BEGIN:DAYLIGHT
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0200
+TZNAME:CEST
+DTSTART:19700329T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:+0200
+TZOFFSETTO:+0100
+TZNAME:CET
+DTSTART:19701025T030000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTART;TZID=Europe/Berlin:20200915T140000
+DTEND;TZID=Europe/Berlin:20200915T143000
+RRULE:FREQ=WEEKLY;BYDAY=FR,MO,TH,TU,WE
+DTSTAMP:20200915T120627Z
+ORGANIZER;CN=anon@anoncompany.com:mailto:anon@anoncompany.com
+UID:7b6g3m7iftuo90ei4ul00feqn_R20200915T120000@google.com
+ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;RSVP=TRUE
+ ;CN=participant@anoncompany.com;X-NUM-GUESTS=0:mailto:participant@anoncompany.com
+CREATED:20200325T095723Z
+DESCRIPTION:Coffee talk
+LAST-MODIFIED:20200915T120623Z
+LOCATION:
+SEQUENCE:0
+STATUS:CONFIRMED
+SUMMARY:Casual coffee talk
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR" (list "participant@anoncompany.com"))))
+
+ (unwind-protect
+ (progn
+ ;; Use this form so as not to rely on system tz database.
+ ;; Eg hydra.nixos.org.
+ (setenv "TZ" "CET-1CEST,M3.5.0/2,M10.5.0/3")
+ (should (eq (eieio-object-class event) 'gnus-icalendar-event-request))
+ (should (gnus-icalendar-event:recurring-p event))
+ (should (string= (gnus-icalendar-event:recurring-interval event) "1"))
+ (should (string= (gnus-icalendar-event:start event) "2020-09-15 14:00"))
+ (with-slots (organizer summary description location end-time uid rsvp participation-type) event
+ (should (string= organizer "anon@anoncompany.com"))
+ (should (string= summary "Casual coffee talk"))
+ (should (string= description "Coffee talk"))
+ (should (string= location ""))
+ (should (string= (format-time-string "%Y-%m-%d %H:%M" end-time) "2020-09-15 14:30"))
+ (should (string= uid "7b6g3m7iftuo90ei4ul00feqn_R20200915T120000@google.com"))
+ (should rsvp)
+ (should (eq participation-type 'required)))
+ (should (equal (sort (gnus-icalendar-event:recurring-days event) #'<) '(1 2 3 4 5)))
+ (should (string= (gnus-icalendar-event:org-timestamp event) "<2020-09-15 14:00-14:30 +1w>
+<2020-09-16 14:00-14:30 +1w>
+<2020-09-17 14:00-14:30 +1w>
+<2020-09-18 14:00-14:30 +1w>
+<2020-09-21 14:00-14:30 +1w>")))
+ (setenv "TZ" tz))))
+
+(provide 'gnus-icalendar-tests)
+;;; gnus-icalendar-tests.el ends here
diff --git a/test/lisp/gnus/gnus-search-tests.el b/test/lisp/gnus/gnus-search-tests.el
new file mode 100644
index 00000000000..63469f8d518
--- /dev/null
+++ b/test/lisp/gnus/gnus-search-tests.el
@@ -0,0 +1,96 @@
+;;; gnus-search-tests.el --- Tests for Gnus' search routines -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2017, 2021 Free Software Foundation, Inc.
+
+;; Author: Eric Abrahamsen <eric@ericabrahamsen.net>
+;; Keywords:
+
+;; This program 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.
+
+;; This program 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 <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Tests for the search parsing, search engines, and their
+;; transformations.
+
+;;; Code:
+
+(require 'ert)
+(require 'gnus-search)
+
+(ert-deftest gnus-s-parse ()
+ "Test basic structural parsing."
+ (let ((pairs
+ '(("string" . ("string"))
+ ("from:john" . ((from . "john")))
+ ("here and there" . ("here" and "there"))
+ ("here or there" . ((or "here" "there")))
+ ("here (there or elsewhere)" . ("here" ((or "there" "elsewhere"))))
+ ("here not there" . ("here" (not "there")))
+ ("from:boss or not vacation" . ((or (from . "boss") (not "vacation")))))))
+ (dolist (p pairs)
+ (should (equal (gnus-search-parse-query (car p)) (cdr p))))))
+
+(ert-deftest gnus-s-expand-keyword ()
+ "Test expansion of keywords"
+ (let ((gnus-search-expandable-keys
+ (default-value 'gnus-search-expandable-keys))
+ (pairs
+ '(("su" . "subject")
+ ("sin" . "since"))))
+ (dolist (p pairs)
+ (should (equal (gnus-search-query-expand-key (car p))
+ (cdr p))))
+ (should-error (gnus-search-query-expand-key "s")
+ :type 'gnus-search-parse-error)))
+
+(ert-deftest gnus-s-parse-date ()
+ "Test parsing of date expressions."
+ (let ((rel-date (encode-time 0 0 0 15 4 2017))
+ (pairs
+ '(("January" . (nil 1 nil))
+ ("2017" . (nil nil 2017))
+ ("15" . (15 nil nil))
+ ("January 15" . (15 1 nil))
+ ("tuesday" . (11 4 2017))
+ ("1d" . (14 4 2017))
+ ("1w" . (8 4 2017)))))
+ (dolist (p pairs)
+ (should (equal (gnus-search-query-parse-date (car p) rel-date)
+ (cdr p))))))
+
+(ert-deftest gnus-s-delimited-string ()
+ "Test proper functioning of `gnus-search-query-return-string'."
+ (with-temp-buffer
+ (insert "one\ntwo words\nthree \"words with quotes\"\n\"quotes at start\"\n/alternate \"quotes\"/\n(more bits)")
+ (goto-char (point-min))
+ (should (string= (gnus-search-query-return-string)
+ "one"))
+ (forward-line)
+ (should (string= (gnus-search-query-return-string)
+ "two"))
+ (forward-line)
+ (should (string= (gnus-search-query-return-string)
+ "three"))
+ (forward-line)
+ (should (string= (gnus-search-query-return-string "\"")
+ "\"quotes at start\""))
+ (forward-line)
+ (should (string= (gnus-search-query-return-string "/")
+ "/alternate \"quotes\"/"))
+ (forward-line)
+ (should (string= (gnus-search-query-return-string ")" t)
+ "more bits"))))
+
+(provide 'gnus-search-tests)
+;;; search-tests.el ends here
diff --git a/test/lisp/gnus/gnus-tests.el b/test/lisp/gnus/gnus-tests.el
index f1f4d30622a..6602e67a347 100644
--- a/test/lisp/gnus/gnus-tests.el
+++ b/test/lisp/gnus/gnus-tests.el
@@ -1,4 +1,4 @@
-;;; gnus-tests.el --- Wrapper for the Gnus tests
+;;; gnus-tests.el --- Wrapper for the Gnus tests -*- lexical-binding:t -*-
;; Copyright (C) 2011-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/gnus/gnus-util-tests.el b/test/lisp/gnus/gnus-util-tests.el
new file mode 100644
index 00000000000..7f64b96303f
--- /dev/null
+++ b/test/lisp/gnus/gnus-util-tests.el
@@ -0,0 +1,172 @@
+;;; gnus-util-tests.el --- Selectived tests only. -*- lexical-binding:t -*-
+;; Copyright (C) 2015-2021 Free Software Foundation, Inc.
+
+;; Author: Jens Lechtenbörger <jens.lechtenboerger@fsfe.org>
+
+;; This file is not 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, 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+(require 'gnus-util)
+
+(ert-deftest gnus-string> ()
+ ;; Failure paths
+ (should-error (gnus-string> "" 1)
+ :type 'wrong-type-argument)
+ (should-error (gnus-string> "")
+ :type 'wrong-number-of-arguments)
+
+ ;; String tests
+ (should (gnus-string> "def" "abc"))
+ (should (gnus-string> 'def 'abc))
+ (should (gnus-string> "abc" "DEF"))
+ (should (gnus-string> "abc" 'DEF))
+ (should (gnus-string> "αβγ" "abc"))
+ (should (gnus-string> "אבג" "αβγ"))
+ (should (gnus-string> nil ""))
+ (should (gnus-string> "abc" ""))
+ (should (gnus-string> "abc" "ab"))
+ (should-not (gnus-string> "abc" "abc"))
+ (should-not (gnus-string> "abc" "def"))
+ (should-not (gnus-string> "DEF" "abc"))
+ (should-not (gnus-string> 'DEF "abc"))
+ (should-not (gnus-string> "123" "abc"))
+ (should-not (gnus-string> "" "")))
+
+(ert-deftest gnus-string< ()
+ ;; Failure paths
+ (should-error (gnus-string< "" 1)
+ :type 'wrong-type-argument)
+ (should-error (gnus-string< "")
+ :type 'wrong-number-of-arguments)
+
+ ;; String tests
+ (setq case-fold-search nil)
+ (should (gnus-string< "abc" "def"))
+ (should (gnus-string< 'abc 'def))
+ (should (gnus-string< "DEF" "abc"))
+ (should (gnus-string< "DEF" 'abc))
+ (should (gnus-string< "abc" "αβγ"))
+ (should (gnus-string< "αβγ" "אבג"))
+ (should (gnus-string< "" nil))
+ (should (gnus-string< "" "abc"))
+ (should (gnus-string< "ab" "abc"))
+ (should-not (gnus-string< "abc" "abc"))
+ (should-not (gnus-string< "def" "abc"))
+ (should-not (gnus-string< "abc" "DEF"))
+ (should-not (gnus-string< "abc" 'DEF))
+ (should-not (gnus-string< "abc" "123"))
+ (should-not (gnus-string< "" ""))
+
+ ;; gnus-string< checks case-fold-search
+ (setq case-fold-search t)
+ (should (gnus-string< "abc" "DEF"))
+ (should (gnus-string< "abc" 'GHI))
+ (should (gnus-string< 'abc "DEF"))
+ (should (gnus-string< 'GHI 'JKL))
+ (should (gnus-string< "abc" "ΑΒΓ"))
+ (should-not (gnus-string< "ABC" "abc"))
+ (should-not (gnus-string< "def" "ABC")))
+
+(ert-deftest gnus-subsetp ()
+ ;; False for non-lists.
+ (should-not (gnus-subsetp "1" "1"))
+ (should-not (gnus-subsetp "1" '("1")))
+ (should-not (gnus-subsetp '("1") "1"))
+
+ ;; Real tests.
+ (should (gnus-subsetp '() '()))
+ (should (gnus-subsetp '() '("1")))
+ (should (gnus-subsetp '("1") '("1")))
+ (should (gnus-subsetp '(42) '("1" 42)))
+ (should (gnus-subsetp '(42) '(42 "1")))
+ (should (gnus-subsetp '(42) '("1" 42 2)))
+ (should-not (gnus-subsetp '("1") '()))
+ (should-not (gnus-subsetp '("1") '(2)))
+ (should-not (gnus-subsetp '("1" 2) '(2)))
+ (should-not (gnus-subsetp '(2 "1") '(2)))
+ (should-not (gnus-subsetp '("1" 2) '(2 3)))
+
+ ;; Duplicates don't matter for sets.
+ (should (gnus-subsetp '("1" "1") '("1")))
+ (should (gnus-subsetp '("1" 2 "1") '(2 "1")))
+ (should (gnus-subsetp '("1" 2 "1") '(2 "1" "1" 2)))
+ (should-not (gnus-subsetp '("1" 2 "1" 3) '(2 "1" "1" 2))))
+
+(ert-deftest gnus-setdiff ()
+ ;; False for non-lists.
+ (should-not (gnus-setdiff "1" "1"))
+ (should-not (gnus-setdiff "1" '()))
+ (should-not (gnus-setdiff '() "1"))
+
+ ;; Real tests.
+ (should-not (gnus-setdiff '() '()))
+ (should-not (gnus-setdiff '() '("1")))
+ (should-not (gnus-setdiff '("1") '("1")))
+ (should (equal '("1") (gnus-setdiff '("1") '())))
+ (should (equal '("1") (gnus-setdiff '("1") '(2))))
+ (should (equal '("1") (gnus-setdiff '("1" 2) '(2))))
+ (should (equal '("1") (gnus-setdiff '("1" 2 3) '(3 2))))
+ (should (equal '("1") (gnus-setdiff '(2 "1" 3) '(3 2))))
+ (should (equal '("1") (gnus-setdiff '(2 3 "1") '(3 2))))
+ (should (equal '(2 "1") (gnus-setdiff '(2 3 "1") '(3))))
+
+ ;; Duplicates aren't touched for sets if they are not removed.
+ (should-not (gnus-setdiff '("1" "1") '("1")))
+ (should (equal '("1") (gnus-setdiff '(2 "1" 2) '(2))))
+ (should (equal '("1" "1") (gnus-setdiff '(2 "1" 2 "1") '(2)))))
+
+(ert-deftest gnus-base64-repad ()
+ (should-error (gnus-base64-repad 1)
+ :type 'wrong-type-argument)
+
+ ;; RFC4648 test vectors
+ (should (equal "" (gnus-base64-repad "")))
+ (should (equal "Zg==" (gnus-base64-repad "Zg==")))
+ (should (equal "Zm8=" (gnus-base64-repad "Zm8=")))
+ (should (equal "Zm9v" (gnus-base64-repad "Zm9v")))
+ (should (equal "Zm9vYg==" (gnus-base64-repad "Zm9vYg==")))
+ (should (equal "Zm9vYmE=" (gnus-base64-repad "Zm9vYmE=")))
+ (should (equal "Zm9vYmFy" (gnus-base64-repad "Zm9vYmFy")))
+
+ (should (equal "Zm8=" (gnus-base64-repad "Zm8")))
+ (should (equal "Zg==" (gnus-base64-repad "Zg")))
+ (should (equal "Zg==" (gnus-base64-repad "Zg====")))
+
+ (should-error (gnus-base64-repad " ")
+ :type 'error)
+ (should-error (gnus-base64-repad "Zg== ")
+ :type 'error)
+ (should-error (gnus-base64-repad "Z?\x00g==")
+ :type 'error)
+ ;; line-length
+ (should-error (gnus-base64-repad "Zg====" nil 4)
+ :type 'error)
+ ;; reject-newlines
+ (should-error (gnus-base64-repad "Zm9v\r\nYmFy" t)
+ :type 'error)
+ (should (equal "Zm9vYmFy" (gnus-base64-repad "Zm9vYmFy" t)))
+ (should (equal "Zm9vYmFy" (gnus-base64-repad "Zm9v\r\nYmFy")))
+ (should (equal "Zm9vYmFy" (gnus-base64-repad "Zm9v\r\nYmFy\n")))
+ (should (equal "Zm9vYmFy" (gnus-base64-repad "Zm9v\r\n YmFy\r\n")))
+ (should (equal "Zm9vYmFy" (gnus-base64-repad "Zm9v \r\n\tYmFy")))
+ (should-error (gnus-base64-repad "Zm9v\r\nYmFy" nil 3)
+ :type 'error))
+
+;;; gnustest-gnus-util.el ends here
diff --git a/test/data/minibuffer-test-cttq$tion b/test/lisp/gnus/mml-sec-resources/.gpg-v21-migrated
index e69de29bb2d..e69de29bb2d 100644
--- a/test/data/minibuffer-test-cttq$tion
+++ b/test/lisp/gnus/mml-sec-resources/.gpg-v21-migrated
diff --git a/test/lisp/gnus/mml-sec-resources/gpg-agent.conf b/test/lisp/gnus/mml-sec-resources/gpg-agent.conf
new file mode 100644
index 00000000000..20192990caf
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/gpg-agent.conf
@@ -0,0 +1,5 @@
+# pinentry-program /usr/bin/pinentry-gtk-2
+
+# verbose
+# log-file /tmp/gpg-agent.log
+# debug-all
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/02089CDDC6DFE93B8EA10D9E876F983E61FEC476.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/02089CDDC6DFE93B8EA10D9E876F983E61FEC476.key
new file mode 100644
index 00000000000..58fd0b5edbc
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/02089CDDC6DFE93B8EA10D9E876F983E61FEC476.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/171B444DE92BEF997229000D9784118A94EEC1C9.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/171B444DE92BEF997229000D9784118A94EEC1C9.key
new file mode 100644
index 00000000000..62f4ab25a69
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/171B444DE92BEF997229000D9784118A94EEC1C9.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/19FFEBC04DF3E037E16F6A4474DCB7984406975D.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/19FFEBC04DF3E037E16F6A4474DCB7984406975D.key
new file mode 100644
index 00000000000..2a8ce135fb2
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/19FFEBC04DF3E037E16F6A4474DCB7984406975D.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/1E36D27DF9DAB96302D35268DADC5CE73EF45A2A.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/1E36D27DF9DAB96302D35268DADC5CE73EF45A2A.key
new file mode 100644
index 00000000000..9f8de71c5e2
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/1E36D27DF9DAB96302D35268DADC5CE73EF45A2A.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/293109315BE584AB2EFEFCFCAD64666221D8B36C.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/293109315BE584AB2EFEFCFCAD64666221D8B36C.key
new file mode 100644
index 00000000000..6e4a4e548fd
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/293109315BE584AB2EFEFCFCAD64666221D8B36C.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/335689599E1C0F66D73ADCF51E03EE36C97D121F.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/335689599E1C0F66D73ADCF51E03EE36C97D121F.key
new file mode 100644
index 00000000000..cff58edaa89
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/335689599E1C0F66D73ADCF51E03EE36C97D121F.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/40BF94E540E3726CB150A1ADF7C1B514444B3FA6.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/40BF94E540E3726CB150A1ADF7C1B514444B3FA6.key
new file mode 100644
index 00000000000..14af8662f79
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/40BF94E540E3726CB150A1ADF7C1B514444B3FA6.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/515D4637EFC6C09DB1F78BE8C2F2A3D63E7756C3.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/515D4637EFC6C09DB1F78BE8C2F2A3D63E7756C3.key
new file mode 100644
index 00000000000..207a7237d3a
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/515D4637EFC6C09DB1F78BE8C2F2A3D63E7756C3.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/5A11B1935C46D0B227A73978DCA1293A85604F1D.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/5A11B1935C46D0B227A73978DCA1293A85604F1D.key
new file mode 100644
index 00000000000..85ca78da04d
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/5A11B1935C46D0B227A73978DCA1293A85604F1D.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/62643CEBC7AEBE6817577A34399483700D76BD64.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/62643CEBC7AEBE6817577A34399483700D76BD64.key
new file mode 100644
index 00000000000..79f3cd2b841
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/62643CEBC7AEBE6817577A34399483700D76BD64.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/680D01F368916A0021C14E3453B27B3C5F900683.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/680D01F368916A0021C14E3453B27B3C5F900683.key
new file mode 100644
index 00000000000..776ddf7e9e2
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/680D01F368916A0021C14E3453B27B3C5F900683.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/6DF2D9DF7AED06F0524BEB642DF0FB48EFDBDB93.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/6DF2D9DF7AED06F0524BEB642DF0FB48EFDBDB93.key
new file mode 100644
index 00000000000..2b464f0ccbe
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/6DF2D9DF7AED06F0524BEB642DF0FB48EFDBDB93.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/78C17E134E86E691297F7B719B2F2CDF41976234.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/78C17E134E86E691297F7B719B2F2CDF41976234.key
new file mode 100644
index 00000000000..28a07668b21
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/78C17E134E86E691297F7B719B2F2CDF41976234.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/7F714F4D9D9676638214991E96D45704E4FFC409.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/7F714F4D9D9676638214991E96D45704E4FFC409.key
new file mode 100644
index 00000000000..137659693bd
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/7F714F4D9D9676638214991E96D45704E4FFC409.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/854752F5D8090CA36EFBDD79C72BDFF6FA2D1FF0.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/854752F5D8090CA36EFBDD79C72BDFF6FA2D1FF0.key
new file mode 100644
index 00000000000..c99824ccd43
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/854752F5D8090CA36EFBDD79C72BDFF6FA2D1FF0.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/93FF37C268FDBF0767F5FFDC49409DDAC9388B2C.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/93FF37C268FDBF0767F5FFDC49409DDAC9388B2C.key
new file mode 100644
index 00000000000..49c2dc58bd8
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/93FF37C268FDBF0767F5FFDC49409DDAC9388B2C.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/A3BA94EAE83509CC90DB1B77B54A51959D8DABEA.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/A3BA94EAE83509CC90DB1B77B54A51959D8DABEA.key
new file mode 100644
index 00000000000..ca128408952
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/A3BA94EAE83509CC90DB1B77B54A51959D8DABEA.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/A73E9D01F0465B518E8E7D5AD529077AAC1603B4.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/A73E9D01F0465B518E8E7D5AD529077AAC1603B4.key
new file mode 100644
index 00000000000..3f14b40927a
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/A73E9D01F0465B518E8E7D5AD529077AAC1603B4.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/AE6A24B17A8D0CAF9B7E000AA77F0B41D7BFFFCF.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/AE6A24B17A8D0CAF9B7E000AA77F0B41D7BFFFCF.key
new file mode 100644
index 00000000000..06adc06c427
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/AE6A24B17A8D0CAF9B7E000AA77F0B41D7BFFFCF.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/C072AF82DCCCB9A7F1B85FFA10B802DC4ED16703.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/C072AF82DCCCB9A7F1B85FFA10B802DC4ED16703.key
new file mode 100644
index 00000000000..cf9a60d233b
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/C072AF82DCCCB9A7F1B85FFA10B802DC4ED16703.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/C43E1A079B28DFAEBB39CBA01793BDE11EF4B490.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/C43E1A079B28DFAEBB39CBA01793BDE11EF4B490.key
new file mode 100644
index 00000000000..0ed35172fe0
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/C43E1A079B28DFAEBB39CBA01793BDE11EF4B490.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/C67DAD345455EAD6D51368008FC3A53B8D195B5A.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/C67DAD345455EAD6D51368008FC3A53B8D195B5A.key
new file mode 100644
index 00000000000..090059d9e81
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/C67DAD345455EAD6D51368008FC3A53B8D195B5A.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/CB5E00CE582C2645D2573FC16B2F14F85A7F47AA.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/CB5E00CE582C2645D2573FC16B2F14F85A7F47AA.key
new file mode 100644
index 00000000000..9061f675121
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/CB5E00CE582C2645D2573FC16B2F14F85A7F47AA.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/CC68630A06B048F5A91136C162C7A3273E20DE6F.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/CC68630A06B048F5A91136C162C7A3273E20DE6F.key
new file mode 100644
index 00000000000..89f6013100d
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/CC68630A06B048F5A91136C162C7A3273E20DE6F.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/E7E73903E1BF93481DE0E7C9769D6C31E1863CFF.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/E7E73903E1BF93481DE0E7C9769D6C31E1863CFF.key
new file mode 100644
index 00000000000..41dac37574e
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/E7E73903E1BF93481DE0E7C9769D6C31E1863CFF.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/F0117468BE801ED4B81972E159A98FDD4814DCEC.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/F0117468BE801ED4B81972E159A98FDD4814DCEC.key
new file mode 100644
index 00000000000..5df7b4a5953
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/F0117468BE801ED4B81972E159A98FDD4814DCEC.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/F4C5EFD5779BE892CAFD5B721D68DED677C9B151.key b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/F4C5EFD5779BE892CAFD5B721D68DED677C9B151.key
new file mode 100644
index 00000000000..03daf80975b
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/private-keys-v1.d/F4C5EFD5779BE892CAFD5B721D68DED677C9B151.key
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/pubring.gpg b/test/lisp/gnus/mml-sec-resources/pubring.gpg
new file mode 100644
index 00000000000..6bd169963df
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/pubring.gpg
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/pubring.kbx b/test/lisp/gnus/mml-sec-resources/pubring.kbx
new file mode 100644
index 00000000000..399a0414fd2
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/pubring.kbx
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/secring.gpg b/test/lisp/gnus/mml-sec-resources/secring.gpg
new file mode 100644
index 00000000000..b323c072c04
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/secring.gpg
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/trustdb.gpg b/test/lisp/gnus/mml-sec-resources/trustdb.gpg
new file mode 100644
index 00000000000..09ebd8db114
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/trustdb.gpg
Binary files differ
diff --git a/test/lisp/gnus/mml-sec-resources/trustlist.txt b/test/lisp/gnus/mml-sec-resources/trustlist.txt
new file mode 100644
index 00000000000..f886572d283
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-resources/trustlist.txt
@@ -0,0 +1,26 @@
+# This is the list of trusted keys. Comment lines, like this one, as
+# well as empty lines are ignored. Lines have a length limit but this
+# is not a serious limitation as the format of the entries is fixed and
+# checked by gpg-agent. A non-comment line starts with optional white
+# space, followed by the SHA-1 fingerpint in hex, followed by a flag
+# which may be one of 'P', 'S' or '*' and optionally followed by a list of
+# other flags. The fingerprint may be prefixed with a '!' to mark the
+# key as not trusted. You should give the gpg-agent a HUP or run the
+# command "gpgconf --reload gpg-agent" after changing this file.
+
+
+# Include the default trust list
+include-default
+
+
+# CN=No Expiry
+D0:6A:A1:18:65:3C:C3:8E:9D:0C:AF:56:ED:7A:21:35:E1:58:21:77 S relax
+
+# CN=Second Key Pair
+0E:58:22:9B:80:EE:33:95:9F:F7:18:FE:EF:25:40:2B:47:9D:C6:E2 S relax
+
+# CN=No Expiry two UIDs
+D4:CA:78:E1:47:0B:9F:C2:AE:45:D7:84:64:9B:8C:E6:4E:BB:32:0C S relax
+
+# CN=Different subkeys
+4F:96:2A:B7:F4:76:61:6A:78:3D:72:AA:40:35:D5:9B:5F:88:E9:FC S relax
diff --git a/test/lisp/gnus/mml-sec-tests.el b/test/lisp/gnus/mml-sec-tests.el
new file mode 100644
index 00000000000..b743187030f
--- /dev/null
+++ b/test/lisp/gnus/mml-sec-tests.el
@@ -0,0 +1,896 @@
+;;; mml-sec-tests.el --- Tests mml-sec.el, see README-mml-secure.txt. -*- lexical-binding:t -*-
+;; Copyright (C) 2015, 2020-2021 Free Software Foundation, Inc.
+
+;; Author: Jens Lechtenbörger <jens.lechtenboerger@fsfe.org>
+
+;; This file is not 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, 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+(require 'ert-x)
+
+(require 'message)
+(require 'epa)
+(require 'epg)
+(require 'mml-sec)
+(require 'gnus-sum)
+
+(defvar with-smime nil
+ "If nil, exclude S/MIME from tests as passphrases need to entered manually.
+Mostly, the empty passphrase is used. However, the keys for
+ \"No Expiry two UIDs\" have the passphrase \"Passphrase\" (for OpenPGP as well
+ as S/MIME).")
+
+(defun test-conf ()
+ ;; Emacs doesn't have support for finding the name of the PGP agent
+ ;; on MacOS, so disable the checks.
+ (and (not (eq system-type 'darwin))
+ (ignore-errors (epg-find-configuration 'OpenPGP))))
+
+(defun enc-standards ()
+ (if with-smime '(enc-pgp enc-pgp-mime enc-smime)
+ '(enc-pgp enc-pgp-mime)))
+(defun enc-sign-standards ()
+ (if with-smime
+ '(enc-sign-pgp enc-sign-pgp-mime enc-sign-smime)
+ '(enc-sign-pgp enc-sign-pgp-mime)))
+(defun sign-standards ()
+ (if with-smime
+ '(sign-pgp sign-pgp-mime sign-smime)
+ '(sign-pgp sign-pgp-mime)))
+
+(defvar mml-smime-use)
+
+(defun mml-secure-test-fixture (body &optional interactive)
+ "Setup GnuPG home containing test keys and prepare environment for BODY.
+If optional INTERACTIVE is non-nil, allow questions to the user in case of
+key problems.
+This fixture temporarily unsets GPG_AGENT_INFO to enable passphrase tests,
+which will neither work with gpgsm nor GnuPG 2.1 any longer, I guess.
+Actually, I'm not sure why people would want to cache passwords in Emacs
+instead of gpg-agent."
+ (unwind-protect
+ (let ((agent-info (getenv "GPG_AGENT_INFO"))
+ (gpghome (getenv "GNUPGHOME")))
+ (condition-case error
+ (let ((epg-gpg-home-directory (ert-resource-directory))
+ (mml-smime-use 'epg)
+ ;; Create debug output in empty epg-debug-buffer.
+ (epg-debug t)
+ (epg-debug-buffer (get-buffer-create " *epg-test*"))
+ (mml-secure-fail-when-key-problem (not interactive)))
+ (with-current-buffer epg-debug-buffer
+ (erase-buffer))
+ ;; Unset GPG_AGENT_INFO to enable passphrase caching inside Emacs.
+ ;; Just for testing. Jens does not recommend this for daily use.
+ (setenv "GPG_AGENT_INFO")
+ ;; Set GNUPGHOME as gpg-agent started by gpgsm does
+ ;; not look in the proper places otherwise, see:
+ ;; https://bugs.gnupg.org/gnupg/issue2126
+ (setenv "GNUPGHOME" epg-gpg-home-directory)
+ (unwind-protect
+ (funcall body)
+ (mml-sec-test--kill-gpg-agent)))
+ (error
+ (setenv "GPG_AGENT_INFO" agent-info)
+ (setenv "GNUPGHOME" gpghome)
+ (signal (car error) (cdr error))))
+ (setenv "GPG_AGENT_INFO" agent-info)
+ (setenv "GNUPGHOME" gpghome))))
+
+(defun mml-secure-test-message-setup (method to from &optional text bcc)
+ "Setup a buffer with MML METHOD, TO, and FROM headers.
+Optionally, a message TEXT and BCC header can be passed."
+ (with-temp-buffer
+ (when bcc (insert (format "Bcc: %s\n" bcc)))
+ (insert (format "To: %s
+From: %s
+Subject: Test
+%s\n" to from mail-header-separator))
+ (if text
+ (insert (format "%s" text))
+ (spook))
+ (cond ((eq method 'enc-pgp-mime)
+ (mml-secure-message-encrypt-pgpmime 'nosig))
+ ((eq method 'enc-sign-pgp-mime)
+ (mml-secure-message-encrypt-pgpmime))
+ ((eq method 'enc-pgp) (mml-secure-message-encrypt-pgp 'nosig))
+ ((eq method 'enc-sign-pgp) (mml-secure-message-encrypt-pgp))
+ ((eq method 'enc-smime) (mml-secure-message-encrypt-smime 'nosig))
+ ((eq method 'enc-sign-smime) (mml-secure-message-encrypt-smime))
+ ((eq method 'sign-pgp-mime) (mml-secure-message-sign-pgpmime))
+ ((eq method 'sign-pgp) (mml-secure-message-sign-pgp))
+ ((eq method 'sign-smime) (mml-secure-message-sign-smime))
+ (t (error "Unknown method")))
+ (buffer-string)))
+
+(defun mml-secure-test-mail-fixture (method to from body2
+ &optional interactive)
+ "Setup buffer encrypted using METHOD for TO from FROM, call BODY2.
+Pass optional INTERACTIVE to mml-secure-test-fixture."
+ (mml-secure-test-fixture
+ (lambda ()
+ (let ((_context (if (memq method '(enc-smime enc-sign-smime sign-smime))
+ (epg-make-context 'CMS)
+ (epg-make-context 'OpenPGP)))
+ ;; Verify and decrypt by default.
+ (mm-verify-option 'known)
+ (mm-decrypt-option 'known)
+ (plaintext "The Magic Words are Squeamish Ossifrage"))
+ (with-temp-buffer
+ (insert (mml-secure-test-message-setup method to from plaintext))
+ (message-options-set-recipient)
+ (message-encode-message-body)
+ ;; Replace separator line with newline.
+ (goto-char (point-min))
+ (re-search-forward
+ (concat "^" (regexp-quote mail-header-separator) "\n"))
+ (replace-match "\n")
+ ;; The following treatment of handles, plainbuf, and multipart
+ ;; resulted from trial-and-error.
+ ;; Someone with more knowledge on how to decrypt messages and verify
+ ;; signatures might know more appropriate functions to invoke
+ ;; instead.
+ (let* ((handles (or (mm-dissect-buffer)
+ (mm-uu-dissect)))
+ (isplain (bufferp (car handles)))
+ (ismultipart (equal (car handles) "multipart/mixed"))
+ (plainbuf (if isplain
+ (car handles)
+ (if ismultipart
+ (car (cadadr handles))
+ (caadr handles))))
+ (decrypted
+ (with-current-buffer plainbuf (buffer-string)))
+ (gnus-info
+ (if isplain
+ nil
+ (if ismultipart
+ (or (mm-handle-multipart-ctl-parameter
+ (cadr handles) 'gnus-details)
+ (mm-handle-multipart-ctl-parameter
+ (cadr handles) 'gnus-info))
+ (mm-handle-multipart-ctl-parameter
+ handles 'gnus-info)))))
+ (funcall body2 gnus-info plaintext decrypted)))))
+ interactive))
+
+;; TODO If the variable BODY3 is renamed to BODY, an infinite recursion
+;; occurs. Emacs bug?
+(defun mml-secure-test-key-fixture (body3)
+ "Customize unique keys for sub@example.org and call BODY3.
+For OpenPGP, we have:
+- 1E6B FA97 3D9E 3103 B77F D399 C399 9CF1 268D BEA2
+ uid Different subkeys <sub@example.org>
+- 1463 2ECA B9E2 2736 9C8D D97B F7E7 9AB7 AE31 D471
+ uid Second Key Pair <sub@example.org>
+
+For S/MIME:
+ ID: 0x479DC6E2
+ Subject: /CN=Second Key Pair
+ aka: sub@example.org
+ fingerprint: 0E:58:22:9B:80:EE:33:95:9F:F7:18:FE:EF:25:40:2B:47:9D:C6:E2
+
+ ID: 0x5F88E9FC
+ Subject: /CN=Different subkeys
+ aka: sub@example.org
+ fingerprint: 4F:96:2A:B7:F4:76:61:6A:78:3D:72:AA:40:35:D5:9B:5F:88:E9:FC
+
+In both cases, the first key is customized for signing and encryption."
+ (mml-secure-test-fixture
+ (lambda ()
+ (let* ((mml-secure-key-preferences
+ '((OpenPGP (sign) (encrypt)) (CMS (sign) (encrypt))))
+ (pcontext (epg-make-context 'OpenPGP))
+ (pkey (epg-list-keys pcontext "C3999CF1268DBEA2"))
+ (scontext (epg-make-context 'CMS))
+ (skey (epg-list-keys scontext "0x479DC6E2")))
+ (mml-secure-cust-record-keys pcontext 'encrypt "sub@example.org" pkey)
+ (mml-secure-cust-record-keys pcontext 'sign "sub@example.org" pkey)
+ (mml-secure-cust-record-keys scontext 'encrypt "sub@example.org" skey)
+ (mml-secure-cust-record-keys scontext 'sign "sub@example.org" skey)
+ (funcall body3)))))
+
+(ert-deftest mml-secure-key-checks ()
+ "Test mml-secure-check-user-id and mml-secure-check-sub-key on sample keys."
+ (skip-unless (test-conf))
+ (mml-secure-test-fixture
+ (lambda ()
+ (let* ((context (epg-make-context 'OpenPGP))
+ (keys1 (epg-list-keys context "expired@example.org"))
+ (keys2 (epg-list-keys context "no-exp@example.org"))
+ (keys3 (epg-list-keys context "sub@example.org"))
+ (keys4 (epg-list-keys context "revoked-uid@example.org"))
+ (keys5 (epg-list-keys context "disabled@example.org"))
+ (keys6 (epg-list-keys context "sign@example.org"))
+ (keys7 (epg-list-keys context "jens.lechtenboerger@fsfe"))
+ )
+ (should (and (= 1 (length keys1)) (= 1 (length keys2))
+ (= 2 (length keys3))
+ (= 1 (length keys4)) (= 1 (length keys5))
+ ))
+ ;; key1 is expired
+ (should-not (mml-secure-check-user-id (car keys1) "expired@example.org"))
+ (should-not (mml-secure-check-sub-key context (car keys1) 'encrypt))
+ (should-not (mml-secure-check-sub-key context (car keys1) 'sign))
+
+ ;; key2 does not expire, but does not have the UID expired@example.org
+ (should-not (mml-secure-check-user-id (car keys2) "expired@example.org"))
+ (should (mml-secure-check-user-id (car keys2) "no-exp@example.org"))
+ (should (mml-secure-check-sub-key context (car keys2) 'encrypt))
+ (should (mml-secure-check-sub-key context (car keys2) 'sign))
+
+ ;; Two keys exist for sub@example.org.
+ (should (mml-secure-check-user-id (car keys3) "sub@example.org"))
+ (should (mml-secure-check-sub-key context (car keys3) 'encrypt))
+ (should (mml-secure-check-sub-key context (car keys3) 'sign))
+ (should (mml-secure-check-user-id (cadr keys3) "sub@example.org"))
+ (should (mml-secure-check-sub-key context (cadr keys3) 'encrypt))
+ (should (mml-secure-check-sub-key context (cadr keys3) 'sign))
+
+ ;; The UID revoked-uid@example.org is revoked. The key itself is
+ ;; usable, though (with the UID sub@example.org).
+ (should-not
+ (mml-secure-check-user-id (car keys4) "revoked-uid@example.org"))
+ (should (mml-secure-check-sub-key context (car keys4) 'encrypt))
+ (should (mml-secure-check-sub-key context (car keys4) 'sign))
+ (should (mml-secure-check-user-id (car keys4) "sub@example.org"))
+
+ ;; The next key is disabled and, thus, unusable.
+ (should (mml-secure-check-user-id (car keys5) "disabled@example.org"))
+ (should-not (mml-secure-check-sub-key context (car keys5) 'encrypt))
+ (should-not (mml-secure-check-sub-key context (car keys5) 'sign))
+
+ ;; The next key has multiple subkeys.
+ ;; 42466F0F is valid sign subkey, 501FFD98 is expired
+ (should (mml-secure-check-sub-key context (car keys6) 'sign "42466F0F"))
+ (should-not
+ (mml-secure-check-sub-key context (car keys6) 'sign "501FFD98"))
+ ;; DC7F66E7 is encrypt subkey
+ (should
+ (mml-secure-check-sub-key context (car keys6) 'encrypt "DC7F66E7"))
+ (should-not
+ (mml-secure-check-sub-key context (car keys6) 'sign "DC7F66E7"))
+ (should-not
+ (mml-secure-check-sub-key context (car keys6) 'encrypt "42466F0F"))
+
+ ;; The final key is just a public key.
+ (should (mml-secure-check-sub-key context (car keys7) 'encrypt))
+ (should-not (mml-secure-check-sub-key context (car keys7) 'sign))
+ ))))
+
+(ert-deftest mml-secure-find-usable-keys-1 ()
+ "Make sure that expired and disabled keys and revoked UIDs are not used."
+ (skip-unless (test-conf))
+ (mml-secure-test-fixture
+ (lambda ()
+ (let ((context (epg-make-context 'OpenPGP)))
+ (should-not
+ (mml-secure-find-usable-keys context "expired@example.org" 'encrypt))
+ (should-not
+ (mml-secure-find-usable-keys context "expired@example.org" 'sign))
+
+ (should-not
+ (mml-secure-find-usable-keys context "disabled@example.org" 'encrypt))
+ (should-not
+ (mml-secure-find-usable-keys context "disabled@example.org" 'sign))
+
+ (should-not
+ (mml-secure-find-usable-keys
+ context "<revoked-uid@example.org>" 'encrypt))
+ (should-not
+ (mml-secure-find-usable-keys
+ context "<revoked-uid@example.org>" 'sign))
+ ;; Same test without ankles. Will fail for Ma Gnus v0.14 and earlier.
+ (should-not
+ (mml-secure-find-usable-keys
+ context "revoked-uid@example.org" 'encrypt))
+
+ ;; Expired key should not be usable.
+ ;; Will fail for Ma Gnus v0.14 and earlier.
+ ;; sign@example.org has the expired subkey 0x501FFD98.
+ (should-not
+ (mml-secure-find-usable-keys context "0x501FFD98" 'sign))
+
+ (should
+ (mml-secure-find-usable-keys context "no-exp@example.org" 'encrypt))
+ (should
+ (mml-secure-find-usable-keys context "no-exp@example.org" 'sign))
+ ))))
+
+(ert-deftest mml-secure-find-usable-keys-2 ()
+ "Test different ways to search for keys."
+ (skip-unless (test-conf))
+ (mml-secure-test-fixture
+ (lambda ()
+ (let ((context (epg-make-context 'OpenPGP)))
+ ;; Plain substring search is not supported.
+ (should
+ (= 0 (length
+ (mml-secure-find-usable-keys context "No Expiry" 'encrypt))))
+ (should
+ (= 0 (length
+ (mml-secure-find-usable-keys context "No Expiry" 'sign))))
+
+ ;; Search for e-mail addresses works with and without ankle brackets.
+ (should
+ (= 1 (length (mml-secure-find-usable-keys
+ context "<no-exp@example.org>" 'encrypt))))
+ (should
+ (= 1 (length (mml-secure-find-usable-keys
+ context "<no-exp@example.org>" 'sign))))
+ (should
+ (= 1 (length (mml-secure-find-usable-keys
+ context "no-exp@example.org" 'encrypt))))
+ (should
+ (= 1 (length (mml-secure-find-usable-keys
+ context "no-exp@example.org" 'sign))))
+
+ ;; Use full UID string.
+ (should
+ (= 1 (length (mml-secure-find-usable-keys
+ context "No Expiry <no-exp@example.org>" 'encrypt))))
+ (should
+ (= 1 (length (mml-secure-find-usable-keys
+ context "No Expiry <no-exp@example.org>" 'sign))))
+
+ ;; If just the public key is present, only encryption is possible.
+ ;; Search works with key IDs, with and without prefix "0x".
+ (should
+ (= 1 (length (mml-secure-find-usable-keys
+ context "A142FD84" 'encrypt))))
+ (should
+ (= 1 (length (mml-secure-find-usable-keys
+ context "0xA142FD84" 'encrypt))))
+ (should
+ (= 0 (length (mml-secure-find-usable-keys
+ context "A142FD84" 'sign))))
+ (should
+ (= 0 (length (mml-secure-find-usable-keys
+ context "0xA142FD84" 'sign))))
+ ))))
+
+(ert-deftest mml-secure-select-preferred-keys-1 ()
+ "If only one key exists for an e-mail address, it is the preferred one."
+ (skip-unless (test-conf))
+ (mml-secure-test-fixture
+ (lambda ()
+ (let ((context (epg-make-context 'OpenPGP)))
+ (should (equal "832F3CC6518D37BC658261B802372A42CA6D40FB"
+ (mml-secure-fingerprint
+ (car (mml-secure-select-preferred-keys
+ context '("no-exp@example.org") 'encrypt)))))))))
+
+(ert-deftest mml-secure-select-preferred-keys-2 ()
+ "If multiple keys exists for an e-mail address, customization is necessary."
+ (skip-unless (test-conf))
+ (mml-secure-test-fixture
+ (lambda ()
+ (let* ((context (epg-make-context 'OpenPGP))
+ (mml-secure-key-preferences
+ '((OpenPGP (sign) (encrypt)) (CMS (sign) (encrypt))))
+ (pref (car (mml-secure-find-usable-keys
+ context "sub@example.org" 'encrypt))))
+ (should-error (mml-secure-select-preferred-keys
+ context '("sub@example.org") 'encrypt))
+ (mml-secure-cust-record-keys
+ context 'encrypt "sub@example.org" (list pref))
+ (should (mml-secure-select-preferred-keys
+ context '("sub@example.org") 'encrypt))
+ (should-error (mml-secure-select-preferred-keys
+ context '("sub@example.org") 'sign))
+ (should (mml-secure-select-preferred-keys
+ context '("sub@example.org") 'encrypt))
+ (should
+ (equal (list (mml-secure-fingerprint pref))
+ (mml-secure-cust-fpr-lookup context 'encrypt "sub@example.org")))
+ (should (mml-secure-cust-remove-keys context 'encrypt "sub@example.org"))
+ (should-error (mml-secure-select-preferred-keys
+ context '("sub@example.org") 'encrypt))))))
+
+(ert-deftest mml-secure-select-preferred-keys-3 ()
+ "Expired customized keys are removed if multiple keys are available."
+ (skip-unless (test-conf))
+ (mml-secure-test-fixture
+ (lambda ()
+ (let ((context (epg-make-context 'OpenPGP))
+ (mml-secure-key-preferences
+ '((OpenPGP (sign) (encrypt)) (CMS (sign) (encrypt)))))
+ ;; sub@example.org has two keys (268DBEA2, AE31D471).
+ ;; Normal preference works.
+ (mml-secure-cust-record-keys
+ context 'encrypt "sub@example.org" (epg-list-keys context "268DBEA2"))
+ (should (mml-secure-select-preferred-keys
+ context '("sub@example.org") 'encrypt))
+ (mml-secure-cust-remove-keys context 'encrypt "sub@example.org")
+
+ ;; Fake preference for expired (unrelated) key CE15FAE7,
+ ;; results in error (and automatic removal of outdated preference).
+ (mml-secure-cust-record-keys
+ context 'encrypt "sub@example.org" (epg-list-keys context "CE15FAE7"))
+ (should-error (mml-secure-select-preferred-keys
+ context '("sub@example.org") 'encrypt))
+ (should-not
+ (mml-secure-cust-remove-keys context 'encrypt "sub@example.org"))))))
+
+(ert-deftest mml-secure-select-preferred-keys-4 ()
+ "Multiple keys can be recorded per recipient or signature."
+ (skip-unless (test-conf))
+ (skip-unless (ignore-errors (epg-find-configuration 'CMS)))
+ (mml-secure-test-fixture
+ (lambda ()
+ (let ((pcontext (epg-make-context 'OpenPGP))
+ (scontext (epg-make-context 'CMS))
+ (pkeys '("1E6BFA973D9E3103B77FD399C3999CF1268DBEA2"
+ "14632ECAB9E227369C8DD97BF7E79AB7AE31D471"))
+ (skeys '("0x5F88E9FC" "0x479DC6E2"))
+ (mml-secure-key-preferences
+ '((OpenPGP (sign) (encrypt)) (CMS (sign) (encrypt)))))
+
+ ;; OpenPGP preferences via pcontext
+ (dolist (key pkeys nil)
+ (mml-secure-cust-record-keys
+ pcontext 'encrypt "sub@example.org" (epg-list-keys pcontext key))
+ (mml-secure-cust-record-keys
+ pcontext 'sign "sub@example.org" (epg-list-keys pcontext key 'secret)))
+ (let ((p-e-fprs (mml-secure-cust-fpr-lookup
+ pcontext 'encrypt "sub@example.org"))
+ (p-s-fprs (mml-secure-cust-fpr-lookup
+ pcontext 'sign "sub@example.org")))
+ (should (= 2 (length p-e-fprs)))
+ (should (= 2 (length p-s-fprs)))
+ (should (member "1E6BFA973D9E3103B77FD399C3999CF1268DBEA2" p-e-fprs))
+ (should (member "14632ECAB9E227369C8DD97BF7E79AB7AE31D471" p-e-fprs))
+ (should (member "1E6BFA973D9E3103B77FD399C3999CF1268DBEA2" p-s-fprs))
+ (should (member "14632ECAB9E227369C8DD97BF7E79AB7AE31D471" p-s-fprs)))
+ ;; Duplicate record does not change anything.
+ (mml-secure-cust-record-keys
+ pcontext 'encrypt "sub@example.org"
+ (epg-list-keys pcontext "1E6BFA973D9E3103B77FD399C3999CF1268DBEA2"))
+ (mml-secure-cust-record-keys
+ pcontext 'sign "sub@example.org"
+ (epg-list-keys pcontext "1E6BFA973D9E3103B77FD399C3999CF1268DBEA2"))
+ (let ((p-e-fprs (mml-secure-cust-fpr-lookup
+ pcontext 'encrypt "sub@example.org"))
+ (p-s-fprs (mml-secure-cust-fpr-lookup
+ pcontext 'sign "sub@example.org")))
+ (should (= 2 (length p-e-fprs)))
+ (should (= 2 (length p-s-fprs))))
+
+ ;; S/MIME preferences via scontext
+ (dolist (key skeys nil)
+ (mml-secure-cust-record-keys
+ scontext 'encrypt "sub@example.org"
+ (epg-list-keys scontext key))
+ (mml-secure-cust-record-keys
+ scontext 'sign "sub@example.org"
+ (epg-list-keys scontext key 'secret)))
+ (let ((s-e-fprs (mml-secure-cust-fpr-lookup
+ scontext 'encrypt "sub@example.org"))
+ (s-s-fprs (mml-secure-cust-fpr-lookup
+ scontext 'sign "sub@example.org")))
+ (should (= 2 (length s-e-fprs)))
+ (should (= 2 (length s-s-fprs))))
+ ))))
+
+(defun mml-secure-test-en-decrypt
+ (method to from
+ &optional checksig checkplain enc-keys expectfail interactive)
+ "Encrypt message using METHOD, addressed to TO, from FROM.
+If optional CHECKSIG is non-nil, it must be a number, and a signature check is
+performed; the number indicates how many signatures are expected.
+If optional CHECKPLAIN is non-nil, the expected plaintext should be obtained
+via decryption.
+If optional ENC-KEYS is non-nil, it is a list of pairs of encryption keys (for
+OpenPGP and S/SMIME) expected in `epg-debug-buffer'.
+If optional EXPECTFAIL is non-nil, a decryption failure is expected.
+Pass optional INTERACTIVE to mml-secure-test-mail-fixture."
+ (mml-secure-test-mail-fixture method to from
+ (lambda (gnus-info plaintext decrypted)
+ (if expectfail
+ (should-not (equal plaintext decrypted))
+ (when checkplain
+ (should (equal plaintext decrypted)))
+ (let ((protocol (if (memq method
+ '(enc-smime enc-sign-smime sign-smime))
+ 'CMS
+ 'OpenPGP)))
+ (when checksig
+ (let* ((context (epg-make-context protocol))
+ (signer-names (mml-secure-signer-names protocol from))
+ (signer-keys (mml-secure-signers context signer-names))
+ (signer-fprs (mapcar 'mml-secure-fingerprint signer-keys)))
+ (should (eq checksig (length signer-fprs)))
+ (if (eq checksig 0)
+ ;; First key in keyring
+ (should (string-match-p
+ (concat "Good signature from "
+ (if (eq protocol 'CMS)
+ "0E58229B80EE33959FF718FEEF25402B479DC6E2"
+ "02372A42CA6D40FB"))
+ gnus-info)))
+ (dolist (fpr signer-fprs nil)
+ ;; OpenPGP: "Good signature from 02372A42CA6D40FB No Expiry <no-exp@example.org> (trust undefined) created ..."
+ ;; S/MIME: "Good signature from D06AA118653CC38E9D0CAF56ED7A2135E1582177 /CN=No Expiry (trust full) ..."
+ (should (string-match-p
+ (concat "Good signature from "
+ (if (eq protocol 'CMS)
+ fpr
+ (substring fpr -16 nil)))
+ gnus-info)))))
+ (when enc-keys
+ (with-current-buffer epg-debug-buffer
+ (goto-char (point-min))
+ ;; The following regexp does not necessarily match at the
+ ;; start of the line as a path may or may not be present.
+ ;; Also note that gpg.* matches gpg2 and gpgsm as well.
+ (let* ((line (concat "gpg.*--encrypt.*$"))
+ (end (re-search-forward line))
+ (match (match-string 0)))
+ (should (and end match))
+ (dolist (pair enc-keys nil)
+ (let ((fpr (if (eq protocol 'OpenPGP)
+ (car pair)
+ (cdr pair))))
+ (should (string-match-p (concat "-r " fpr) match))))
+ (goto-char (point-max))
+ ))))))
+ interactive))
+
+(defvar mml-smime-cache-passphrase)
+(defvar mml2015-cache-passphrase)
+(defvar mml1991-cache-passphrase)
+
+(defun mml-secure-test-en-decrypt-with-passphrase
+ (method to from checksig jl-passphrase do-cache
+ &optional enc-keys expectfail)
+ "Call mml-secure-test-en-decrypt with changed passphrase caching.
+Args METHOD, TO, FROM, CHECKSIG are passed to mml-secure-test-en-decrypt.
+JL-PASSPHRASE is fixed as return value for `read-passwd',
+boolean DO-CACHE determines whether to cache the passphrase.
+If optional ENC-KEYS is non-nil, it is a list of encryption keys expected
+in `epg-debug-buffer'.
+If optional EXPECTFAIL is non-nil, a decryption failure is expected."
+ (let ((mml-secure-cache-passphrase do-cache)
+ (mml1991-cache-passphrase do-cache)
+ (mml2015-cache-passphrase do-cache)
+ (mml-smime-cache-passphrase do-cache)
+ )
+ (cl-letf (((symbol-function 'read-passwd)
+ (lambda (_prompt &optional _confirm _default) jl-passphrase)))
+ (mml-secure-test-en-decrypt method to from checksig t enc-keys expectfail)
+ )))
+
+(ert-deftest mml-secure-en-decrypt-1 ()
+ "Encrypt message; then decrypt and test for expected result.
+In this test, the single matching key is chosen automatically."
+ (skip-unless (test-conf))
+ (dolist (method (enc-standards) nil)
+ ;; no-exp@example.org with single encryption key
+ (mml-secure-test-en-decrypt
+ method "no-exp@example.org" "sub@example.org" nil t
+ (list (cons "02372A42CA6D40FB" "ED7A2135E1582177")))))
+
+(ert-deftest mml-secure-en-decrypt-2 ()
+ "Encrypt message; then decrypt and test for expected result.
+In this test, the encryption key needs to fixed among multiple ones."
+ (skip-unless (test-conf))
+ (skip-unless (ignore-errors (epg-find-configuration 'CMS)))
+ ;; sub@example.org with multiple candidate keys,
+ ;; fixture customizes preferred ones.
+ (mml-secure-test-key-fixture
+ (lambda ()
+ (dolist (method (enc-standards) nil)
+ (mml-secure-test-en-decrypt
+ method "sub@example.org" "no-exp@example.org" nil t
+ (list (cons "C3999CF1268DBEA2" "EF25402B479DC6E2")))))))
+
+(ert-deftest mml-secure-en-decrypt-3 ()
+ "Encrypt message; then decrypt and test for expected result.
+In this test, encrypt-to-self variables are set to t."
+ (skip-unless (test-conf))
+ (skip-unless (ignore-errors (epg-find-configuration 'CMS)))
+ ;; sub@example.org with multiple candidate keys,
+ ;; fixture customizes preferred ones.
+ (mml-secure-test-key-fixture
+ (lambda ()
+ (let ((mml-secure-openpgp-encrypt-to-self t)
+ (mml-secure-smime-encrypt-to-self t))
+ (dolist (method (enc-standards) nil)
+ (mml-secure-test-en-decrypt
+ method "sub@example.org" "no-exp@example.org" nil t
+ (list (cons "C3999CF1268DBEA2" "EF25402B479DC6E2")
+ (cons "02372A42CA6D40FB" "ED7A2135E1582177"))))))))
+
+(ert-deftest mml-secure-en-decrypt-4 ()
+ "Encrypt message; then decrypt and test for expected result.
+In this test, encrypt-to-self variables are set to lists."
+ (skip-unless (test-conf))
+ ;; Send from sub@example.org, which has two keys; encrypt to both.
+ (let ((mml-secure-openpgp-encrypt-to-self
+ '("C3999CF1268DBEA2" "F7E79AB7AE31D471"))
+ (mml-secure-smime-encrypt-to-self
+ '("EF25402B479DC6E2" "4035D59B5F88E9FC")))
+ (dolist (method (enc-standards) nil)
+ (mml-secure-test-en-decrypt
+ method "no-exp@example.org" "sub@example.org" nil t
+ (list (cons "C3999CF1268DBEA2" "EF25402B479DC6E2")
+ (cons "F7E79AB7AE31D471" "4035D59B5F88E9FC"))))))
+
+(ert-deftest mml-secure-en-decrypt-sign-1-1-single ()
+ "Sign and encrypt message; then decrypt and test for expected result.
+In this test, just multiple encryption and signing keys may be available."
+ :tags '(:unstable)
+ (skip-unless (test-conf))
+ (mml-secure-test-key-fixture
+ (lambda ()
+ (let ((mml-secure-openpgp-sign-with-sender t)
+ (mml-secure-smime-sign-with-sender t))
+ (dolist (method (enc-sign-standards) nil)
+ ;; no-exp with just one key
+ (mml-secure-test-en-decrypt
+ method "no-exp@example.org" "no-exp@example.org" 1 t)
+ ;; customized choice for encryption key
+ (mml-secure-test-en-decrypt
+ method "sub@example.org" "no-exp@example.org" 1 t)
+ ;; customized choice for signing key
+ (mml-secure-test-en-decrypt
+ method "no-exp@example.org" "sub@example.org" 1 t)
+ ;; customized choice for both keys
+ (mml-secure-test-en-decrypt
+ method "sub@example.org" "sub@example.org" 1 t)
+ )))))
+
+(ert-deftest mml-secure-en-decrypt-sign-1-2-double ()
+ "Sign and encrypt message; then decrypt and test for expected result.
+In this test, just multiple encryption and signing keys may be available."
+ :tags '(:unstable)
+ (skip-unless (test-conf))
+ (mml-secure-test-key-fixture
+ (lambda ()
+ (let ((mml-secure-openpgp-sign-with-sender t)
+ (mml-secure-smime-sign-with-sender t))
+ ;; Now use both keys to sign. The customized one via sign-with-sender,
+ ;; the other one via the following setting.
+ (let ((mml-secure-openpgp-signers '("F7E79AB7AE31D471"))
+ (mml-secure-smime-signers '("0x5F88E9FC")))
+ (dolist (method (enc-sign-standards) nil)
+ (mml-secure-test-en-decrypt
+ method "no-exp@example.org" "sub@example.org" 2 t)))))))
+
+(ert-deftest mml-secure-en-decrypt-sign-1-3-double ()
+ "Sign and encrypt message; then decrypt and test for expected result.
+In this test, just multiple encryption and signing keys may be available."
+ :tags '(:unstable)
+ (skip-unless (test-conf))
+ (mml-secure-test-key-fixture
+ (lambda ()
+ ;; Now use both keys for sub@example.org to sign an e-mail from
+ ;; a different address (without associated keys).
+ (let ((mml-secure-openpgp-sign-with-sender nil)
+ (mml-secure-smime-sign-with-sender nil)
+ (mml-secure-openpgp-signers
+ '("F7E79AB7AE31D471" "C3999CF1268DBEA2"))
+ (mml-secure-smime-signers '("0x5F88E9FC" "0x479DC6E2")))
+ (dolist (method (enc-sign-standards) nil)
+ (mml-secure-test-en-decrypt
+ method "no-exp@example.org" "no-keys@example.org" 2 t))))))
+
+(ert-deftest mml-secure-en-decrypt-sign-2 ()
+ "Sign and encrypt message; then decrypt and test for expected result.
+In this test, lists of encryption and signing keys are customized."
+ :tags '(:unstable)
+ (skip-unless (test-conf))
+ (mml-secure-test-key-fixture
+ (lambda ()
+ (let ((mml-secure-key-preferences
+ '((OpenPGP (sign) (encrypt)) (CMS (sign) (encrypt))))
+ (pcontext (epg-make-context 'OpenPGP))
+ (scontext (epg-make-context 'CMS))
+ (mml-secure-openpgp-sign-with-sender t)
+ (mml-secure-smime-sign-with-sender t))
+ (dolist (key '("F7E79AB7AE31D471" "C3999CF1268DBEA2") nil)
+ (mml-secure-cust-record-keys
+ pcontext 'encrypt "sub@example.org" (epg-list-keys pcontext key))
+ (mml-secure-cust-record-keys
+ pcontext 'sign "sub@example.org" (epg-list-keys pcontext key t)))
+ (dolist (key '("0x5F88E9FC" "0x479DC6E2") nil)
+ (mml-secure-cust-record-keys
+ scontext 'encrypt "sub@example.org" (epg-list-keys scontext key))
+ (mml-secure-cust-record-keys
+ scontext 'sign "sub@example.org" (epg-list-keys scontext key t)))
+ (dolist (method (enc-sign-standards) nil)
+ ;; customized choice for encryption key
+ (mml-secure-test-en-decrypt
+ method "sub@example.org" "no-exp@example.org" 1 t)
+ ;; customized choice for signing key
+ (mml-secure-test-en-decrypt
+ method "no-exp@example.org" "sub@example.org" 2 t)
+ ;; customized choice for both keys
+ (mml-secure-test-en-decrypt
+ method "sub@example.org" "sub@example.org" 2 t)
+ )))))
+
+(ert-deftest mml-secure-en-decrypt-sign-3 ()
+ "Sign and encrypt message; then decrypt and test for expected result.
+Use sign-with-sender and encrypt-to-self."
+ :tags '(:unstable)
+ (skip-unless (test-conf))
+ (mml-secure-test-key-fixture
+ (lambda ()
+ (let ((mml-secure-openpgp-sign-with-sender t)
+ (mml-secure-openpgp-encrypt-to-self t)
+ (mml-secure-smime-sign-with-sender t)
+ (mml-secure-smime-encrypt-to-self t))
+ (dolist (method (enc-sign-standards) nil)
+ (mml-secure-test-en-decrypt
+ method "sub@example.org" "no-exp@example.org" 1 t
+ (list (cons "C3999CF1268DBEA2" "EF25402B479DC6E2")
+ (cons "02372A42CA6D40FB" "ED7A2135E1582177"))))
+ ))))
+
+(ert-deftest mml-secure-sign-verify-1 ()
+ "Sign message with sender; then verify and test for expected result."
+ (skip-unless (test-conf))
+ (skip-unless (ignore-errors (epg-find-configuration 'CMS)))
+ (mml-secure-test-key-fixture
+ (lambda ()
+ (dolist (method (sign-standards) nil)
+ (let ((mml-secure-openpgp-sign-with-sender t)
+ (mml-secure-smime-sign-with-sender t))
+ ;; A single signing key for sender sub@example.org is customized
+ ;; in the fixture.
+ (mml-secure-test-en-decrypt
+ method "uid1@example.org" "sub@example.org" 1 nil)
+
+ ;; From sub@example.org, sign with two keys;
+ ;; sign-with-sender and one from signers-variable:
+ (let ((mml-secure-openpgp-signers '("02372A42CA6D40FB"))
+ (mml-secure-smime-signers
+ '("D06AA118653CC38E9D0CAF56ED7A2135E1582177")))
+ (mml-secure-test-en-decrypt
+ method "no-exp@example.org" "sub@example.org" 2 nil))
+ )))))
+
+(ert-deftest mml-secure-sign-verify-3 ()
+ "Try to sign message with expired OpenPGP subkey, which raises an error.
+With Ma Gnus v0.14 and earlier a signature would be created with a wrong key."
+ (skip-unless (test-conf))
+ (should-error
+ (mml-secure-test-key-fixture
+ (lambda ()
+ (let ((with-smime nil)
+ (mml-secure-openpgp-sign-with-sender nil)
+ (mml-secure-openpgp-signers '("501FFD98")))
+ (dolist (method (sign-standards) nil)
+ (mml-secure-test-en-decrypt
+ method "no-exp@example.org" "sign@example.org" 1 nil)
+ ))))))
+
+;; TODO Passphrase passing and caching in Emacs does not seem to work
+;; with gpgsm at all.
+;; Independently of caching settings, a pinentry dialogue is displayed.
+;; Thus, the following tests require the user to enter the correct gpgsm
+;; passphrases at the correct points in time. (Either empty string or
+;; "Passphrase".)
+(ert-deftest mml-secure-en-decrypt-passphrase-cache ()
+ "Encrypt message; then decrypt and test for expected result.
+In this test, a key is used that requires the passphrase \"Passphrase\".
+In the first decryption this passphrase is hardcoded, in the second one it
+ is taken from a cache."
+ (skip-unless (test-conf))
+ (ert-skip "Requires passphrase")
+ (mml-secure-test-key-fixture
+ (lambda ()
+ (dolist (method (enc-standards) nil)
+ (mml-secure-test-en-decrypt-with-passphrase
+ method "uid1@example.org" "sub@example.org" nil
+ ;; Beware! For passphrases copy-sequence is necessary, as they may
+ ;; be erased, which actually changes the function's code and causes
+ ;; multiple invocations to fail. I was surprised...
+ (copy-sequence "Passphrase") t)
+ (mml-secure-test-en-decrypt-with-passphrase
+ method "uid1@example.org" "sub@example.org" nil
+ (copy-sequence "Incorrect") t)))))
+
+(defun mml-secure-en-decrypt-passphrase-no-cache (method)
+ "Encrypt message with METHOD; then decrypt and test for expected result.
+In this test, a key is used that requires the passphrase \"Passphrase\".
+In the first decryption this passphrase is hardcoded, but caching disabled.
+So the second decryption fails."
+ (mml-secure-test-key-fixture
+ (lambda ()
+ (mml-secure-test-en-decrypt-with-passphrase
+ method "uid1@example.org" "sub@example.org" nil
+ (copy-sequence "Passphrase") nil)
+ (mml-secure-test-en-decrypt-with-passphrase
+ method "uid1@example.org" "sub@example.org" nil
+ (copy-sequence "Incorrect") nil nil t))))
+
+(ert-deftest mml-secure-en-decrypt-passphrase-no-cache-openpgp-todo ()
+ "Passphrase caching with OpenPGP only for GnuPG 1.x."
+ (skip-unless (test-conf))
+ (skip-unless (string< (cdr (assq 'version (epg-find-configuration 'OpenPGP)))
+ "2"))
+ (mml-secure-en-decrypt-passphrase-no-cache 'enc-pgp)
+ (mml-secure-en-decrypt-passphrase-no-cache 'enc-pgp-mime))
+
+(ert-deftest mml-secure-en-decrypt-passphrase-no-cache-smime-todo ()
+ "Passphrase caching does not work with S/MIME (and gpgsm)."
+ :expected-result :failed
+ (skip-unless (test-conf))
+ (if with-smime
+ (mml-secure-en-decrypt-passphrase-no-cache 'enc-smime)
+ (should nil)))
+
+
+;; Test truncation of question in y-or-n-p.
+(defun mml-secure-select-preferred-keys-todo ()
+ "Manual customization with truncated question."
+ (mml-secure-test-key-fixture
+ (lambda ()
+ (mml-secure-test-en-decrypt
+ 'enc-pgp-mime
+ "jens.lechtenboerger@informationelle-selbstbestimmung-im-internet.de"
+ "no-exp@example.org" nil t nil nil t))))
+
+(defun mml-secure-select-preferred-keys-ok ()
+ "Manual customization with entire question."
+ (mml-secure-test-fixture
+ (lambda ()
+ (mml-secure-select-preferred-keys
+ (epg-make-context 'OpenPGP)
+ '("jens.lechtenboerger@informationelle-selbstbestimmung-im-internet.de")
+ 'encrypt))
+ t))
+
+
+;; ERT entry points
+(defun mml-secure-run-tests ()
+ "Run all tests with defaults."
+ (ert-run-tests-batch))
+
+(defun mml-secure-run-tests-with-gpg2 ()
+ "Run all tests with gpg2 instead of gpg."
+ (let* ((epg-gpg-program "gpg2"); ~/local/gnupg-2.1.9/PLAY/inst/bin/gpg2
+ (gpg-version (cdr (assq 'version (epg-find-configuration 'OpenPGP))))
+ ;; Empty passphrases do not seem to work with gpgsm in 2.1.x:
+ ;; https://lists.gnupg.org/pipermail/gnupg-users/2015-October/054575.html
+ (with-smime (string< gpg-version "2.1")))
+ (ert-run-tests-batch)))
+
+(defun mml-secure-run-tests-without-smime ()
+ "Skip S/MIME tests (as they require manual passphrase entry)."
+ (let ((with-smime nil))
+ (ert-run-tests-batch)))
+
+(defun mml-sec-test--kill-gpg-agent ()
+ (dolist (pid (list-system-processes))
+ (let ((atts (process-attributes pid)))
+ (when (and (equal (cdr (assq 'user atts)) (user-login-name))
+ (or (equal (cdr (assq 'comm atts)) "gpg-agent")
+ (equal (cdr (assq 'comm atts)) "scdaemon"))
+ (string-match
+ (concat "homedir.*"
+ (regexp-quote (directory-file-name
+ (ert-resource-directory))))
+ (cdr (assq 'args atts))))
+ (call-process "kill" nil nil nil (format "%d" pid))))))
+
+;;; mml-sec-tests.el ends here
diff --git a/test/lisp/help-fns-tests.el b/test/lisp/help-fns-tests.el
index 64f9ef6272f..80d90daaf91 100644
--- a/test/lisp/help-fns-tests.el
+++ b/test/lisp/help-fns-tests.el
@@ -24,8 +24,9 @@
;;; Code:
(require 'ert)
+(require 'help-fns)
-(autoload 'help-fns-test--macro "help-fns" nil nil t)
+(autoload 'help-fns-test--macro "foo" nil nil t)
;;; Several tests for describe-function
@@ -56,28 +57,28 @@ Return first line of the output of (describe-function-1 FUNC)."
(should (string-match regexp result))))
(ert-deftest help-fns-test-lisp-macro ()
- (let ((regexp "a Lisp macro in .subr\.el")
+ (let ((regexp "a Lisp macro in .+subr\\.el")
(result (help-fns-tests--describe-function 'when)))
(should (string-match regexp result))))
(ert-deftest help-fns-test-lisp-defun ()
- (let ((regexp "a compiled Lisp function in .subr\.el")
+ (let ((regexp "a compiled Lisp function in .+subr\\.el")
(result (help-fns-tests--describe-function 'last)))
(should (string-match regexp result))))
(ert-deftest help-fns-test-lisp-defsubst ()
- (let ((regexp "a compiled Lisp function in .subr\.el")
+ (let ((regexp "a compiled Lisp function in .+subr\\.el")
(result (help-fns-tests--describe-function 'posn-window)))
(should (string-match regexp result))))
(ert-deftest help-fns-test-alias-to-defun ()
- (let ((regexp "an alias for .set-file-modes. in .subr\.el")
+ (let ((regexp "an alias for .set-file-modes. in .+subr\\.el")
(result (help-fns-tests--describe-function 'chmod)))
(should (string-match regexp result))))
(ert-deftest help-fns-test-bug23887 ()
"Test for https://debbugs.gnu.org/23887 ."
- (let ((regexp "an alias for .re-search-forward. in .subr\.el")
+ (let ((regexp "an alias for .re-search-forward. in .+subr\\.el")
(result (help-fns-tests--describe-function 'search-forward-regexp)))
(should (string-match regexp result))))
@@ -123,4 +124,55 @@ Return first line of the output of (describe-function-1 FUNC)."
(goto-char (point-min))
(should (looking-at "^font-lock-comment-face is "))))
+(defvar foo-test-map)
+(defvar help-fns-test--describe-keymap-foo)
+
+
+;;; Tests for describe-keymap
+(ert-deftest help-fns-test-find-keymap-name ()
+ (should (equal (help-fns-find-keymap-name lisp-mode-map) 'lisp-mode-map))
+ ;; Follow aliasing.
+ (unwind-protect
+ (progn
+ (defvaralias 'foo-test-map 'lisp-mode-map)
+ (should (equal (help-fns-find-keymap-name foo-test-map) 'lisp-mode-map)))
+ (makunbound 'foo-test-map)))
+
+(ert-deftest help-fns-test-describe-keymap/symbol ()
+ (describe-keymap 'minibuffer-local-must-match-map)
+ (with-current-buffer "*Help*"
+ (should (looking-at "^minibuffer-local-must-match-map is"))))
+
+(ert-deftest help-fns-test-describe-keymap/value ()
+ (describe-keymap minibuffer-local-must-match-map)
+ (with-current-buffer "*Help*"
+ (should (looking-at "^key"))))
+
+(ert-deftest help-fns-test-describe-keymap/not-keymap ()
+ (should-error (describe-keymap nil))
+ (should-error (describe-keymap emacs-version)))
+
+(ert-deftest help-fns-test-describe-keymap/let-bound ()
+ (let ((foobar minibuffer-local-must-match-map))
+ (describe-keymap foobar)
+ (with-current-buffer "*Help*"
+ (should (looking-at "^key")))))
+
+(ert-deftest help-fns-test-describe-keymap/dynamically-bound-no-file ()
+ (setq help-fns-test--describe-keymap-foo minibuffer-local-must-match-map)
+ (describe-keymap 'help-fns-test--describe-keymap-foo)
+ (with-current-buffer "*Help*"
+ (should (looking-at "^help-fns-test--describe-keymap-foo is"))))
+
+;;; Tests for find-lisp-object-file-name
+(ert-deftest help-fns-test-bug24697-function-search ()
+ (should-not (find-lisp-object-file-name 'tab-width 1)))
+
+(ert-deftest help-fns-test-bug24697-non-internal-variable ()
+ (let ((help-fns--test-var (make-symbol "help-fns--test-var")))
+ ;; simulate an internal variable
+ (put help-fns--test-var 'variable-documentation 1)
+ (should-not (find-lisp-object-file-name help-fns--test-var 'defface))
+ (should-not (find-lisp-object-file-name help-fns--test-var 1))))
+
;;; help-fns-tests.el ends here
diff --git a/test/lisp/help-mode-tests.el b/test/lisp/help-mode-tests.el
new file mode 100644
index 00000000000..e0e82c9cc1a
--- /dev/null
+++ b/test/lisp/help-mode-tests.el
@@ -0,0 +1,169 @@
+;;; help-mode-tests.el --- Tests for help-mode.el -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+;; Author: Simen Heggestøyl <simenheg@gmail.com>
+;; Keywords:
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'ert)
+(require 'help-mode)
+(require 'pp)
+
+(ert-deftest help-mode-tests-help-buffer ()
+ (let ((help-xref-following nil))
+ (should (equal "*Help*" (help-buffer)))))
+
+(ert-deftest help-mode-tests-help-buffer-current-buffer ()
+ (with-temp-buffer
+ (help-mode)
+ (let ((help-xref-following t))
+ (should (equal (buffer-name (current-buffer))
+ (help-buffer))))))
+
+(ert-deftest help-mode-tests-help-buffer-current-buffer-error ()
+ (with-temp-buffer
+ (let ((help-xref-following t))
+ (should-error (help-buffer)))))
+
+(ert-deftest help-mode-tests-make-xrefs ()
+ (with-temp-buffer
+ (insert "car is a built-in function in ‘C source code’.
+
+(car LIST)
+
+ Probably introduced at or before Emacs version 1.2.
+ This function does not change global state, including the match data.
+
+Return the car of LIST. If arg is nil, return nil.
+Error if arg is not nil and not a cons cell. See also ‘car-safe’.
+
+See Info node ‘(elisp)Cons Cells’ for a discussion of related basic
+Lisp concepts such as car, cdr, cons cell and list.")
+ (help-mode)
+ (help-make-xrefs)
+ (let ((car-safe-button (button-at 298)))
+ (should (eq (button-type car-safe-button) 'help-symbol))
+ (should (eq (button-get car-safe-button 'help-function)
+ #'describe-symbol)))
+ (let ((cons-cells-info-button (button-at 333)))
+ (should (eq (button-type cons-cells-info-button) 'help-info))
+ (should (eq (button-get cons-cells-info-button 'help-function)
+ #'info)))))
+
+(ert-deftest help-mode-tests-xref-button ()
+ (with-temp-buffer
+ (insert "See also the function ‘interactive’.")
+ (string-match help-xref-symbol-regexp (buffer-string))
+ (help-xref-button 8 'help-function)
+ (should-not (button-at 22))
+ (should-not (button-at 35))
+ (let ((button (button-at 30)))
+ (should (eq (button-type button) 'help-function)))))
+
+(ert-deftest help-mode-tests-insert-xref-button ()
+ (with-temp-buffer
+ (help-insert-xref-button "[back]" 'help-back)
+ (goto-char (point-min))
+ (should (eq (button-type (button-at (point))) 'help-back))
+ (help-insert-xref-button "[forward]" 'help-forward)
+ ;; The back button should stay unchanged.
+ (should (eq (button-type (button-at (point))) 'help-back))))
+
+(ert-deftest help-mode-tests-xref-on-pp ()
+ (with-temp-buffer
+ (insert (pp '(cons fill-column)))
+ (help-xref-on-pp (point-min) (point-max))
+ (goto-char (point-min))
+ (search-forward "co")
+ (should (eq (button-type (button-at (point))) 'help-function))
+ (search-forward "-")
+ (should (eq (button-type (button-at (point))) 'help-variable))))
+
+(ert-deftest help-mode-tests-xref-go-back ()
+ (let ((help-xref-stack
+ `((2 ,(lambda () (erase-buffer) (insert "bar"))))))
+ (with-temp-buffer
+ (insert "foo")
+ (help-xref-go-back (current-buffer))
+ (should (= (point) 2))
+ (should (equal (buffer-string) "bar")))))
+
+(ert-deftest help-mode-tests-xref-go-forward ()
+ (let ((help-xref-forward-stack
+ `((2 ,(lambda () (erase-buffer) (insert "bar"))))))
+ (with-temp-buffer
+ (insert "foo")
+ (help-xref-go-forward (current-buffer))
+ (should (= (point) 2))
+ (should (equal (buffer-string) "bar")))))
+
+(ert-deftest help-mode-tests-go-back ()
+ (let ((help-xref-stack
+ `((2 ,(lambda () (erase-buffer) (insert "bar"))))))
+ (with-temp-buffer
+ (insert "foo")
+ (help-go-back)
+ (should (= (point) 2))
+ (should (equal (buffer-string) "bar")))))
+
+(ert-deftest help-mode-tests-go-back-no-stack ()
+ (let ((help-xref-stack '()))
+ (should-error (help-go-back))))
+
+(ert-deftest help-mode-tests-go-forward ()
+ (let ((help-xref-forward-stack
+ `((2 ,(lambda () (erase-buffer) (insert "bar"))))))
+ (with-temp-buffer
+ (insert "foo")
+ (help-go-forward)
+ (should (= (point) 2))
+ (should (equal (buffer-string) "bar")))))
+
+(ert-deftest help-mode-tests-go-forward-no-stack ()
+ (let ((help-xref-forward-stack '()))
+ (should-error (help-go-forward))))
+
+(ert-deftest help-mode-tests-do-xref ()
+ (with-temp-buffer
+ (help-mode)
+ (help-do-xref 0 #'describe-symbol '(car))
+ (should (looking-at-p "car is a"))
+ (should (string-match-p "[back]" (buffer-string)))))
+
+(ert-deftest help-mode-tests-follow-symbol ()
+ (with-temp-buffer
+ (insert "car")
+ (help-mode)
+ (help-follow-symbol 0)
+ (should (looking-at-p "car is a"))
+ (should (string-match-p "[back]" (buffer-string)))))
+
+(ert-deftest help-mode-tests-follow-symbol-no-symbol ()
+ (with-temp-buffer
+ (insert "fXYEWnRHI0B9w6VJqQIw")
+ (help-mode)
+ (should-error (help-follow-symbol 0))))
+
+(provide 'help-mode-tests)
+;;; help-mode-tests.el ends here
diff --git a/test/lisp/help-tests.el b/test/lisp/help-tests.el
index 1c432f58560..95557c95eb7 100644
--- a/test/lisp/help-tests.el
+++ b/test/lisp/help-tests.el
@@ -3,6 +3,8 @@
;; Copyright (C) 2019-2021 Free Software Foundation, Inc.
;; Author: Juanma Barranquero <lekktu@gmail.com>
+;; Eli Zaretskii <eliz@gnu.org>
+;; Stefan Kangas <stefankangas@gmail.com>
;; Keywords: help, internal
;; This file is part of GNU Emacs.
@@ -23,6 +25,7 @@
;;; Code:
(require 'ert)
+(eval-when-compile (require 'cl-lib))
(ert-deftest help-split-fundoc-SECTION ()
"Test new optional arg SECTION."
@@ -51,6 +54,350 @@
(should (equal (help-split-fundoc nil t 'usage) nil))
(should (equal (help-split-fundoc nil t 'doc) nil))))
+
+;;; substitute-command-keys
+
+(defmacro with-substitute-command-keys-test (&rest body)
+ `(cl-flet* ((test
+ (lambda (orig result)
+ (should (equal-including-properties
+ (substitute-command-keys orig)
+ result))))
+ (test-re
+ (lambda (orig regexp)
+ (should (string-match (concat "^" regexp "$")
+ (substitute-command-keys orig))))))
+ ,@body))
+
+(ert-deftest help-tests-substitute-command-keys/no-change ()
+ (with-substitute-command-keys-test
+ (test "foo" "foo")
+ (test "\\invalid-escape" "\\invalid-escape")))
+
+(ert-deftest help-tests-substitute-command-keys/commands ()
+ (with-substitute-command-keys-test
+ (test "foo \\[goto-char]" "foo M-g c")
+ (test "\\[next-line]" "C-n")
+ (test "\\[next-line]\n\\[next-line]" "C-n\nC-n")
+ (test "\\[next-line]\\[previous-line]" "C-nC-p")
+ (test "\\[next-line]\\=\\[previous-line]" "C-n\\[previous-line]")
+ ;; Allow any style of quotes, since the terminal might not support
+ ;; UTF-8. Same thing is done below.
+ (test-re "\\[next-line]`foo'" "C-n[`'‘]foo['’]")
+ (test "\\[emacs-version]" "M-x emacs-version")
+ (test "\\[emacs-version]\\[next-line]" "M-x emacs-versionC-n")
+ (test-re "\\[emacs-version]`foo'" "M-x emacs-version[`'‘]foo['’]")))
+
+(ert-deftest help-tests-substitute-command-keys/keymaps ()
+ (with-substitute-command-keys-test
+ (test "\\{minibuffer-local-must-match-map}"
+ "\
+key binding
+--- -------
+
+C-g abort-recursive-edit
+TAB minibuffer-complete
+C-j minibuffer-complete-and-exit
+RET minibuffer-complete-and-exit
+ESC Prefix Command
+SPC minibuffer-complete-word
+? minibuffer-completion-help
+<C-tab> file-cache-minibuffer-complete
+<XF86Back> previous-history-element
+<XF86Forward> next-history-element
+<down> next-line-or-history-element
+<next> next-history-element
+<prior> switch-to-completions
+<up> previous-line-or-history-element
+
+M-v switch-to-completions
+
+M-< minibuffer-beginning-of-buffer
+M-n next-history-element
+M-p previous-history-element
+M-r previous-matching-history-element
+M-s next-matching-history-element
+
+")))
+
+(ert-deftest help-tests-substitute-command-keys/keymap-change ()
+ (with-substitute-command-keys-test
+ (test "\\<minibuffer-local-must-match-map>\\[abort-recursive-edit]" "C-g")
+ (test "\\<emacs-lisp-mode-map>\\[eval-defun]" "C-M-x")))
+
+(defvar help-tests-remap-map
+ (let ((map (make-keymap)))
+ (define-key map (kbd "x") 'foo)
+ (define-key map (kbd "y") 'bar)
+ (define-key map [remap foo] 'bar)
+ map))
+
+(ert-deftest help-tests-substitute-command-keys/remap ()
+ (should (equal (substitute-command-keys "\\<help-tests-remap-map>\\[foo]") "y"))
+ (should (equal (substitute-command-keys "\\<help-tests-remap-map>\\[bar]") "y")))
+
+(ert-deftest help-tests-substitute-command-keys/undefined-map ()
+ (with-substitute-command-keys-test
+ (test-re "\\{foobar-map}"
+ "\nUses keymap [`'‘]foobar-map['’], which is not currently defined.\n")))
+
+(ert-deftest help-tests-substitute-command-keys/quotes ()
+ (with-substitute-command-keys-test
+ (let ((text-quoting-style 'curve))
+ (test "quotes ‘like this’" "quotes ‘like this’")
+ (test "`x'" "‘x’")
+ (test "`" "‘")
+ (test "'" "’")
+ (test "\\`" "\\‘"))
+ (let ((text-quoting-style 'straight))
+ (test "quotes `like this'" "quotes 'like this'")
+ (test "`x'" "'x'")
+ (test "`" "'")
+ (test "'" "'")
+ (test "\\`" "\\'"))
+ (let ((text-quoting-style 'grave))
+ (test "quotes `like this'" "quotes `like this'")
+ (test "`x'" "`x'")
+ (test "`" "`")
+ (test "'" "'")
+ (test "\\`" "\\`"))))
+
+(ert-deftest help-tests-substitute-command-keys/literals ()
+ (with-substitute-command-keys-test
+ (test "foo \\=\\[goto-char]" "foo \\[goto-char]")
+ (test "foo \\=\\=" "foo \\=")
+ (test "\\=\\=" "\\=")
+ (test "\\=\\[" "\\[")
+ (let ((text-quoting-style 'curve))
+ (test "\\=`x\\='" "`x'"))
+ (let ((text-quoting-style 'straight))
+ (test "\\=`x\\='" "`x'"))
+ (let ((text-quoting-style 'grave))
+ (test "\\=`x\\='" "`x'"))))
+
+(ert-deftest help-tests-substitute-command-keys/no-change ()
+ (with-substitute-command-keys-test
+ (test "\\[foobar" "\\[foobar")
+ (test "\\=" "\\=")))
+
+(ert-deftest help-tests-substitute-command-keys/multibyte ()
+ ;; Cannot use string= here, as that compares unibyte and multibyte
+ ;; strings not equal.
+ (should (compare-strings
+ (substitute-command-keys "\200 \\[goto-char]") nil nil
+ "\200 M-g c" nil nil)))
+
+(ert-deftest help-tests-substitute-command-keys/apropos ()
+ (save-window-excursion
+ (apropos "foo")
+ (switch-to-buffer "*Apropos*")
+ (goto-char (point-min))
+ (should (looking-at "Type RET on"))))
+
+(defvar help-tests-major-mode-map
+ (let ((map (make-keymap)))
+ (define-key map "x" 'foo-original)
+ (define-key map "1" 'foo-range)
+ (define-key map "2" 'foo-range)
+ (define-key map "3" 'foo-range)
+ (define-key map "4" 'foo-range)
+ (define-key map (kbd "C-e") 'foo-something)
+ (define-key map '[F1] 'foo-function-key1)
+ (define-key map "(" 'short-range)
+ (define-key map ")" 'short-range)
+ (define-key map "a" 'foo-other-range)
+ (define-key map "b" 'foo-other-range)
+ (define-key map "c" 'foo-other-range)
+ map))
+
+(define-derived-mode help-tests-major-mode nil
+ "Major mode for testing shadowing.")
+
+(defvar help-tests-minor-mode-map
+ (let ((map (make-keymap)))
+ (define-key map "x" 'foo-shadow)
+ (define-key map (kbd "C-e") 'foo-shadow)
+ map))
+
+(define-minor-mode help-tests-minor-mode
+ "Minor mode for testing shadowing.")
+
+(ert-deftest help-tests-substitute-command-keys/test-mode ()
+ (with-substitute-command-keys-test
+ (with-temp-buffer
+ (help-tests-major-mode)
+ (test "\\{help-tests-major-mode-map}"
+ "\
+key binding
+--- -------
+
+( .. ) short-range
+1 .. 4 foo-range
+a .. c foo-other-range
+
+C-e foo-something
+x foo-original
+<F1> foo-function-key1
+
+"))))
+
+(ert-deftest help-tests-substitute-command-keys/shadow ()
+ (with-substitute-command-keys-test
+ (with-temp-buffer
+ (help-tests-major-mode)
+ (help-tests-minor-mode)
+ (test "\\{help-tests-major-mode-map}"
+ "\
+key binding
+--- -------
+
+( .. ) short-range
+1 .. 4 foo-range
+a .. c foo-other-range
+
+C-e foo-something
+ (this binding is currently shadowed)
+x foo-original
+ (this binding is currently shadowed)
+<F1> foo-function-key1
+
+"))))
+
+(ert-deftest help-tests-substitute-command-keys/command-remap ()
+ (with-substitute-command-keys-test
+ (let ((help-tests-major-mode-map (make-keymap))) ; Protect from changes.
+ (with-temp-buffer
+ (help-tests-major-mode)
+ (define-key help-tests-major-mode-map [remap foo] 'bar)
+ (test "\\{help-tests-major-mode-map}"
+ "\
+key binding
+--- -------
+
+<remap> Prefix Command
+
+<remap> <foo> bar
+
+")))))
+
+(ert-deftest help-tests-describe-map-tree/no-menu-t ()
+ (with-temp-buffer
+ (let ((standard-output (current-buffer))
+ (map '(keymap . ((1 . foo)
+ (menu-bar keymap
+ (foo menu-item "Foo" foo
+ :enable mark-active
+ :help "Help text"))))))
+ (describe-map-tree map nil nil nil nil t nil nil nil)
+ (should (equal (buffer-string) "key binding
+--- -------
+
+C-a foo
+
+")))))
+
+(ert-deftest help-tests-describe-map-tree/no-menu-nil ()
+ (with-temp-buffer
+ (let ((standard-output (current-buffer))
+ (map '(keymap . ((1 . foo)
+ (menu-bar keymap
+ (foo menu-item "Foo" foo
+ :enable mark-active
+ :help "Help text"))))))
+ (describe-map-tree map nil nil nil nil nil nil nil nil)
+ (should (equal (buffer-string) "key binding
+--- -------
+
+C-a foo
+<menu-bar> Prefix Command
+
+<menu-bar> <foo> foo
+
+")))))
+
+(ert-deftest help-tests-describe-map-tree/mention-shadow-t ()
+ (with-temp-buffer
+ (let ((standard-output (current-buffer))
+ (map '(keymap . ((1 . foo)
+ (2 . bar))))
+ (shadow-maps '((keymap . ((1 . baz))))))
+ (describe-map-tree map t shadow-maps nil nil t nil nil t)
+ (should (equal (buffer-string) "key binding
+--- -------
+
+C-a foo
+ (this binding is currently shadowed)
+C-b bar
+
+")))))
+
+(ert-deftest help-tests-describe-map-tree/mention-shadow-nil ()
+ (with-temp-buffer
+ (let ((standard-output (current-buffer))
+ (map '(keymap . ((1 . foo)
+ (2 . bar))))
+ (shadow-maps '((keymap . ((1 . baz))))))
+ (describe-map-tree map t shadow-maps nil nil t nil nil nil)
+ (should (equal (buffer-string) "key binding
+--- -------
+
+C-b bar
+
+")))))
+
+(ert-deftest help-tests-describe-map-tree/partial-t ()
+ (with-temp-buffer
+ (let ((standard-output (current-buffer))
+ (map '(keymap . ((1 . foo)
+ (2 . undefined)))))
+ (describe-map-tree map t nil nil nil nil nil nil nil)
+ (should (equal (buffer-string) "key binding
+--- -------
+
+C-a foo
+
+")))))
+
+(ert-deftest help-tests-describe-map-tree/partial-nil ()
+ (with-temp-buffer
+ (let ((standard-output (current-buffer))
+ (map '(keymap . ((1 . foo)
+ (2 . undefined)))))
+ (describe-map-tree map nil nil nil nil nil nil nil nil)
+ (should (equal (buffer-string) "key binding
+--- -------
+
+C-a foo
+C-b undefined
+
+")))))
+
+(defvar help-tests--was-in-buffer nil)
+
+(ert-deftest help-substitute-command-keys/menu-filter-in-correct-buffer ()
+ "Evaluate menu-filter in the original buffer. See Bug#39149."
+ (unwind-protect
+ (progn
+ (define-key global-map (kbd "C-c C-l r")
+ `(menu-item "2" identity
+ :filter ,(lambda (cmd)
+ (setq help-tests--was-in-buffer
+ (current-buffer))
+ cmd)))
+ (with-temp-buffer
+ (substitute-command-keys "\\[identity]")
+ (should (eq help-tests--was-in-buffer
+ (current-buffer)))))
+ (setq help-tests--was-in-buffer nil)
+ (define-key global-map (kbd "C-c C-l r") nil)
+ (define-key global-map (kbd "C-c C-l") nil)))
+
+(ert-deftest help-substitute-command-keys/preserves-text-properties ()
+ "Check that we preserve text properties (Bug#17052)."
+ (should (equal (substitute-command-keys
+ (propertize "foo \\[save-buffer]" 'face 'bold))
+ (propertize "foo C-x C-s" 'face 'bold))))
+
(provide 'help-tests)
;;; help-tests.el ends here
diff --git a/test/lisp/hfy-cmap-resources/rgb.txt b/test/lisp/hfy-cmap-resources/rgb.txt
new file mode 100644
index 00000000000..f8e369fae2a
--- /dev/null
+++ b/test/lisp/hfy-cmap-resources/rgb.txt
@@ -0,0 +1,4 @@
+# test comment
+255 250 250 snow
+248 248 255 ghost white
+248 248 255 GhostWhite
diff --git a/test/lisp/hfy-cmap-tests.el b/test/lisp/hfy-cmap-tests.el
new file mode 100644
index 00000000000..7e0be3753b3
--- /dev/null
+++ b/test/lisp/hfy-cmap-tests.el
@@ -0,0 +1,55 @@
+;;; hfy-cmap-tests.el --- tests for hfy-cmap.el -*- lexical-binding: t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(require 'ert-x)
+(require 'hfy-cmap)
+
+(defconst hfy-cmap-tests--data
+ (concat "255 250 250 snow\n"
+ "248 248 255 ghost white\n"
+ "248 248 255 GhostWhite\n"))
+
+(defconst hfy-cmap-tests--parsed
+ '(("GhostWhite" 248 248 255)
+ ("ghost white" 248 248 255)
+ ("snow" 255 250 250)))
+
+(ert-deftest test-hfy-cmap--parse-buffer ()
+ (with-temp-buffer
+ (insert hfy-cmap-tests--data)
+ (should (equal (hfy-cmap--parse-buffer (current-buffer))
+ hfy-cmap-tests--parsed))))
+
+(ert-deftest test-htmlfontify-load-rgb-file ()
+ :tags '(:expensive-test)
+ (let (hfy-rgb-txt-color-map)
+ (htmlfontify-load-rgb-file (ert-resource-file "rgb.txt"))
+ (should (equal hfy-rgb-txt-color-map
+ hfy-cmap-tests--parsed))))
+
+(ert-deftest test-htmlfontify-load-rgb-file/non-existent-file ()
+ (let (hfy-rgb-txt-color-map)
+ (htmlfontify-load-rgb-file "/non/existent/file")
+ (should-not hfy-rgb-txt-color-map)))
+
+(provide 'hfy-cmap-tests)
+;;; hfy-cmap-tests.el ends here
diff --git a/test/lisp/hi-lock-tests.el b/test/lisp/hi-lock-tests.el
index 94dbc16a779..199512fe7de 100644
--- a/test/lisp/hi-lock-tests.el
+++ b/test/lisp/hi-lock-tests.el
@@ -5,18 +5,20 @@
;; Author: Tino Calancha <tino.calancha@gmail.com>
;; Keywords:
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Code:
@@ -48,5 +50,161 @@
;; Only one match, then we have used just 1 face
(should (equal hi-lock--unused-faces (cdr faces))))))
+(ert-deftest hi-lock-case-fold ()
+ "Test for case-sensitivity."
+ (let ((hi-lock-auto-select-face t))
+ (with-temp-buffer
+ (insert "a A b B\n")
+
+ (dotimes (_ 2) (highlight-regexp "[a]"))
+ (should (= (length (overlays-in (point-min) (point-max))) 2))
+ (unhighlight-regexp "[a]")
+ (should (= (length (overlays-in (point-min) (point-max))) 0))
+
+ (dotimes (_ 2) (highlight-regexp "[a]" nil nil "a"))
+ (should (= (length (overlays-in (point-min) (point-max))) 2))
+ (unhighlight-regexp "a")
+ (should (= (length (overlays-in (point-min) (point-max))) 0))
+
+ (dotimes (_ 2) (highlight-regexp "[A]" ))
+ (should (= (length (overlays-in (point-min) (point-max))) 1))
+ (unhighlight-regexp "[A]")
+ (should (= (length (overlays-in (point-min) (point-max))) 0))
+
+ (dotimes (_ 2) (highlight-regexp "[A]" nil nil "A"))
+ (should (= (length (overlays-in (point-min) (point-max))) 1))
+ (unhighlight-regexp "A")
+ (should (= (length (overlays-in (point-min) (point-max))) 0))
+
+ (let ((case-fold-search nil)) (dotimes (_ 2) (highlight-regexp "[a]")))
+ (should (= (length (overlays-in (point-min) (point-max))) 1))
+ (unhighlight-regexp "[a]")
+ (should (= (length (overlays-in (point-min) (point-max))) 0))
+
+ (dotimes (_ 2) (highlight-phrase "a a"))
+ (should (= (length (overlays-in (point-min) (point-max))) 1))
+ (unhighlight-regexp "a a")
+ (should (= (length (overlays-in (point-min) (point-max))) 0))
+
+ (let ((search-spaces-regexp search-whitespace-regexp)) (highlight-regexp "a a"))
+ (should (= (length (overlays-in (point-min) (point-max))) 1))
+ (cl-letf (((symbol-function 'completing-read)
+ (lambda (_prompt _coll _x _y _z _hist defaults)
+ (car defaults))))
+ (call-interactively 'unhighlight-regexp))
+ (should (= (length (overlays-in (point-min) (point-max))) 0))
+
+ (emacs-lisp-mode)
+ (setq font-lock-mode t)
+
+ (dotimes (_ 2) (highlight-regexp "[a]"))
+ (font-lock-ensure)
+ (should (memq 'hi-yellow (get-text-property 1 'face)))
+ (should (memq 'hi-yellow (get-text-property 3 'face)))
+ (let ((font-lock-fontified t)) (unhighlight-regexp "[a]"))
+ (should (null (get-text-property 3 'face)))
+
+ (dotimes (_ 2) (highlight-regexp "[a]" nil nil "a"))
+ (font-lock-ensure)
+ (should (memq 'hi-yellow (get-text-property 1 'face)))
+ (should (memq 'hi-yellow (get-text-property 3 'face)))
+ (let ((font-lock-fontified t)) (unhighlight-regexp "a"))
+ (should (null (get-text-property 3 'face)))
+
+ (dotimes (_ 2) (highlight-regexp "[A]" ))
+ (font-lock-ensure)
+ (should (null (get-text-property 1 'face)))
+ (should (memq 'hi-yellow (get-text-property 3 'face)))
+ (let ((font-lock-fontified t)) (unhighlight-regexp "[A]"))
+ (should (null (get-text-property 3 'face)))
+
+ (dotimes (_ 2) (highlight-regexp "[A]" nil nil "A"))
+ (font-lock-ensure)
+ (should (null (get-text-property 1 'face)))
+ (should (memq 'hi-yellow (get-text-property 3 'face)))
+ (let ((font-lock-fontified t)) (unhighlight-regexp "A"))
+ (should (null (get-text-property 3 'face)))
+
+ (let ((case-fold-search nil)) (dotimes (_ 2) (highlight-regexp "[a]")))
+ (font-lock-ensure)
+ (should (memq 'hi-yellow (get-text-property 1 'face)))
+ (should (null (get-text-property 3 'face)))
+ (let ((font-lock-fontified t)) (unhighlight-regexp "[a]"))
+ (should (null (get-text-property 1 'face)))
+
+ (dotimes (_ 2) (highlight-phrase "a a"))
+ (font-lock-ensure)
+ (should (memq 'hi-yellow (get-text-property 1 'face)))
+ (let ((font-lock-fontified t)) (unhighlight-regexp "a a"))
+ (should (null (get-text-property 1 'face)))
+
+ (let ((search-spaces-regexp search-whitespace-regexp)) (highlight-regexp "a a"))
+ (font-lock-ensure)
+ (should (memq 'hi-yellow (get-text-property 1 'face)))
+ (cl-letf (((symbol-function 'completing-read)
+ (lambda (_prompt _coll _x _y _z _hist defaults)
+ (car defaults)))
+ (font-lock-fontified t))
+ (call-interactively 'unhighlight-regexp))
+ (should (null (get-text-property 1 'face))))))
+
+(ert-deftest hi-lock-unhighlight ()
+ "Test for unhighlighting and `hi-lock--regexps-at-point'."
+ (let ((hi-lock-auto-select-face t))
+ (with-temp-buffer
+ (insert "aAbB\n")
+
+ (cl-letf (((symbol-function 'completing-read)
+ (lambda (_prompt _coll _x _y _z _hist defaults)
+ (car defaults))))
+
+ (highlight-regexp "a")
+ (highlight-regexp "b")
+ (should (= (length (overlays-in (point-min) (point-max))) 4))
+ ;; `hi-lock--regexps-at-point' should take regexp "a" at point 1,
+ ;; not the last regexp "b"
+ (goto-char 1)
+ (call-interactively 'unhighlight-regexp)
+ (should (= (length (overlays-in 1 3)) 0))
+ (should (= (length (overlays-in 3 5)) 2))
+ ;; Next call should unhighlight remaining regepxs
+ (call-interactively 'unhighlight-regexp)
+ (should (= (length (overlays-in 3 5)) 0))
+
+ ;; Test unhighlight all
+ (highlight-regexp "a")
+ (highlight-regexp "b")
+ (should (= (length (overlays-in (point-min) (point-max))) 4))
+ (unhighlight-regexp t)
+ (should (= (length (overlays-in (point-min) (point-max))) 0))
+
+ (emacs-lisp-mode)
+ (setq font-lock-mode t)
+
+ (highlight-regexp "a")
+ (highlight-regexp "b")
+ (font-lock-ensure)
+ (should (memq 'hi-yellow (get-text-property 1 'face)))
+ (should (memq 'hi-yellow (get-text-property 3 'face)))
+ ;; `hi-lock--regexps-at-point' should take regexp "a" at point 1,
+ ;; not the last regexp "b"
+ (goto-char 1)
+ (let ((font-lock-fontified t)) (call-interactively 'unhighlight-regexp))
+ (should (null (get-text-property 1 'face)))
+ (should (memq 'hi-yellow (get-text-property 3 'face)))
+ ;; Next call should unhighlight remaining regepxs
+ (let ((font-lock-fontified t)) (call-interactively 'unhighlight-regexp))
+ (should (null (get-text-property 3 'face)))
+
+ ;; Test unhighlight all
+ (highlight-regexp "a")
+ (highlight-regexp "b")
+ (font-lock-ensure)
+ (should (memq 'hi-yellow (get-text-property 1 'face)))
+ (should (memq 'hi-yellow (get-text-property 3 'face)))
+ (let ((font-lock-fontified t)) (unhighlight-regexp t))
+ (should (null (get-text-property 1 'face)))
+ (should (null (get-text-property 3 'face)))))))
+
(provide 'hi-lock-tests)
;;; hi-lock-tests.el ends here
diff --git a/test/lisp/ibuffer-tests.el b/test/lisp/ibuffer-tests.el
index b81c76aea31..a51079180a5 100644
--- a/test/lisp/ibuffer-tests.el
+++ b/test/lisp/ibuffer-tests.el
@@ -82,7 +82,7 @@
(test1 '((mode . org-mode)
(or (size-gt . 10000)
(and (not (starred-name))
- (directory . "\<org\>")))))
+ (directory . "<org>")))))
(test2 '((or (mode . emacs-lisp-mode) (file-extension . "elc?")
(and (starred-name) (name . "elisp"))
(mode . lisp-interaction-mode))))
diff --git a/test/lisp/image/gravatar-tests.el b/test/lisp/image/gravatar-tests.el
index 597125c525c..2324dc5e8b4 100644
--- a/test/lisp/image/gravatar-tests.el
+++ b/test/lisp/image/gravatar-tests.el
@@ -65,8 +65,13 @@
"Test `gravatar-build-url'."
(let ((gravatar-default-image nil)
(gravatar-force-default nil)
- (gravatar-size nil))
- (should (equal (gravatar-build-url "foo") "\
+ (gravatar-size nil)
+ (gravatar-service 'gravatar)
+ url)
+ (gravatar-build-url "foo" (lambda (u) (setq url u)))
+ (while (not url)
+ (sleep-for 0.01))
+ (should (equal url "\
https://www.gravatar.com/avatar/acbd18db4cc2f85cedef654fccc4a4d8?r=g"))))
;;; gravatar-tests.el ends here
diff --git a/test/lisp/imenu-tests.el b/test/lisp/imenu-tests.el
index de6163f5e1c..17f2501f67d 100644
--- a/test/lisp/imenu-tests.el
+++ b/test/lisp/imenu-tests.el
@@ -1,4 +1,4 @@
-;;; imenu-tests.el --- Test suite for imenu.
+;;; imenu-tests.el --- Test suite for imenu. -*- lexical-binding:t -*-
;; Copyright (C) 2013-2021 Free Software Foundation, Inc.
@@ -50,24 +50,23 @@
(setq input (cdr input)))))
result))
-(defmacro imenu-simple-scan-deftest (name doc major-mode content expected-items)
+(defmacro imenu-simple-scan-deftest (name doc mode content expected-items)
"Generate an ert test for mode-own imenu expression.
Run `imenu-create-index-function' at the buffer which content is
-CONTENT with MAJOR-MODE. A generated test runs `imenu-create-index-function'
-at the buffer which content is CONTENT with MAJOR-MODE. Then it compares a list
-of strings which are picked up from the result with EXPECTED-ITEMS."
+CONTENT with major MODE. A generated test runs `imenu-create-index-function'
+at the buffer which content is CONTENT with major MODE. Then it compares a
+list of strings which are picked up from the result with EXPECTED-ITEMS."
(let ((xname (intern (concat "imenu-simple-scan-deftest-" (symbol-name name)))))
`(ert-deftest ,xname ()
- ,doc
+ ,doc
(with-temp-buffer
(insert ,content)
- (funcall ',major-mode)
+ (funcall #',mode)
(let ((result-items (sort (imenu-simple-scan-deftest-gather-strings-from-list
(funcall imenu-create-index-function))
#'string-lessp))
(expected-items (sort (copy-sequence ,expected-items) #'string-lessp)))
- (should (equal result-items expected-items))
- )))))
+ (should (equal result-items expected-items)))))))
(imenu-simple-scan-deftest sh "Test imenu expression for sh-mode." sh-mode "a()
{
diff --git a/test/lisp/info-xref-tests.el b/test/lisp/info-xref-tests.el
index e7388d74440..95af21fb591 100644
--- a/test/lisp/info-xref-tests.el
+++ b/test/lisp/info-xref-tests.el
@@ -1,4 +1,4 @@
-;;; info-xref.el --- tests for info-xref.el
+;;; info-xref.el --- tests for info-xref.el -*- lexical-binding:t -*-
;; Copyright (C) 2013-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/international/ccl-tests.el b/test/lisp/international/ccl-tests.el
index 32f598688ee..0f765e4ff88 100644
--- a/test/lisp/international/ccl-tests.el
+++ b/test/lisp/international/ccl-tests.el
@@ -1,3 +1,5 @@
+;;; ccl-tests.el --- unit tests for ccl.el -*- lexical-binding:t -*-
+
;; Copyright (C) 2018-2021 Free Software Foundation, Inc.
;; This file is part of GNU Emacs.
@@ -230,3 +232,17 @@ At EOF:
(with-temp-buffer
(ccl-dump prog-midi-code)
(should (equal (buffer-string) prog-midi-dump))))
+
+(ert-deftest ccl-hash-table ()
+ (let ((sym (gensym))
+ (table (make-hash-table :test 'eq)))
+ (puthash 16 17 table)
+ (puthash 17 16 table)
+ (define-translation-hash-table sym table)
+ (let* ((prog `(2
+ ((loop
+ (lookup-integer ,sym r0 r1)))))
+ (compiled (ccl-compile prog))
+ (registers [17 0 0 0 0 0 0 0]))
+ (ccl-execute compiled registers)
+ (should (equal registers [2 16 0 0 0 0 0 1])))))
diff --git a/test/lisp/international/mule-tests.el b/test/lisp/international/mule-tests.el
index 767a128d626..7727c118b2c 100644
--- a/test/lisp/international/mule-tests.el
+++ b/test/lisp/international/mule-tests.el
@@ -23,6 +23,8 @@
;;; Code:
+(require 'ert-x) ;For `ert-run-keys'.
+
(ert-deftest find-auto-coding--bug27391 ()
"Check that Bug#27391 is fixed."
(with-temp-buffer
@@ -41,12 +43,32 @@
(should (not (multibyte-string-p (encode-coding-char ?a 'utf-8)))))
(ert-deftest mule-cmds--test-universal-coding-system-argument ()
- (skip-unless (not noninteractive))
(should (equal "ccccccccccccccccab"
- (let ((enable-recursive-minibuffers t)
- (unread-command-events
- (append (kbd "C-x RET c u t f - 8 RET C-u C-u c a b RET") nil)))
- (read-string "prompt:")))))
+ (let ((enable-recursive-minibuffers t))
+ (ert-simulate-keys
+ (kbd "C-x RET c u t f - 8 RET C-u C-u c a b RET")
+ (read-string "prompt:"))))))
+
+(ert-deftest mule-utf-7 ()
+ ;; utf-7 and utf-7-imap are not ASCII-compatible.
+ (should-not (coding-system-get 'utf-7 :ascii-compatible-p))
+ (should-not (coding-system-get 'utf-7-imap :ascii-compatible-p))
+ ;; Invariant ASCII subset.
+ (let ((s (apply #'string (append (number-sequence #x20 #x25)
+ (number-sequence #x27 #x7e)))))
+ (should (equal (encode-coding-string s 'utf-7-imap) s))
+ (should (equal (decode-coding-string s 'utf-7-imap) s)))
+ ;; Escaped ampersand.
+ (should (equal (encode-coding-string "a&bcd" 'utf-7-imap) "a&-bcd"))
+ (should (equal (decode-coding-string "a&-bcd" 'utf-7-imap) "a&bcd"))
+ ;; Ability to encode Unicode.
+ (should (equal (check-coding-systems-region "あ" nil '(utf-7-imap)) nil))
+ (should (equal (encode-coding-string "あ" 'utf-7-imap) "&MEI-"))
+ (should (equal (decode-coding-string "&MEI-" 'utf-7-imap) "あ")))
+
+(ert-deftest mule-hz ()
+ ;; The chinese-hz encoding is not ASCII compatible.
+ (should-not (coding-system-get 'chinese-hz :ascii-compatible-p)))
;; Stop "Local Variables" above causing confusion when visiting this file.
diff --git a/test/lisp/international/mule-util-tests.el b/test/lisp/international/mule-util-tests.el
index 8e49112d8e1..6518be66dbe 100644
--- a/test/lisp/international/mule-util-tests.el
+++ b/test/lisp/international/mule-util-tests.el
@@ -1,4 +1,4 @@
-;;; mule-util --- tests for international/mule-util.el
+;;; mule-util-tests.el --- tests for international/mule-util.el -*- lexical-binding:t -*-
;; Copyright (C) 2002-2021 Free Software Foundation, Inc.
@@ -75,10 +75,11 @@
(eval
`(ert-deftest ,testname ()
,testdoc
- (should (equal (apply 'truncate-string-to-width ',(car testdata))
- ,(cdr testdata)))))))
+ (let ((truncate-string-ellipsis "..."))
+ (should (equal (apply 'truncate-string-to-width ',(car testdata))
+ ,(cdr testdata))))))))
(dotimes (i (length mule-util-test-truncate-data))
(mule-util-test-truncate-create i))
-;;; mule-util.el ends here
+;;; mule-util-tests.el ends here
diff --git a/test/lisp/international/ucs-normalize-tests.el b/test/lisp/international/ucs-normalize-tests.el
index e8895c9abc7..a2da73767bc 100644
--- a/test/lisp/international/ucs-normalize-tests.el
+++ b/test/lisp/international/ucs-normalize-tests.el
@@ -307,7 +307,7 @@ implementations:
(list " var var))
(dolist (linos (seq-partition newval 8))
(insert (mapconcat #'number-to-string linos " ") "\n"))
- (insert ")\)"))
+ (insert "))"))
(defun ucs-normalize-check-failing-lines ()
(interactive)
@@ -341,4 +341,15 @@ implementations:
(display-buffer (current-buffer)))
(message "No changes to failing lines needed"))))
+(ert-deftest ucs-normalize-save-match-data ()
+ "Verify that match data isn't clobbered (bug#41445)"
+ (string-match (rx (+ digit)) "a47b")
+ (should (equal (match-data t) '(1 3)))
+ (should (equal
+ (decode-coding-string
+ (encode-coding-string "Käsesoßenrührlöffel" 'utf-8-hfs)
+ 'utf-8-hfs)
+ "Käsesoßenrührlöffel"))
+ (should (equal (match-data t) '(1 3))))
+
;;; ucs-normalize-tests.el ends here
diff --git a/test/lisp/isearch-tests.el b/test/lisp/isearch-tests.el
index b134567bc4b..9f3ac373126 100644
--- a/test/lisp/isearch-tests.el
+++ b/test/lisp/isearch-tests.el
@@ -4,18 +4,20 @@
;; Author: Artur Malabarba <bruce.connor.am@gmail.com>
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Code:
diff --git a/test/lisp/jit-lock-tests.el b/test/lisp/jit-lock-tests.el
index 8cbd06e3b33..121966b2b77 100644
--- a/test/lisp/jit-lock-tests.el
+++ b/test/lisp/jit-lock-tests.el
@@ -1,4 +1,4 @@
-;;; jit-lock-tests.el --- tests for jit-lock
+;;; jit-lock-tests.el --- tests for jit-lock -*- lexical-binding:t -*-
;; Copyright (C) 2016-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/json-tests.el b/test/lisp/json-tests.el
index a3b606ad5da..11b61d8b47e 100644
--- a/test/lisp/json-tests.el
+++ b/test/lisp/json-tests.el
@@ -1,31 +1,38 @@
-;;; json-tests.el --- Test suite for json.el
+;;; json-tests.el --- Test suite for json.el -*- lexical-binding:t -*-
;; Copyright (C) 2015-2021 Free Software Foundation, Inc.
;; Author: Dmitry Gutov <dgutov@yandex.ru>
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Code:
(require 'ert)
(require 'json)
+(require 'map)
+(require 'seq)
+
+(eval-when-compile
+ (require 'cl-lib))
(defmacro json-tests--with-temp-buffer (content &rest body)
"Create a temporary buffer with CONTENT and evaluate BODY there.
Point is moved to beginning of the buffer."
- (declare (indent 1))
+ (declare (debug t) (indent 1))
`(with-temp-buffer
(insert ,content)
(goto-char (point-min))
@@ -33,66 +40,107 @@ Point is moved to beginning of the buffer."
;;; Utilities
-(ert-deftest test-json-join ()
- (should (equal (json-join '() ", ") ""))
- (should (equal (json-join '("a" "b" "c") ", ") "a, b, c")))
-
(ert-deftest test-json-alist-p ()
(should (json-alist-p '()))
- (should (json-alist-p '((a 1) (b 2) (c 3))))
- (should (json-alist-p '((:a 1) (:b 2) (:c 3))))
- (should (json-alist-p '(("a" 1) ("b" 2) ("c" 3))))
+ (should (json-alist-p '((()))))
+ (should (json-alist-p '((a))))
+ (should (json-alist-p '((a . 1))))
+ (should (json-alist-p '((a . 1) (b 2) (c))))
+ (should (json-alist-p '((:a) (:b 2) (:c . 3))))
+ (should (json-alist-p '(("a" . 1) ("b" 2) ("c"))))
+ (should-not (json-alist-p '(())))
+ (should-not (json-alist-p '(a)))
+ (should-not (json-alist-p '(a . 1)))
+ (should-not (json-alist-p '((a . 1) . [])))
+ (should-not (json-alist-p '((a . 1) [])))
(should-not (json-alist-p '(:a :b :c)))
(should-not (json-alist-p '(:a 1 :b 2 :c 3)))
- (should-not (json-alist-p '((:a 1) (:b 2) 3))))
+ (should-not (json-alist-p '((:a 1) (:b 2) 3)))
+ (should-not (json-alist-p '((:a 1) (:b 2) ())))
+ (should-not (json-alist-p '(((a) 1) (b 2) (c 3))))
+ (should-not (json-alist-p []))
+ (should-not (json-alist-p [(a . 1)]))
+ (should-not (json-alist-p #s(hash-table))))
(ert-deftest test-json-plist-p ()
(should (json-plist-p '()))
+ (should (json-plist-p '(:a 1)))
(should (json-plist-p '(:a 1 :b 2 :c 3)))
+ (should (json-plist-p '(:a :b)))
+ (should (json-plist-p '(:a :b :c :d)))
+ (should-not (json-plist-p '(a)))
+ (should-not (json-plist-p '(a 1)))
(should-not (json-plist-p '(a 1 b 2 c 3)))
(should-not (json-plist-p '("a" 1 "b" 2 "c" 3)))
+ (should-not (json-plist-p '(:a)))
(should-not (json-plist-p '(:a :b :c)))
- (should-not (json-plist-p '((:a 1) (:b 2) (:c 3)))))
-
-(ert-deftest test-json-plist-reverse ()
- (should (equal (json--plist-reverse '()) '()))
- (should (equal (json--plist-reverse '(:a 1)) '(:a 1)))
- (should (equal (json--plist-reverse '(:a 1 :b 2 :c 3))
+ (should-not (json-plist-p '(:a 1 :b 2 :c)))
+ (should-not (json-plist-p '((:a 1))))
+ (should-not (json-plist-p '((:a 1) (:b 2) (:c 3))))
+ (should-not (json-plist-p []))
+ (should-not (json-plist-p [:a 1]))
+ (should-not (json-plist-p #s(hash-table))))
+
+(ert-deftest test-json-plist-nreverse ()
+ (should (equal (json--plist-nreverse '()) '()))
+ (should (equal (json--plist-nreverse (list :a 1)) '(:a 1)))
+ (should (equal (json--plist-nreverse (list :a 1 :b 2)) '(:b 2 :a 1)))
+ (should (equal (json--plist-nreverse (list :a 1 :b 2 :c 3))
'(:c 3 :b 2 :a 1))))
-(ert-deftest test-json-plist-to-alist ()
- (should (equal (json--plist-to-alist '()) '()))
- (should (equal (json--plist-to-alist '(:a 1)) '((:a . 1))))
- (should (equal (json--plist-to-alist '(:a 1 :b 2 :c 3))
- '((:a . 1) (:b . 2) (:c . 3)))))
-
(ert-deftest test-json-advance ()
(json-tests--with-temp-buffer "{ \"a\": 1 }"
(json-advance 0)
- (should (= (point) (point-min)))
+ (should (bobp))
+ (json-advance)
+ (should (= (point) (1+ (point-min))))
+ (json-advance 0)
+ (should (= (point) (1+ (point-min))))
+ (json-advance 1)
+ (should (= (point) (+ (point-min) 2)))
(json-advance 3)
- (should (= (point) (+ (point-min) 3)))))
+ (should (= (point) (+ (point-min) 5)))))
(ert-deftest test-json-peek ()
(json-tests--with-temp-buffer ""
(should (zerop (json-peek))))
(json-tests--with-temp-buffer "{ \"a\": 1 }"
- (should (equal (json-peek) ?{))))
+ (should (= (json-peek) ?\{))
+ (goto-char (1- (point-max)))
+ (should (= (json-peek) ?\}))
+ (json-advance)
+ (should (zerop (json-peek)))))
(ert-deftest test-json-pop ()
(json-tests--with-temp-buffer ""
(should-error (json-pop) :type 'json-end-of-file))
(json-tests--with-temp-buffer "{ \"a\": 1 }"
- (should (equal (json-pop) ?{))
- (should (= (point) (+ (point-min) 1)))))
+ (should (= (json-pop) ?\{))
+ (should (= (point) (1+ (point-min))))
+ (goto-char (1- (point-max)))
+ (should (= (json-pop) ?\}))
+ (should-error (json-pop) :type 'json-end-of-file)))
(ert-deftest test-json-skip-whitespace ()
+ (json-tests--with-temp-buffer ""
+ (json-skip-whitespace)
+ (should (bobp))
+ (should (eobp)))
+ (json-tests--with-temp-buffer "{}"
+ (json-skip-whitespace)
+ (should (bobp))
+ (json-advance)
+ (json-skip-whitespace)
+ (should (= (point) (1+ (point-min))))
+ (json-advance)
+ (json-skip-whitespace)
+ (should (eobp)))
(json-tests--with-temp-buffer "\t\r\n\f\b { \"a\": 1 }"
(json-skip-whitespace)
- (should (equal (char-after) ?\f)))
+ (should (= (json-peek) ?\f)))
(json-tests--with-temp-buffer "\t\r\n\t { \"a\": 1 }"
(json-skip-whitespace)
- (should (equal (char-after) ?{))))
+ (should (= (json-peek) ?\{))))
;;; Paths
@@ -113,59 +161,243 @@ Point is moved to beginning of the buffer."
(ert-deftest test-json-path-to-position-no-match ()
(let* ((json-string "{\"foo\": {\"bar\": \"baz\"}}")
(matched-path (json-path-to-position 5 json-string)))
- (should (null matched-path))))
+ (should-not matched-path)))
;;; Keywords
(ert-deftest test-json-read-keyword ()
(json-tests--with-temp-buffer "true"
- (should (json-read-keyword "true")))
+ (should (eq (json-read-keyword "true") t))
+ (should (eobp)))
+ (json-tests--with-temp-buffer "true "
+ (should (eq (json-read-keyword "true") t))
+ (should (eobp)))
+ (json-tests--with-temp-buffer "true}"
+ (should (eq (json-read-keyword "true") t))
+ (should (= (point) (+ (point-min) 4))))
+ (json-tests--with-temp-buffer "true false"
+ (should (eq (json-read-keyword "true") t))
+ (should (= (point) (+ (point-min) 5))))
+ (json-tests--with-temp-buffer "true }"
+ (should (eq (json-read-keyword "true") t))
+ (should (= (point) (+ (point-min) 5))))
+ (json-tests--with-temp-buffer "true |"
+ (should (eq (json-read-keyword "true") t))
+ (should (= (point) (+ (point-min) 5))))
+ (json-tests--with-temp-buffer "false"
+ (let ((json-false 'false))
+ (should (eq (json-read-keyword "false") 'false)))
+ (should (eobp)))
+ (json-tests--with-temp-buffer "null"
+ (let ((json-null 'null))
+ (should (eq (json-read-keyword "null") 'null)))
+ (should (eobp))))
+
+(ert-deftest test-json-read-keyword-invalid ()
+ (json-tests--with-temp-buffer ""
+ (should (equal (should-error (json-read-keyword ""))
+ '(json-unknown-keyword "")))
+ (should (equal (should-error (json-read-keyword "true"))
+ '(json-unknown-keyword ()))))
(json-tests--with-temp-buffer "true"
- (should-error
- (json-read-keyword "false") :type 'json-unknown-keyword))
+ (should (equal (should-error (json-read-keyword "false"))
+ '(json-unknown-keyword "true"))))
(json-tests--with-temp-buffer "foo"
- (should-error
- (json-read-keyword "foo") :type 'json-unknown-keyword)))
+ (should (equal (should-error (json-read-keyword "foo"))
+ '(json-unknown-keyword "foo")))
+ (should (equal (should-error (json-read-keyword "bar"))
+ '(json-unknown-keyword "bar"))))
+ (json-tests--with-temp-buffer " true"
+ (should (equal (should-error (json-read-keyword "true"))
+ '(json-unknown-keyword ()))))
+ (json-tests--with-temp-buffer "truefalse"
+ (should (equal (should-error (json-read-keyword "true"))
+ '(json-unknown-keyword "truefalse"))))
+ (json-tests--with-temp-buffer "true|"
+ (should (equal (should-error (json-read-keyword "true"))
+ '(json-unknown-keyword "true")))))
(ert-deftest test-json-encode-keyword ()
(should (equal (json-encode-keyword t) "true"))
- (should (equal (json-encode-keyword json-false) "false"))
- (should (equal (json-encode-keyword json-null) "null")))
+ (let ((json-false 'false))
+ (should (equal (json-encode-keyword 'false) "false"))
+ (should (equal (json-encode-keyword json-false) "false")))
+ (let ((json-null 'null))
+ (should (equal (json-encode-keyword 'null) "null"))
+ (should (equal (json-encode-keyword json-null) "null"))))
;;; Numbers
-(ert-deftest test-json-read-number ()
- (json-tests--with-temp-buffer "3"
- (should (= (json-read-number) 3)))
- (json-tests--with-temp-buffer "-5"
- (should (= (json-read-number) -5)))
- (json-tests--with-temp-buffer "123.456"
- (should (= (json-read-number) 123.456)))
- (json-tests--with-temp-buffer "1e3"
- (should (= (json-read-number) 1e3)))
- (json-tests--with-temp-buffer "2e+3"
- (should (= (json-read-number) 2e3)))
- (json-tests--with-temp-buffer "3E3"
- (should (= (json-read-number) 3e3)))
- (json-tests--with-temp-buffer "1e-7"
- (should (= (json-read-number) 1e-7)))
- (json-tests--with-temp-buffer "abc"
- (should-error (json-read-number) :type 'json-number-format)))
+(ert-deftest test-json-read-integer ()
+ (json-tests--with-temp-buffer "0 "
+ (should (= (json-read-number) 0))
+ (should (eobp)))
+ (json-tests--with-temp-buffer "-0 "
+ (should (= (json-read-number) 0))
+ (should (eobp)))
+ (json-tests--with-temp-buffer "3 "
+ (should (= (json-read-number) 3))
+ (should (eobp)))
+ (json-tests--with-temp-buffer "-10 "
+ (should (= (json-read-number) -10))
+ (should (eobp)))
+ (json-tests--with-temp-buffer (format "%d " (1+ most-positive-fixnum))
+ (should (= (json-read-number) (1+ most-positive-fixnum)))
+ (should (eobp)))
+ (json-tests--with-temp-buffer (format "%d " (1- most-negative-fixnum))
+ (should (= (json-read-number) (1- most-negative-fixnum)))
+ (should (eobp))))
+
+(ert-deftest test-json-read-fraction ()
+ (json-tests--with-temp-buffer "0.0 "
+ (should (= (json-read-number) 0.0))
+ (should (eobp)))
+ (json-tests--with-temp-buffer "-0.0 "
+ (should (= (json-read-number) 0.0))
+ (should (eobp)))
+ (json-tests--with-temp-buffer "0.01 "
+ (should (= (json-read-number) 0.01))
+ (should (eobp)))
+ (json-tests--with-temp-buffer "-0.01 "
+ (should (= (json-read-number) -0.01))
+ (should (eobp)))
+ (json-tests--with-temp-buffer "123.456 "
+ (should (= (json-read-number) 123.456))
+ (should (eobp)))
+ (json-tests--with-temp-buffer "-123.456 "
+ (should (= (json-read-number) -123.456))
+ (should (eobp))))
+
+(ert-deftest test-json-read-exponent ()
+ (json-tests--with-temp-buffer "0e0 "
+ (should (= (json-read-number) 0e0))
+ (should (eobp)))
+ (json-tests--with-temp-buffer "-0E0 "
+ (should (= (json-read-number) 0e0))
+ (should (eobp)))
+ (json-tests--with-temp-buffer "-0E+0 "
+ (should (= (json-read-number) 0e0))
+ (should (eobp)))
+ (json-tests--with-temp-buffer "0e-0 "
+ (should (= (json-read-number) 0e0))
+ (should (eobp)))
+ (json-tests--with-temp-buffer "12e34 "
+ (should (= (json-read-number) 12e34))
+ (should (eobp)))
+ (json-tests--with-temp-buffer "-12E34 "
+ (should (= (json-read-number) -12e34))
+ (should (eobp)))
+ (json-tests--with-temp-buffer "-12E+34 "
+ (should (= (json-read-number) -12e34))
+ (should (eobp)))
+ (json-tests--with-temp-buffer "12e-34 "
+ (should (= (json-read-number) 12e-34))
+ (should (eobp))))
+
+(ert-deftest test-json-read-fraction-exponent ()
+ (json-tests--with-temp-buffer "0.0e0 "
+ (should (= (json-read-number) 0.0e0))
+ (should (eobp)))
+ (json-tests--with-temp-buffer "-0.0E0 "
+ (should (= (json-read-number) 0.0e0))
+ (should (eobp)))
+ (json-tests--with-temp-buffer "0.12E-0 "
+ (should (= (json-read-number) 0.12e0))
+ (should (eobp)))
+ (json-tests--with-temp-buffer "-12.34e+56 "
+ (should (= (json-read-number) -12.34e+56))
+ (should (eobp))))
+
+(ert-deftest test-json-read-number-invalid ()
+ (cl-flet ((read (str)
+ ;; Return error and point resulting from reading STR.
+ (json-tests--with-temp-buffer str
+ (cons (should-error (json-read-number)) (point)))))
+ ;; POS is where each of its STRINGS becomes invalid.
+ (pcase-dolist (`(,pos . ,strings)
+ '((1 "" "+" "-" "." "e" "e1" "abc" "++0" "++1"
+ "+0" "+0.0" "+12" "+12.34" "+12.34e56"
+ ".0" "+.0" "-.0" ".12" "+.12" "-.12"
+ ".e0" "+.e0" "-.e0" ".0e0" "+.0e0" "-.0e0")
+ (2 "01" "1ee1" "1e++1")
+ (3 "-01")
+ (4 "0.0.0" "1.1.1" "1e1e1")
+ (5 "-0.0.0" "-1.1.1")))
+ ;; Expected error and point.
+ (let ((res `((json-number-format ,pos) . ,pos)))
+ (dolist (str strings)
+ (should (equal (read str) res)))))))
(ert-deftest test-json-encode-number ()
+ (should (equal (json-encode-number 0) "0"))
+ (should (equal (json-encode-number -0) "0"))
(should (equal (json-encode-number 3) "3"))
(should (equal (json-encode-number -5) "-5"))
- (should (equal (json-encode-number 123.456) "123.456")))
+ (should (equal (json-encode-number 123.456) "123.456"))
+ (let ((bignum (1+ most-positive-fixnum)))
+ (should (equal (json-encode-number bignum)
+ (number-to-string bignum)))))
-;; Strings
+;;; Strings
(ert-deftest test-json-read-escaped-char ()
(json-tests--with-temp-buffer "\\\""
- (should (equal (json-read-escaped-char) ?\"))))
+ (should (= (json-read-escaped-char) ?\"))
+ (should (eobp)))
+ (json-tests--with-temp-buffer "\\\\ "
+ (should (= (json-read-escaped-char) ?\\))
+ (should (= (point) (+ (point-min) 2))))
+ (json-tests--with-temp-buffer "\\b "
+ (should (= (json-read-escaped-char) ?\b))
+ (should (= (point) (+ (point-min) 2))))
+ (json-tests--with-temp-buffer "\\f "
+ (should (= (json-read-escaped-char) ?\f))
+ (should (= (point) (+ (point-min) 2))))
+ (json-tests--with-temp-buffer "\\n "
+ (should (= (json-read-escaped-char) ?\n))
+ (should (= (point) (+ (point-min) 2))))
+ (json-tests--with-temp-buffer "\\r "
+ (should (= (json-read-escaped-char) ?\r))
+ (should (= (point) (+ (point-min) 2))))
+ (json-tests--with-temp-buffer "\\t "
+ (should (= (json-read-escaped-char) ?\t))
+ (should (= (point) (+ (point-min) 2))))
+ (json-tests--with-temp-buffer "\\x "
+ (should (= (json-read-escaped-char) ?x))
+ (should (= (point) (+ (point-min) 2))))
+ (json-tests--with-temp-buffer "\\ud800\\uDC00 "
+ (should (= (json-read-escaped-char) #x10000))
+ (should (= (point) (+ (point-min) 12))))
+ (json-tests--with-temp-buffer "\\ud7ff\\udc00 "
+ (should (= (json-read-escaped-char) #xd7ff))
+ (should (= (point) (+ (point-min) 6))))
+ (json-tests--with-temp-buffer "\\uffff "
+ (should (= (json-read-escaped-char) #xffff))
+ (should (= (point) (+ (point-min) 6))))
+ (json-tests--with-temp-buffer "\\ufffff "
+ (should (= (json-read-escaped-char) #xffff))
+ (should (= (point) (+ (point-min) 6)))))
+
+(ert-deftest test-json-read-escaped-char-invalid ()
+ (json-tests--with-temp-buffer ""
+ (should-error (json-read-escaped-char)))
+ (json-tests--with-temp-buffer "\\"
+ (should-error (json-read-escaped-char) :type 'json-end-of-file))
+ (json-tests--with-temp-buffer "\\ufff "
+ (should (equal (should-error (json-read-escaped-char))
+ (list 'json-string-escape (+ (point-min) 2)))))
+ (json-tests--with-temp-buffer "\\ufffg "
+ (should (equal (should-error (json-read-escaped-char))
+ (list 'json-string-escape (+ (point-min) 2))))))
(ert-deftest test-json-read-string ()
+ (json-tests--with-temp-buffer ""
+ (should-error (json-read-string)))
(json-tests--with-temp-buffer "\"formfeed\f\""
- (should-error (json-read-string) :type 'json-string-format))
+ (should (equal (should-error (json-read-string))
+ '(json-string-format ?\f))))
+ (json-tests--with-temp-buffer "\"\""
+ (should (equal (json-read-string) "")))
(json-tests--with-temp-buffer "\"foo \\\"bar\\\"\""
(should (equal (json-read-string) "foo \"bar\"")))
(json-tests--with-temp-buffer "\"abcαβγ\""
@@ -175,57 +407,117 @@ Point is moved to beginning of the buffer."
;; Bug#24784
(json-tests--with-temp-buffer "\"\\uD834\\uDD1E\""
(should (equal (json-read-string) "\U0001D11E")))
+ (json-tests--with-temp-buffer "f"
+ (should-error (json-read-string) :type 'json-end-of-file))
(json-tests--with-temp-buffer "foo"
- (should-error (json-read-string) :type 'json-string-format)))
+ (should-error (json-read-string) :type 'json-end-of-file)))
(ert-deftest test-json-encode-string ()
+ (should (equal (json-encode-string "") "\"\""))
+ (should (equal (json-encode-string "a") "\"a\""))
(should (equal (json-encode-string "foo") "\"foo\""))
(should (equal (json-encode-string "a\n\fb") "\"a\\n\\fb\""))
(should (equal (json-encode-string "\nasdфыв\u001f\u007ffgh\t")
"\"\\nasdфыв\\u001f\u007ffgh\\t\"")))
(ert-deftest test-json-encode-key ()
+ (should (equal (json-encode-key "") "\"\""))
+ (should (equal (json-encode-key '##) "\"\""))
+ (should (equal (json-encode-key :) "\"\""))
(should (equal (json-encode-key "foo") "\"foo\""))
(should (equal (json-encode-key 'foo) "\"foo\""))
(should (equal (json-encode-key :foo) "\"foo\""))
- (should-error (json-encode-key 5) :type 'json-key-format)
- (should-error (json-encode-key ["foo"]) :type 'json-key-format)
- (should-error (json-encode-key '("foo")) :type 'json-key-format))
+ (should (equal (should-error (json-encode-key 5))
+ '(json-key-format 5)))
+ (should (equal (should-error (json-encode-key ["foo"]))
+ '(json-key-format ["foo"])))
+ (should (equal (should-error (json-encode-key '("foo")))
+ '(json-key-format ("foo")))))
;;; Objects
(ert-deftest test-json-new-object ()
(let ((json-object-type 'alist))
- (should (equal (json-new-object) '())))
+ (should-not (json-new-object)))
(let ((json-object-type 'plist))
- (should (equal (json-new-object) '())))
+ (should-not (json-new-object)))
(let* ((json-object-type 'hash-table)
(json-object (json-new-object)))
(should (hash-table-p json-object))
- (should (= (hash-table-count json-object) 0))))
+ (should (map-empty-p json-object))
+ (should (eq (hash-table-test json-object) #'equal))))
-(ert-deftest test-json-add-to-object ()
+(ert-deftest test-json-add-to-alist ()
(let* ((json-object-type 'alist)
- (json-key-type nil)
(obj (json-new-object)))
- (setq obj (json-add-to-object obj "a" 1))
- (setq obj (json-add-to-object obj "b" 2))
- (should (equal (assq 'a obj) '(a . 1)))
- (should (equal (assq 'b obj) '(b . 2))))
+ (let ((json-key-type nil))
+ (setq obj (json-add-to-object obj "a" 1))
+ (setq obj (json-add-to-object obj "b" 2))
+ (should (equal (assq 'a obj) '(a . 1)))
+ (should (equal (assq 'b obj) '(b . 2))))
+ (let ((json-key-type 'symbol))
+ (setq obj (json-add-to-object obj "c" 3))
+ (setq obj (json-add-to-object obj "d" 4))
+ (should (equal (assq 'c obj) '(c . 3)))
+ (should (equal (assq 'd obj) '(d . 4))))
+ (let ((json-key-type 'keyword))
+ (setq obj (json-add-to-object obj "e" 5))
+ (setq obj (json-add-to-object obj "f" 6))
+ (should (equal (assq :e obj) '(:e . 5)))
+ (should (equal (assq :f obj) '(:f . 6))))
+ (let ((json-key-type 'string))
+ (setq obj (json-add-to-object obj "g" 7))
+ (setq obj (json-add-to-object obj "h" 8))
+ (should (equal (assoc "g" obj) '("g" . 7)))
+ (should (equal (assoc "h" obj) '("h" . 8))))))
+
+(ert-deftest test-json-add-to-plist ()
(let* ((json-object-type 'plist)
- (json-key-type nil)
(obj (json-new-object)))
- (setq obj (json-add-to-object obj "a" 1))
- (setq obj (json-add-to-object obj "b" 2))
- (should (= (plist-get obj :a) 1))
- (should (= (plist-get obj :b) 2)))
+ (let ((json-key-type nil))
+ (setq obj (json-add-to-object obj "a" 1))
+ (setq obj (json-add-to-object obj "b" 2))
+ (should (= (plist-get obj :a) 1))
+ (should (= (plist-get obj :b) 2)))
+ (let ((json-key-type 'keyword))
+ (setq obj (json-add-to-object obj "c" 3))
+ (setq obj (json-add-to-object obj "d" 4))
+ (should (= (plist-get obj :c) 3))
+ (should (= (plist-get obj :d) 4)))
+ (let ((json-key-type 'symbol))
+ (setq obj (json-add-to-object obj "e" 5))
+ (setq obj (json-add-to-object obj "f" 6))
+ (should (= (plist-get obj 'e) 5))
+ (should (= (plist-get obj 'f) 6)))
+ (let ((json-key-type 'string))
+ (setq obj (json-add-to-object obj "g" 7))
+ (setq obj (json-add-to-object obj "h" 8))
+ (should (= (lax-plist-get obj "g") 7))
+ (should (= (lax-plist-get obj "h") 8)))))
+
+(ert-deftest test-json-add-to-hash-table ()
(let* ((json-object-type 'hash-table)
- (json-key-type nil)
(obj (json-new-object)))
- (setq obj (json-add-to-object obj "a" 1))
- (setq obj (json-add-to-object obj "b" 2))
- (should (= (gethash "a" obj) 1))
- (should (= (gethash "b" obj) 2))))
+ (let ((json-key-type nil))
+ (setq obj (json-add-to-object obj "a" 1))
+ (setq obj (json-add-to-object obj "b" 2))
+ (should (= (gethash "a" obj) 1))
+ (should (= (gethash "b" obj) 2)))
+ (let ((json-key-type 'string))
+ (setq obj (json-add-to-object obj "c" 3))
+ (setq obj (json-add-to-object obj "d" 4))
+ (should (= (gethash "c" obj) 3))
+ (should (= (gethash "d" obj) 4)))
+ (let ((json-key-type 'symbol))
+ (setq obj (json-add-to-object obj "e" 5))
+ (setq obj (json-add-to-object obj "f" 6))
+ (should (= (gethash 'e obj) 5))
+ (should (= (gethash 'f obj) 6)))
+ (let ((json-key-type 'keyword))
+ (setq obj (json-add-to-object obj "g" 7))
+ (setq obj (json-add-to-object obj "h" 8))
+ (should (= (gethash :g obj) 7))
+ (should (= (gethash :h obj) 8)))))
(ert-deftest test-json-read-object ()
(json-tests--with-temp-buffer "{ \"a\": 1, \"b\": 2 }"
@@ -238,94 +530,384 @@ Point is moved to beginning of the buffer."
(let* ((json-object-type 'hash-table)
(hash-table (json-read-object)))
(should (= (gethash "a" hash-table) 1))
- (should (= (gethash "b" hash-table) 2))))
+ (should (= (gethash "b" hash-table) 2)))))
+
+(ert-deftest test-json-read-object-empty ()
+ (json-tests--with-temp-buffer "{}"
+ (let ((json-object-type 'alist))
+ (should-not (save-excursion (json-read-object))))
+ (let ((json-object-type 'plist))
+ (should-not (save-excursion (json-read-object))))
+ (let* ((json-object-type 'hash-table)
+ (hash-table (json-read-object)))
+ (should (hash-table-p hash-table))
+ (should (map-empty-p hash-table)))))
+
+(ert-deftest test-json-read-object-invalid ()
+ (json-tests--with-temp-buffer "{ \"a\" 1, \"b\": 2 }"
+ (should (equal (should-error (json-read-object))
+ '(json-object-format ":" ?1))))
(json-tests--with-temp-buffer "{ \"a\": 1 \"b\": 2 }"
- (should-error (json-read-object) :type 'json-object-format)))
+ (should (equal (should-error (json-read-object))
+ '(json-object-format "," ?\")))))
+
+(ert-deftest test-json-read-object-function ()
+ (let* ((pre nil)
+ (post nil)
+ (keys '("b" "a"))
+ (json-pre-element-read-function
+ (lambda (key)
+ (setq pre 'pre)
+ (should (equal key (pop keys)))))
+ (json-post-element-read-function
+ (lambda () (setq post 'post))))
+ (json-tests--with-temp-buffer "{ \"b\": 2, \"a\": 1 }"
+ (json-read-object)
+ (should (eq pre 'pre))
+ (should (eq post 'post)))))
(ert-deftest test-json-encode-hash-table ()
- (let ((hash-table (make-hash-table))
- (json-encoding-object-sort-predicate 'string<)
+ (let ((json-encoding-object-sort-predicate nil)
(json-encoding-pretty-print nil))
- (puthash :a 1 hash-table)
- (puthash :b 2 hash-table)
- (puthash :c 3 hash-table)
- (should (equal (json-encode hash-table)
- "{\"a\":1,\"b\":2,\"c\":3}"))))
-
-(ert-deftest json-encode-simple-alist ()
- (let ((json-encoding-pretty-print nil))
- (should (equal (json-encode '((a . 1) (b . 2)))
- "{\"a\":1,\"b\":2}"))))
-
-(ert-deftest test-json-encode-plist ()
- (let ((plist '(:a 1 :b 2))
+ (should (equal (json-encode-hash-table #s(hash-table)) "{}"))
+ (should (equal (json-encode-hash-table #s(hash-table data (a 1)))
+ "{\"a\":1}"))
+ (should (member (json-encode-hash-table #s(hash-table data (b 2 a 1)))
+ '("{\"a\":1,\"b\":2}" "{\"b\":2,\"a\":1}")))
+ (should (member (json-encode-hash-table #s(hash-table data (c 3 b 2 a 1)))
+ '("{\"a\":1,\"b\":2,\"c\":3}"
+ "{\"a\":1,\"c\":3,\"b\":2}"
+ "{\"b\":2,\"a\":1,\"c\":3}"
+ "{\"b\":2,\"c\":3,\"a\":1}"
+ "{\"c\":3,\"a\":1,\"b\":2}"
+ "{\"c\":3,\"b\":2,\"a\":1}")))))
+
+(ert-deftest test-json-encode-hash-table-pretty ()
+ (let ((json-encoding-object-sort-predicate nil)
+ (json-encoding-pretty-print t)
+ (json-encoding-default-indentation " ")
+ (json-encoding-lisp-style-closings nil))
+ (should (equal (json-encode-hash-table #s(hash-table)) "{}"))
+ (should (equal (json-encode-hash-table #s(hash-table data (a 1)))
+ "{\n \"a\": 1\n}"))
+ (should (member (json-encode-hash-table #s(hash-table data (b 2 a 1)))
+ '("{\n \"a\": 1,\n \"b\": 2\n}"
+ "{\n \"b\": 2,\n \"a\": 1\n}")))
+ (should (member (json-encode-hash-table #s(hash-table data (c 3 b 2 a 1)))
+ '("{\n \"a\": 1,\n \"b\": 2,\n \"c\": 3\n}"
+ "{\n \"a\": 1,\n \"c\": 3,\n \"b\": 2\n}"
+ "{\n \"b\": 2,\n \"a\": 1,\n \"c\": 3\n}"
+ "{\n \"b\": 2,\n \"c\": 3,\n \"a\": 1\n}"
+ "{\n \"c\": 3,\n \"a\": 1,\n \"b\": 2\n}"
+ "{\n \"c\": 3,\n \"b\": 2,\n \"a\": 1\n}")))))
+
+(ert-deftest test-json-encode-hash-table-lisp-style ()
+ (let ((json-encoding-object-sort-predicate nil)
+ (json-encoding-pretty-print t)
+ (json-encoding-default-indentation " ")
+ (json-encoding-lisp-style-closings t))
+ (should (equal (json-encode-hash-table #s(hash-table)) "{}"))
+ (should (equal (json-encode-hash-table #s(hash-table data (a 1)))
+ "{\n \"a\": 1}"))
+ (should (member (json-encode-hash-table #s(hash-table data (b 2 a 1)))
+ '("{\n \"a\": 1,\n \"b\": 2}"
+ "{\n \"b\": 2,\n \"a\": 1}")))
+ (should (member (json-encode-hash-table #s(hash-table data (c 3 b 2 a 1)))
+ '("{\n \"a\": 1,\n \"b\": 2,\n \"c\": 3}"
+ "{\n \"a\": 1,\n \"c\": 3,\n \"b\": 2}"
+ "{\n \"b\": 2,\n \"a\": 1,\n \"c\": 3}"
+ "{\n \"b\": 2,\n \"c\": 3,\n \"a\": 1}"
+ "{\n \"c\": 3,\n \"a\": 1,\n \"b\": 2}"
+ "{\n \"c\": 3,\n \"b\": 2,\n \"a\": 1}")))))
+
+(ert-deftest test-json-encode-hash-table-sort ()
+ (let ((json-encoding-object-sort-predicate #'string<)
(json-encoding-pretty-print nil))
- (should (equal (json-encode plist) "{\"a\":1,\"b\":2}"))))
-
-(ert-deftest test-json-encode-plist-with-sort-predicate ()
- (let ((plist '(:c 3 :a 1 :b 2))
- (json-encoding-object-sort-predicate 'string<)
+ (pcase-dolist (`(,in . ,out)
+ '((#s(hash-table) . "{}")
+ (#s(hash-table data (a 1)) . "{\"a\":1}")
+ (#s(hash-table data (b 2 a 1)) . "{\"a\":1,\"b\":2}")
+ (#s(hash-table data (c 3 b 2 a 1))
+ . "{\"a\":1,\"b\":2,\"c\":3}")))
+ (let ((copy (map-pairs in)))
+ (should (equal (json-encode-hash-table in) out))
+ ;; Ensure sorting isn't destructive.
+ (should (seq-set-equal-p (map-pairs in) copy))))))
+
+(ert-deftest test-json-encode-alist ()
+ (let ((json-encoding-object-sort-predicate nil)
(json-encoding-pretty-print nil))
- (should (equal (json-encode plist) "{\"a\":1,\"b\":2,\"c\":3}"))))
+ (should (equal (json-encode-alist ()) "{}"))
+ (should (equal (json-encode-alist '((a . 1))) "{\"a\":1}"))
+ (should (equal (json-encode-alist '((b . 2) (a . 1))) "{\"b\":2,\"a\":1}"))
+ (should (equal (json-encode-alist '((c . 3) (b . 2) (a . 1)))
+ "{\"c\":3,\"b\":2,\"a\":1}"))))
+
+(ert-deftest test-json-encode-alist-pretty ()
+ (let ((json-encoding-object-sort-predicate nil)
+ (json-encoding-pretty-print t)
+ (json-encoding-default-indentation " ")
+ (json-encoding-lisp-style-closings nil))
+ (should (equal (json-encode-alist ()) "{}"))
+ (should (equal (json-encode-alist '((a . 1))) "{\n \"a\": 1\n}"))
+ (should (equal (json-encode-alist '((b . 2) (a . 1)))
+ "{\n \"b\": 2,\n \"a\": 1\n}"))
+ (should (equal (json-encode-alist '((c . 3) (b . 2) (a . 1)))
+ "{\n \"c\": 3,\n \"b\": 2,\n \"a\": 1\n}"))))
+
+(ert-deftest test-json-encode-alist-lisp-style ()
+ (let ((json-encoding-object-sort-predicate nil)
+ (json-encoding-pretty-print t)
+ (json-encoding-default-indentation " ")
+ (json-encoding-lisp-style-closings t))
+ (should (equal (json-encode-alist ()) "{}"))
+ (should (equal (json-encode-alist '((a . 1))) "{\n \"a\": 1}"))
+ (should (equal (json-encode-alist '((b . 2) (a . 1)))
+ "{\n \"b\": 2,\n \"a\": 1}"))
+ (should (equal (json-encode-alist '((c . 3) (b . 2) (a . 1)))
+ "{\n \"c\": 3,\n \"b\": 2,\n \"a\": 1}"))))
+
+(ert-deftest test-json-encode-alist-sort ()
+ (let ((json-encoding-object-sort-predicate #'string<)
+ (json-encoding-pretty-print nil))
+ (pcase-dolist (`(,in . ,out)
+ '((() . "{}")
+ (((a . 1)) . "{\"a\":1}")
+ (((b . 2) (a . 1)) . "{\"a\":1,\"b\":2}")
+ (((c . 3) (b . 2) (a . 1))
+ . "{\"a\":1,\"b\":2,\"c\":3}")))
+ (let ((copy (copy-alist in)))
+ (should (equal (json-encode-alist in) out))
+ ;; Ensure sorting isn't destructive (bug#40693).
+ (should (equal in copy))))))
-(ert-deftest test-json-encode-alist-with-sort-predicate ()
- (let ((alist '((:c . 3) (:a . 1) (:b . 2)))
- (json-encoding-object-sort-predicate 'string<)
+(ert-deftest test-json-encode-plist ()
+ (let ((json-encoding-object-sort-predicate nil)
(json-encoding-pretty-print nil))
- (should (equal (json-encode alist) "{\"a\":1,\"b\":2,\"c\":3}"))))
+ (should (equal (json-encode-plist ()) "{}"))
+ (should (equal (json-encode-plist '(:a 1)) "{\"a\":1}"))
+ (should (equal (json-encode-plist '(:b 2 :a 1)) "{\"b\":2,\"a\":1}"))
+ (should (equal (json-encode-plist '(:c 3 :b 2 :a 1))
+ "{\"c\":3,\"b\":2,\"a\":1}"))))
+
+(ert-deftest test-json-encode-plist-pretty ()
+ (let ((json-encoding-object-sort-predicate nil)
+ (json-encoding-pretty-print t)
+ (json-encoding-default-indentation " ")
+ (json-encoding-lisp-style-closings nil))
+ (should (equal (json-encode-plist ()) "{}"))
+ (should (equal (json-encode-plist '(:a 1)) "{\n \"a\": 1\n}"))
+ (should (equal (json-encode-plist '(:b 2 :a 1))
+ "{\n \"b\": 2,\n \"a\": 1\n}"))
+ (should (equal (json-encode-plist '(:c 3 :b 2 :a 1))
+ "{\n \"c\": 3,\n \"b\": 2,\n \"a\": 1\n}"))))
+
+(ert-deftest test-json-encode-plist-lisp-style ()
+ (let ((json-encoding-object-sort-predicate nil)
+ (json-encoding-pretty-print t)
+ (json-encoding-default-indentation " ")
+ (json-encoding-lisp-style-closings t))
+ (should (equal (json-encode-plist ()) "{}"))
+ (should (equal (json-encode-plist '(:a 1)) "{\n \"a\": 1}"))
+ (should (equal (json-encode-plist '(:b 2 :a 1))
+ "{\n \"b\": 2,\n \"a\": 1}"))
+ (should (equal (json-encode-plist '(:c 3 :b 2 :a 1))
+ "{\n \"c\": 3,\n \"b\": 2,\n \"a\": 1}"))))
+
+(ert-deftest test-json-encode-plist-sort ()
+ (let ((json-encoding-object-sort-predicate #'string<)
+ (json-encoding-pretty-print nil))
+ (pcase-dolist (`(,in . ,out)
+ '((() . "{}")
+ ((:a 1) . "{\"a\":1}")
+ ((:b 2 :a 1) . "{\"a\":1,\"b\":2}")
+ ((:c 3 :b 2 :a 1) . "{\"a\":1,\"b\":2,\"c\":3}")))
+ (let ((copy (copy-sequence in)))
+ (should (equal (json-encode-plist in) out))
+ ;; Ensure sorting isn't destructive.
+ (should (equal in copy))))))
(ert-deftest test-json-encode-list ()
- (let ((json-encoding-pretty-print nil))
- (should (equal (json-encode-list '(:a 1 :b 2))
- "{\"a\":1,\"b\":2}"))
- (should (equal (json-encode-list '((:a . 1) (:b . 2)))
- "{\"a\":1,\"b\":2}"))
- (should (equal (json-encode-list '(1 2 3 4)) "[1,2,3,4]"))))
+ (let ((json-encoding-object-sort-predicate nil)
+ (json-encoding-pretty-print nil))
+ (should (equal (json-encode-list ()) "{}"))
+ (should (equal (json-encode-list '(a)) "[\"a\"]"))
+ (should (equal (json-encode-list '(:a)) "[\"a\"]"))
+ (should (equal (json-encode-list '("a")) "[\"a\"]"))
+ (should (equal (json-encode-list '(a 1)) "[\"a\",1]"))
+ (should (equal (json-encode-list '("a" 1)) "[\"a\",1]"))
+ (should (equal (json-encode-list '(:a 1)) "{\"a\":1}"))
+ (should (equal (json-encode-list '((a . 1))) "{\"a\":1}"))
+ (should (equal (json-encode-list '((:a . 1))) "{\"a\":1}"))
+ (should (equal (json-encode-list '(:b 2 :a)) "[\"b\",2,\"a\"]"))
+ (should (equal (json-encode-list '(4 3 2 1)) "[4,3,2,1]"))
+ (should (equal (json-encode-list '(b 2 a 1)) "[\"b\",2,\"a\",1]"))
+ (should (equal (json-encode-list '(:b 2 :a 1)) "{\"b\":2,\"a\":1}"))
+ (should (equal (json-encode-list '((b . 2) (a . 1))) "{\"b\":2,\"a\":1}"))
+ (should (equal (json-encode-list '((:b . 2) (:a . 1)))
+ "{\"b\":2,\"a\":1}"))
+ (should (equal (json-encode-list '((a) 1)) "[[\"a\"],1]"))
+ (should (equal (json-encode-list '((:a) 1)) "[[\"a\"],1]"))
+ (should (equal (json-encode-list '(("a") 1)) "[[\"a\"],1]"))
+ (should (equal (json-encode-list '((a 1) 2)) "[[\"a\",1],2]"))
+ (should (equal (json-encode-list '((:a 1) 2)) "[{\"a\":1},2]"))
+ (should (equal (json-encode-list '(((a . 1)) 2)) "[{\"a\":1},2]"))
+ (should (equal (json-encode-list '(:a 1 :b (2))) "{\"a\":1,\"b\":[2]}"))
+ (should (equal (json-encode-list '((a . 1) (b 2))) "{\"a\":1,\"b\":[2]}"))
+ (should-error (json-encode-list '(a . 1)) :type 'wrong-type-argument)
+ (should-error (json-encode-list '((a . 1) 2)) :type 'wrong-type-argument)
+ (should (equal (should-error (json-encode-list []))
+ '(json-error [])))
+ (should (equal (should-error (json-encode-list [a]))
+ '(json-error [a])))))
;;; Arrays
(ert-deftest test-json-read-array ()
(let ((json-array-type 'vector))
+ (json-tests--with-temp-buffer "[]"
+ (should (equal (json-read-array) [])))
+ (json-tests--with-temp-buffer "[ ]"
+ (should (equal (json-read-array) [])))
+ (json-tests--with-temp-buffer "[1]"
+ (should (equal (json-read-array) [1])))
(json-tests--with-temp-buffer "[1, 2, \"a\", \"b\"]"
(should (equal (json-read-array) [1 2 "a" "b"]))))
(let ((json-array-type 'list))
+ (json-tests--with-temp-buffer "[]"
+ (should-not (json-read-array)))
+ (json-tests--with-temp-buffer "[ ]"
+ (should-not (json-read-array)))
+ (json-tests--with-temp-buffer "[1]"
+ (should (equal (json-read-array) '(1))))
(json-tests--with-temp-buffer "[1, 2, \"a\", \"b\"]"
(should (equal (json-read-array) '(1 2 "a" "b")))))
(json-tests--with-temp-buffer "[1 2]"
- (should-error (json-read-array) :type 'json-error)))
+ (should (equal (should-error (json-read-array))
+ '(json-array-format "," ?2)))))
+
+(ert-deftest test-json-read-array-function ()
+ (let* ((pre nil)
+ (post nil)
+ (keys '(0 1))
+ (json-pre-element-read-function
+ (lambda (key)
+ (setq pre 'pre)
+ (should (equal key (pop keys)))))
+ (json-post-element-read-function
+ (lambda () (setq post 'post))))
+ (json-tests--with-temp-buffer "[1, 0]"
+ (json-read-array)
+ (should (eq pre 'pre))
+ (should (eq post 'post)))))
(ert-deftest test-json-encode-array ()
- (let ((json-encoding-pretty-print nil))
- (should (equal (json-encode-array [1 2 "a" "b"])
- "[1,2,\"a\",\"b\"]"))))
+ (let ((json-encoding-object-sort-predicate nil)
+ (json-encoding-pretty-print nil))
+ (should (equal (json-encode-array ()) "[]"))
+ (should (equal (json-encode-array []) "[]"))
+ (should (equal (json-encode-array '(1)) "[1]"))
+ (should (equal (json-encode-array '[1]) "[1]"))
+ (should (equal (json-encode-array '(2 1)) "[2,1]"))
+ (should (equal (json-encode-array '[2 1]) "[2,1]"))
+ (should (equal (json-encode-array '[:b a 2 1]) "[\"b\",\"a\",2,1]"))))
+
+(ert-deftest test-json-encode-array-pretty ()
+ (let ((json-encoding-object-sort-predicate nil)
+ (json-encoding-pretty-print t)
+ (json-encoding-default-indentation " ")
+ (json-encoding-lisp-style-closings nil))
+ (should (equal (json-encode-array ()) "[]"))
+ (should (equal (json-encode-array []) "[]"))
+ (should (equal (json-encode-array '(1)) "[\n 1\n]"))
+ (should (equal (json-encode-array '[1]) "[\n 1\n]"))
+ (should (equal (json-encode-array '(2 1)) "[\n 2,\n 1\n]"))
+ (should (equal (json-encode-array '[2 1]) "[\n 2,\n 1\n]"))
+ (should (equal (json-encode-array '[:b a 2 1])
+ "[\n \"b\",\n \"a\",\n 2,\n 1\n]"))))
+
+(ert-deftest test-json-encode-array-lisp-style ()
+ (let ((json-encoding-object-sort-predicate nil)
+ (json-encoding-pretty-print t)
+ (json-encoding-default-indentation " ")
+ (json-encoding-lisp-style-closings t))
+ (should (equal (json-encode-array ()) "[]"))
+ (should (equal (json-encode-array []) "[]"))
+ (should (equal (json-encode-array '(1)) "[\n 1]"))
+ (should (equal (json-encode-array '[1]) "[\n 1]"))
+ (should (equal (json-encode-array '(2 1)) "[\n 2,\n 1]"))
+ (should (equal (json-encode-array '[2 1]) "[\n 2,\n 1]"))
+ (should (equal (json-encode-array '[:b a 2 1])
+ "[\n \"b\",\n \"a\",\n 2,\n 1]"))))
;;; Reader
(ert-deftest test-json-read ()
- (json-tests--with-temp-buffer "{ \"a\": 1 }"
- ;; We don't care exactly what the return value is (that is tested
- ;; in `test-json-read-object'), but it should parse without error.
- (should (json-read)))
+ (pcase-dolist (`(,fn . ,contents)
+ '((json-read-string "\"\"" "\"a\"")
+ (json-read-array "[]" "[1]")
+ (json-read-object "{}" "{\"a\":1}")
+ (json-read-keyword "null" "false" "true")
+ (json-read-number
+ "-0" "0" "1" "2" "3" "4" "5" "6" "7" "8" "9")))
+ (dolist (content contents)
+ ;; Check that leading whitespace is skipped.
+ (dolist (str (list content (concat " " content)))
+ (cl-letf* ((called nil)
+ ((symbol-function fn)
+ (lambda (&rest _) (setq called t))))
+ (json-tests--with-temp-buffer str
+ ;; We don't care exactly what the return value is (that is
+ ;; tested elsewhere), but it should parse without error.
+ (should (json-read))
+ (should called)))))))
+
+(ert-deftest test-json-read-invalid ()
(json-tests--with-temp-buffer ""
(should-error (json-read) :type 'json-end-of-file))
- (json-tests--with-temp-buffer "xxx"
- (let ((err (should-error (json-read) :type 'json-readtable-error)))
- (should (equal (cdr err) '(?x))))))
+ (json-tests--with-temp-buffer " "
+ (should-error (json-read) :type 'json-end-of-file))
+ (json-tests--with-temp-buffer "x"
+ (should (equal (should-error (json-read))
+ '(json-readtable-error ?x))))
+ (json-tests--with-temp-buffer " x"
+ (should (equal (should-error (json-read))
+ '(json-readtable-error ?x)))))
(ert-deftest test-json-read-from-string ()
- (let ((json-string "{ \"a\": 1 }"))
- (json-tests--with-temp-buffer json-string
- (should (equal (json-read-from-string json-string)
+ (dolist (str '("\"\"" "\"a\"" "[]" "[1]" "{}" "{\"a\":1}"
+ "null" "false" "true" "0" "123"))
+ (json-tests--with-temp-buffer str
+ (should (equal (json-read-from-string str)
(json-read))))))
-;;; JSON encoder
+;;; Encoder
(ert-deftest test-json-encode ()
+ (should (equal (json-encode t) "true"))
+ (let ((json-null 'null))
+ (should (equal (json-encode json-null) "null")))
+ (let ((json-false 'false))
+ (should (equal (json-encode json-false) "false")))
+ (should (equal (json-encode "") "\"\""))
(should (equal (json-encode "foo") "\"foo\""))
+ (should (equal (json-encode :) "\"\""))
+ (should (equal (json-encode :foo) "\"foo\""))
+ (should (equal (json-encode '(1)) "[1]"))
+ (should (equal (json-encode 'foo) "\"foo\""))
+ (should (equal (json-encode 0) "0"))
+ (should (equal (json-encode 123) "123"))
+ (let ((json-encoding-object-sort-predicate nil)
+ (json-encoding-pretty-print nil))
+ (should (equal (json-encode []) "[]"))
+ (should (equal (json-encode [1]) "[1]"))
+ (should (equal (json-encode #s(hash-table)) "{}"))
+ (should (equal (json-encode #s(hash-table data (a 1))) "{\"a\":1}")))
(with-temp-buffer
- (should-error (json-encode (current-buffer)) :type 'json-error)))
+ (should (equal (should-error (json-encode (current-buffer)))
+ (list 'json-error (current-buffer))))))
-;;; Pretty-print
+;;; Pretty printing & minimizing
(defun json-tests-equal-pretty-print (original &optional expected)
"Abort current test if pretty-printing ORIGINAL does not yield EXPECTED.
@@ -351,46 +933,45 @@ nil, ORIGINAL should stay unchanged by pretty-printing."
(json-tests-equal-pretty-print "0.123"))
(ert-deftest test-json-pretty-print-object ()
- ;; empty (regression test for bug#24252)
- (json-tests-equal-pretty-print
- "{}"
- "{\n}")
- ;; one pair
+ ;; Empty (regression test for bug#24252).
+ (json-tests-equal-pretty-print "{}")
+ ;; One pair.
(json-tests-equal-pretty-print
"{\"key\":1}"
"{\n \"key\": 1\n}")
- ;; two pairs
+ ;; Two pairs.
(json-tests-equal-pretty-print
"{\"key1\":1,\"key2\":2}"
"{\n \"key1\": 1,\n \"key2\": 2\n}")
- ;; embedded object
+ ;; Nested object.
(json-tests-equal-pretty-print
"{\"foo\":{\"key\":1}}"
"{\n \"foo\": {\n \"key\": 1\n }\n}")
- ;; embedded array
+ ;; Nested array.
(json-tests-equal-pretty-print
"{\"key\":[1,2]}"
"{\n \"key\": [\n 1,\n 2\n ]\n}"))
(ert-deftest test-json-pretty-print-array ()
- ;; empty
+ ;; Empty.
(json-tests-equal-pretty-print "[]")
- ;; one item
+ ;; One item.
(json-tests-equal-pretty-print
"[1]"
"[\n 1\n]")
- ;; two items
+ ;; Two items.
(json-tests-equal-pretty-print
"[1,2]"
"[\n 1,\n 2\n]")
- ;; embedded object
+ ;; Nested object.
(json-tests-equal-pretty-print
"[{\"key\":1}]"
"[\n {\n \"key\": 1\n }\n]")
- ;; embedded array
+ ;; Nested array.
(json-tests-equal-pretty-print
"[[1,2]]"
"[\n [\n 1,\n 2\n ]\n]"))
(provide 'json-tests)
+
;;; json-tests.el ends here
diff --git a/test/lisp/jsonrpc-tests.el b/test/lisp/jsonrpc-tests.el
index 8b41af1686d..ea340c370d1 100644
--- a/test/lisp/jsonrpc-tests.el
+++ b/test/lisp/jsonrpc-tests.el
@@ -5,18 +5,20 @@
;; Author: João Távora <joaotavora@gmail.com>
;; Keywords: tests
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
@@ -165,7 +167,7 @@
(ert-deftest deferred-action-toolate ()
:tags '(:expensive-test)
- "Deferred request fails because noone clears the flag."
+ "Deferred request fails because no one clears the flag."
(jsonrpc--with-emacsrpc-fixture (conn)
(should-error
(jsonrpc-request conn '+ [1 2]
diff --git a/test/lisp/mail/flow-fill-tests.el b/test/lisp/mail/flow-fill-tests.el
index c271069961d..ec5b984dc04 100644
--- a/test/lisp/mail/flow-fill-tests.el
+++ b/test/lisp/mail/flow-fill-tests.el
@@ -35,7 +35,8 @@
">>> unmuzzled ratsbane!\n"
">>>> Henceforth, the coding style is to be strictly \n"
">>>> enforced, including the use of only upper case.\n"
- ">>>>> I've noticed a lack of adherence to the coding \n"
+ ">>>>> I've noticed a lack of adherence to \n"
+ ">>>>> the coding \n"
">>>>> styles, of late.\n"
">>>>>> Any complaints?\n"))
(output
diff --git a/test/lisp/mail/footnote-tests.el b/test/lisp/mail/footnote-tests.el
index ff66aa121a8..731ba3e706b 100644
--- a/test/lisp/mail/footnote-tests.el
+++ b/test/lisp/mail/footnote-tests.el
@@ -5,18 +5,20 @@
;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
;; Keywords:
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Code:
diff --git a/test/lisp/mail/qp-tests.el b/test/lisp/mail/qp-tests.el
new file mode 100644
index 00000000000..89f02894ea8
--- /dev/null
+++ b/test/lisp/mail/qp-tests.el
@@ -0,0 +1,74 @@
+;;; qp-tests.el --- Tests for qp.el -*- lexical-binding:t; coding:utf-8 -*-
+
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+;; Author: Stefan Kangas <stefankangas@gmail.com>
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+(require 'qp)
+
+;; Quote by Antoine de Saint-Exupéry, Citadelle (1948)
+;; from https://en.wikipedia.org/wiki/Quoted-printable
+(defvar qp-tests-quote-qp
+ (concat "J'interdis aux marchands de vanter trop leurs marchandises. Car ils se font =\n"
+ "vite p=C3=A9dagogues et t'enseignent comme but ce qui n'est par essence qu'=\n"
+ "un moyen, et te trompant ainsi sur la route =C3=A0 suivre les voil=C3=A0 bi=\n"
+ "ent=C3=B4t qui te d=C3=A9gradent, car si leur musique est vulgaire ils te f=\n"
+ "abriquent pour te la vendre une =C3=A2me vulgaire."))
+(defvar qp-tests-quote-utf8
+ (concat "J'interdis aux marchands de vanter trop leurs marchandises. Car ils se font "
+ "vite pédagogues et t'enseignent comme but ce qui n'est par essence qu'"
+ "un moyen, et te trompant ainsi sur la route à suivre les voilà bi"
+ "entôt qui te dégradent, car si leur musique est vulgaire ils te f"
+ "abriquent pour te la vendre une âme vulgaire."))
+
+(ert-deftest qp-test--quoted-printable-decode-region ()
+ (with-temp-buffer
+ (insert qp-tests-quote-qp)
+ (encode-coding-region (point-min) (point-max) 'utf-8)
+ (quoted-printable-decode-region (point-min) (point-max) 'utf-8)
+ (should (equal (buffer-string) qp-tests-quote-utf8))))
+
+(ert-deftest qp-test--quoted-printable-decode-string ()
+ (should (equal (quoted-printable-decode-string "foo!") "foo!"))
+ (should (equal (quoted-printable-decode-string "=0C") "\^L"))
+ (should (equal (quoted-printable-decode-string "=3D") "="))
+ (should (equal (quoted-printable-decode-string "=A1Hola, se=F1or!?")
+ "\241Hola, se\361or!?")))
+
+(ert-deftest qp-test--quoted-printable-encode-region ()
+ (with-temp-buffer
+ (insert (make-string 26 ?=))
+ ;; (encode-coding-region (point-min) (point-max) 'utf-8)
+ (quoted-printable-encode-region (point-min) (point-max) t)
+ (should (equal (buffer-string)
+ (concat "=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D"
+ "=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=\n=3D")))))
+
+(ert-deftest qp-test--quoted-printable-encode-string ()
+ (should (equal (quoted-printable-encode-string "\241Hola, se\361or!?")
+ "=A1Hola, se=F1or!?"))
+ ;; Multibyte character.
+ (should-error (quoted-printable-encode-string "å")))
+
+(provide 'qp-tests)
+;;; qp-tests.el ends here
diff --git a/test/lisp/mail/rfc2045-tests.el b/test/lisp/mail/rfc2045-tests.el
new file mode 100644
index 00000000000..ac547aabe5b
--- /dev/null
+++ b/test/lisp/mail/rfc2045-tests.el
@@ -0,0 +1,37 @@
+;;; rfc2045-tests.el --- Tests for rfc2045.el -*- lexical-binding:t -*-
+
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+;; Author: Stefan Kangas <stefankangas@gmail.com>
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+(require 'rfc2045)
+
+(ert-deftest rfc2045-test-encode-string ()
+ (should (equal (rfc2045-encode-string "foo" "bar") "foo=bar"))
+ (should (equal (rfc2045-encode-string "foo" "bar-baz") "foo=bar-baz"))
+ (should (equal (rfc2045-encode-string "foo" "bar baz") "foo=\"bar baz\""))
+ (should (equal (rfc2045-encode-string "foo" "bar\tbaz") "foo=\"bar\tbaz\""))
+ (should (equal (rfc2045-encode-string "foo" "bar\nbaz") "foo=\"bar\nbaz\"")))
+
+(provide 'rfc2045-tests)
+;;; rfc2045-tests.el ends here
diff --git a/test/lisp/mail/rfc2368-tests.el b/test/lisp/mail/rfc2368-tests.el
new file mode 100644
index 00000000000..f997ea3ecb4
--- /dev/null
+++ b/test/lisp/mail/rfc2368-tests.el
@@ -0,0 +1,39 @@
+;;; rfc2368-tests.el --- Tests for rfc2368.el -*- lexical-binding:t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+(require 'rfc2368)
+
+(ert-deftest rfc2368-unhexify-string ()
+ (should (equal (rfc2368-unhexify-string "hello%20there") "hello there")))
+
+(ert-deftest rfc2368-parse-mailto-url ()
+ (should (equal (rfc2368-parse-mailto-url "mailto:foo@example.org?subject=Foo&bar=baz")
+ '(("To" . "foo@example.org") ("Subject" . "Foo") ("Bar" . "baz"))))
+ (should (equal (rfc2368-parse-mailto-url "mailto:foo@bar.com?to=bar@example.org")
+ '(("To" . "foo@bar.com, bar@example.org"))))
+ (should (equal (rfc2368-parse-mailto-url "mailto:foo@bar.com?subject=bar%20baz")
+ '(("To" . "foo@bar.com") ("Subject" . "bar baz")))))
+
+(provide 'rfc2368-tests)
+;;; rfc2368-tests.el ends here
diff --git a/test/lisp/mail/rfc822-tests.el b/test/lisp/mail/rfc822-tests.el
new file mode 100644
index 00000000000..3e36a61a1f3
--- /dev/null
+++ b/test/lisp/mail/rfc822-tests.el
@@ -0,0 +1,83 @@
+;;; rfc822-tests.el --- Tests for rfc822.el -*- lexical-binding:t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+(require 'rfc822)
+
+(defmacro rfc822-tests-deftest (email desc &optional valid)
+ `(ert-deftest ,(intern (format "rfc822-email-%s-%s"
+ (if valid "valid" "invalid")
+ desc)) ()
+ (if ,valid
+ (should (equal (rfc822-addresses ,email) (list ,email)))
+ (let ((addresses (rfc822-addresses ,email)))
+ ;; `rfc822-addresses' returns a string if parsing fails.
+ (while (and (consp addresses)
+ (not (eq (string-to-char (car addresses)) ?\()))
+ (setq addresses (cdr addresses)))
+ ;; Found saved error.
+ (should (= (length addresses) 1))))))
+
+;;;; Valid emails
+
+(rfc822-tests-deftest "email@example.org" "email" t)
+(rfc822-tests-deftest "firstname.lastname@example.org" "dot-in-address" t)
+(rfc822-tests-deftest "email@subdomain.example.org" "dot-in-subdomain" t)
+(rfc822-tests-deftest "firstname+lastname@example.org" "contains-plus-sign" t)
+(rfc822-tests-deftest "email@123.123.123.123" "domain-valid-ip" t)
+(rfc822-tests-deftest "email@[123.123.123.123]" "domain-valid-ip-square-bracket" t)
+(rfc822-tests-deftest "\"email\"@example.org" "quotes-around-email" t)
+(rfc822-tests-deftest "1234567890@example.org" "digits-in-address" t)
+(rfc822-tests-deftest "email@example-one.com" "dash-in-domain-name" t)
+(rfc822-tests-deftest "_______@example.org" "underscore-in-address" t)
+(rfc822-tests-deftest "email@example.name" "dotname-tld" t)
+(rfc822-tests-deftest "email@example.co.jp" "dot-in-tld" t)
+(rfc822-tests-deftest "firstname-lastname@example.org" "dash-in-address" t)
+(rfc822-tests-deftest "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm@example.org" "address-long" t)
+
+;;;; Invalid emails
+
+(rfc822-tests-deftest "#@%^%#$@#$@#.com" "garbage")
+(rfc822-tests-deftest "@example.org" "missing-username")
+(rfc822-tests-deftest "email@example@example.org" "two-at-signs")
+(rfc822-tests-deftest ".email@example.org" "address-leading-dot")
+(rfc822-tests-deftest "email.@example.org" "address-trailing-dot")
+(rfc822-tests-deftest "email..email@example.org" "address-multiple-dots")
+(rfc822-tests-deftest "email@example..org" "domain-multiple-dots")
+(rfc822-tests-deftest "email@example.org." "domain-trailing-dot")
+(rfc822-tests-deftest "email@.example.org" "domain-leading-dot")
+(rfc822-tests-deftest "test\\@test@example.org" "address-escaped-at-sign")
+
+;; FIXME: Should these fail?
+;; (rfc822-tests-deftest "plainaddress" "missing-at-sign-and-domain")
+;; (rfc822-tests-deftest "email@example.org (J. Random Hacker)" "text-following-email")
+;; (rfc822-tests-deftest "email@-example.org" "leading-dash-in-domain-is-invalid")
+;; (rfc822-tests-deftest "email@example-.org" "trailing-dash-in-domain-is-invalid")
+;; (rfc822-tests-deftest "あいうえお@example.org" "address-unicode-chars")
+;; (rfc822-tests-deftest "email.example.org" "missing-at")
+;; (rfc822-tests-deftest "email@111.222.333.44444" "invalid-IP-format")
+;; (rfc822-tests-deftest "email@domain" "missing-top-level-domain")
+;; (rfc822-tests-deftest "email@domain.web" ".web-is-not-a-valid-top-level-domain")
+
+(provide 'rfc822-tests)
+;;; rfc822-tests.el ends here
diff --git a/test/manual/rmailmm.el b/test/lisp/mail/rmailmm-tests.el
index 6cfeb16e5b2..a022008b534 100644
--- a/test/manual/rmailmm.el
+++ b/test/lisp/mail/rmailmm-tests.el
@@ -1,4 +1,4 @@
-;;; rmailmm.el --- tests for mail/rmailmm.el
+;;; rmailmm-tests.el --- Tests for rmailmm.el -*- lexical-binding:t -*-
;; Copyright (C) 2006-2021 Free Software Foundation, Inc.
@@ -19,27 +19,42 @@
;;; Commentary:
+;; Converted to ert from previous manual tests.
+
+;; FIXME: Some of these still lack a condition for success.
+
;;; Code:
+(require 'ert)
(require 'rmailmm)
-(defun rmailmm-test-handler ()
+(ert-deftest rmailmm-test-handler ()
"Test of a mail using no MIME parts at all."
(let ((mail "To: alex@gnu.org
Content-Type: text/plain; charset=koi8-r
Content-Transfer-Encoding: 8bit
MIME-Version: 1.0
-\372\304\322\301\327\323\324\327\325\312\324\305\41"))
- (switch-to-buffer (get-buffer-create "*test*"))
- (erase-buffer)
- (set-buffer-multibyte nil)
- (insert mail)
- (rmail-mime-show t)
- (set-buffer-multibyte t)))
+\372\304\322\301\327\323\324\327\325\312\324\305\41")
+ (correct "To: alex@gnu.org
+Content-Type: text/plain; charset=koi8-r
+Content-Transfer-Encoding: 8bit
+MIME-Version: 1.0
-(defun rmailmm-test-bulk-handler ()
+Здравствуйте!
+"))
+ (with-temp-buffer
+ (erase-buffer)
+ (set-buffer-multibyte nil)
+ (insert mail)
+ (rmail-mime-show t)
+ (set-buffer-multibyte t)
+ (should (equal (buffer-string) correct)))))
+
+;;;; FIXME: This doesn't seem to be working.
+(ert-deftest rmailmm-test-bulk-handler ()
"Test of a mail used as an example in RFC 2183."
+ :tags '(:unstable)
(let ((mail "Content-Type: image/jpeg
Content-Disposition: attachment; filename=genome.jpeg;
modification-date=\"Wed, 12 Feb 1997 16:29:51 -0500\";
@@ -54,13 +69,17 @@ WATQdRUvAK0Bnmshmtn79PpaLBbbOZkjKvRnjRZoRswOkG1wFchKew2g9wXVJVZL/m4+B+vv
UDwbgUEAUmk2Zyg101d6PhCDySgAvTvDgKiuOrc4dLxUb7UMnhGIexyI+d6U+ABuNAP4Simx
lgAAAABJRU5ErkJggg==
"))
- (switch-to-buffer (get-buffer-create "*test*"))
- (erase-buffer)
- (insert mail)
- (rmail-mime-show)))
-
-(defun rmailmm-test-multipart-handler ()
+ (with-temp-buffer
+ (erase-buffer)
+ (insert mail)
+ (rmail-mime-show)
+ ;; FIXME: What is the condition for success?
+ )))
+
+;; FIXME: Has no condition for success -- see below.
+(ert-deftest rmailmm-test-multipart-handler ()
"Test of a mail used as an example in RFC 2046."
+ :tags '(:unstable)
(let ((mail "From: Nathaniel Borenstein <nsb@bellcore.com>
To: Ned Freed <ned@innosoft.com>
Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST)
@@ -88,6 +107,11 @@ This is the epilogue. It is also to be ignored."))
(switch-to-buffer (get-buffer-create "*test*"))
(erase-buffer)
(insert mail)
- (rmail-mime-show t)))
+ (rmail-mime-show t)
+ ;; FIXME: What is the condition for success?
+ (should nil) ; expected fail for now
+ ))
+
+(provide 'rmailmm-tests)
-;;; rmailmm.el ends here
+;; rmailmm-tests.el ends here
diff --git a/test/lisp/mail/uudecode-tests.el b/test/lisp/mail/uudecode-tests.el
index c1b48dee7e8..6ff767562e3 100644
--- a/test/lisp/mail/uudecode-tests.el
+++ b/test/lisp/mail/uudecode-tests.el
@@ -24,15 +24,9 @@
;;; Code:
(require 'ert)
+(require 'ert-x)
(require 'uudecode)
-(defvar uudecode-tests-data-dir
- (file-truename
- (expand-file-name "uudecode-resources/"
- (file-name-directory (or load-file-name
- buffer-file-name))))
- "Base directory of uudecode-tests.el test data files.")
-
(defun uudecode-tests-read-file (file)
"Read contents of FILE and return as string."
(with-temp-buffer
@@ -40,13 +34,11 @@
(buffer-string)))
(defvar uudecode-tests-encoded-str
- (uudecode-tests-read-file
- (expand-file-name "uuencoded.txt" uudecode-tests-data-dir))
+ (uudecode-tests-read-file (ert-resource-file "uuencoded.txt"))
"Uuencoded data for bookmark-tests.el
Same as `uudecode-tests-decoded-str' but uuencoded.")
(defvar uudecode-tests-decoded-str
- (uudecode-tests-read-file
- (expand-file-name "uudecoded.txt" uudecode-tests-data-dir))
+ (uudecode-tests-read-file (ert-resource-file "uudecoded.txt"))
"Plain text data for bookmark-tests.el
Same as `uudecode-tests-encoded-str' but plain text.")
diff --git a/test/lisp/man-tests.el b/test/lisp/man-tests.el
index c0a4915895f..7fb0c5e9443 100644
--- a/test/lisp/man-tests.el
+++ b/test/lisp/man-tests.el
@@ -1,4 +1,4 @@
-;;; man-tests.el --- Test suite for man.
+;;; man-tests.el --- Test suite for man. -*- lexical-binding:t -*-
;; Copyright (C) 2013-2021 Free Software Foundation, Inc.
@@ -44,7 +44,7 @@ sinl [sin] (3) - sine function"
sin(3), sinf(3), sinl(3) - sine functions"
. (#("sin(3)" 0 6 (help-echo "sine functions")) #("sinf(3)" 0 7 (help-echo "sine functions")) #("sinl(3)" 0 7 (help-echo "sine functions"))))
;; SunOS, Solaris
- ;; http://docs.oracle.com/cd/E19455-01/805-6331/usradm-7/index.html
+ ;; https://docs.oracle.com/cd/E19455-01/805-6331/usradm-7/index.html
;; SunOS 4
("\
tset, reset (1) - establish or restore terminal characteristics"
@@ -61,7 +61,7 @@ cawf, nroff (1) - C version of the nroff-like, Amazingly Workable (text) Formatt
whatis (5) - database of online manual pages"
. (#("cawf(1)" 0 7 (help-echo "C version of the nroff-like, Amazingly Workable (text) Formatter")) #("nroff(1)" 0 8 (help-echo "C version of the nroff-like, Amazingly Workable (text) Formatter")) #("whatis(5)" 0 9 (help-echo "database of online manual pages"))))
;; HP-UX
- ;; http://docstore.mik.ua/manuals/hp-ux/en/B2355-60130/man.1.html
+ ;; https://docstore.mik.ua/manuals/hp-ux/en/B2355-60130/man.1.html
;; Assuming that the line break in the zgrep description was
;; introduced by the man page formatting.
("\
@@ -114,7 +114,7 @@ in the cdr of the element.")
(dolist (test man-tests-parse-man-k-tests)
(should (man-tests-parse-man-k-test-case test))))
-(defun man-tests-filter-strings (buffer strings)
+(defun man-tests-filter-strings (_buffer strings)
"Run `Man-bgproc-filter' on each of STRINGS.
The formatted result will be inserted into BUFFER."
(let ((proc (start-process "dummy man-tests proc" (current-buffer) "cat")))
diff --git a/test/lisp/minibuffer-resources/data/minibuffer-test-cttq$tion b/test/lisp/minibuffer-resources/data/minibuffer-test-cttq$tion
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/test/lisp/minibuffer-resources/data/minibuffer-test-cttq$tion
diff --git a/test/lisp/minibuffer-resources/lisp/cedet/semantic-utest-c.test b/test/lisp/minibuffer-resources/lisp/cedet/semantic-utest-c.test
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/test/lisp/minibuffer-resources/lisp/cedet/semantic-utest-c.test
diff --git a/test/lisp/minibuffer-resources/lisp/cedet/semantic-utest.test b/test/lisp/minibuffer-resources/lisp/cedet/semantic-utest.test
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/test/lisp/minibuffer-resources/lisp/cedet/semantic-utest.test
diff --git a/test/lisp/minibuffer-tests.el b/test/lisp/minibuffer-tests.el
index 4bd41b590db..3ebca14a284 100644
--- a/test/lisp/minibuffer-tests.el
+++ b/test/lisp/minibuffer-tests.el
@@ -5,18 +5,20 @@
;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
;; Keywords:
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
@@ -24,6 +26,9 @@
;;; Code:
+(require 'ert)
+(require 'ert-x)
+
(eval-when-compile (require 'cl-lib))
(ert-deftest completion-test1 ()
@@ -83,7 +88,7 @@
(ert-deftest completion-table-test-quoting ()
(let ((process-environment
`("CTTQ1=ed" "CTTQ2=et/" ,@process-environment))
- (default-directory (expand-file-name "test" source-directory)))
+ (default-directory (ert-resource-directory)))
(pcase-dolist (`(,input ,output)
'(
;; Test that $ in files is properly $$ quoted.
diff --git a/test/lisp/misc-tests.el b/test/lisp/misc-tests.el
new file mode 100644
index 00000000000..a519fd1ee62
--- /dev/null
+++ b/test/lisp/misc-tests.el
@@ -0,0 +1,77 @@
+;;; misc-tests.el --- Tests for misc.el -*- lexical-binding:t -*-
+
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+;; Author: Stefan Kangas <stefankangas@gmail.com>
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+
+(defmacro with-misc-test (original result &rest body)
+ (declare (indent 2))
+ `(with-temp-buffer
+ (insert ,original)
+ ,@body
+ (should (equal (buffer-string) ,result))))
+
+(ert-deftest misc-test-copy-from-above-command ()
+ (with-misc-test "abc\n" "abc\nabc"
+ (copy-from-above-command))
+ (with-misc-test "abc\n" "abc\nab"
+ (copy-from-above-command 2)))
+
+(ert-deftest misc-test-zap-up-to-char ()
+ (with-misc-test "abcde" "cde"
+ (goto-char (point-min))
+ (zap-up-to-char 1 ?c))
+ (with-misc-test "abcde abc123" "c123"
+ (goto-char (point-min))
+ (zap-up-to-char 2 ?c)))
+
+(ert-deftest misc-test-upcase-char ()
+ (with-misc-test "abcde" "aBCDe"
+ (goto-char (1+ (point-min)))
+ (upcase-char 3)))
+
+(ert-deftest misc-test-forward-to-word ()
+ (with-temp-buffer
+ (insert " - abc")
+ (goto-char (point-min))
+ (forward-to-word 1)
+ (should (equal (point) 9)))
+ (with-temp-buffer
+ (insert "a b c")
+ (goto-char (point-min))
+ (forward-to-word 3)
+ (should (equal (point) 6))))
+
+(ert-deftest misc-test-backward-to-word ()
+ (with-temp-buffer
+ (insert "abc - ")
+ (backward-to-word 1)
+ (should (equal (point) 4)))
+ (with-temp-buffer
+ (insert "a b c")
+ (backward-to-word 3)
+ (should (equal (point) 1))))
+
+(provide 'misc-tests)
+;;; misc-tests.el ends here
diff --git a/test/lisp/mwheel-tests.el b/test/lisp/mwheel-tests.el
new file mode 100644
index 00000000000..058f1a8afb1
--- /dev/null
+++ b/test/lisp/mwheel-tests.el
@@ -0,0 +1,46 @@
+;;; mwheel-tests.el --- tests for mwheel.el -*- lexical-binding:t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(require 'mwheel)
+
+(ert-deftest mwheel-test-enable/disable ()
+ (mouse-wheel-mode 1)
+ (should (eq (lookup-key (current-global-map) `[,mouse-wheel-up-event]) 'mwheel-scroll))
+ (mouse-wheel-mode -1)
+ (should (eq (lookup-key (current-global-map) `[,mouse-wheel-up-event]) nil)))
+
+(ert-deftest mwheel-test--create-scroll-keys ()
+ (should (equal (mouse-wheel--create-scroll-keys 10 'mouse-4)
+ '([mouse-4]
+ [left-margin mouse-4] [right-margin mouse-4]
+ [left-fringe mouse-4] [right-fringe mouse-4]
+ [vertical-scroll-bar mouse-4] [horizontal-scroll-bar mouse-4]
+ [mode-line mouse-4] [header-line mouse-4])))
+ ;; Don't bind modifiers outside of buffer area (e.g. for fringes).
+ (should (equal (mouse-wheel--create-scroll-keys '((shift) . 1) 'mouse-4)
+ '([(shift mouse-4)])))
+ (should (equal (mouse-wheel--create-scroll-keys '((control) . 9) 'mouse-7)
+ '([(control mouse-7)])))
+ (should (equal (mouse-wheel--create-scroll-keys '((meta) . 5) 'mouse-5)
+ '([(meta mouse-5)]))))
+
+;;; mwheel-tests.el ends here
diff --git a/test/lisp/net/browse-url-tests.el b/test/lisp/net/browse-url-tests.el
new file mode 100644
index 00000000000..898bef8513b
--- /dev/null
+++ b/test/lisp/net/browse-url-tests.el
@@ -0,0 +1,119 @@
+;;; browse-url-tests.el --- Tests for browse-url.el -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+;; Author: Simen Heggestøyl <simenheg@gmail.com>
+;; Keywords:
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'browse-url)
+(require 'ert)
+
+(ert-deftest browse-url-tests-browser-kind ()
+ (should (eq (browse-url--browser-kind #'browse-url-w3 "gnu.org")
+ 'internal))
+ (should
+ (eq (browse-url--browser-kind #'browse-url-firefox "gnu.org")
+ 'external)))
+
+(ert-deftest browse-url-tests-non-html-file-url-p ()
+ (should (browse-url--non-html-file-url-p "file://foo.txt"))
+ (should-not (browse-url--non-html-file-url-p "file://foo.html")))
+
+(ert-deftest browse-url-tests-select-handler-mailto ()
+ (should (eq (browse-url-select-handler "mailto:foo@bar.org")
+ 'browse-url--mailto))
+ (should (eq (browse-url-select-handler "mailto:foo@bar.org"
+ 'internal)
+ 'browse-url--mailto))
+ (should-not (browse-url-select-handler "mailto:foo@bar.org"
+ 'external)))
+
+(ert-deftest browse-url-tests-select-handler-man ()
+ (should (eq (browse-url-select-handler "man:ls") 'browse-url--man))
+ (should (eq (browse-url-select-handler "man:ls" 'internal)
+ 'browse-url--man))
+ (should-not (browse-url-select-handler "man:ls" 'external)))
+
+(ert-deftest browse-url-tests-select-handler-file ()
+ (should (eq (browse-url-select-handler "file://foo.txt")
+ 'browse-url-emacs))
+ (should (eq (browse-url-select-handler "file://foo.txt" 'internal)
+ 'browse-url-emacs))
+ (should-not (browse-url-select-handler "file://foo.txt" 'external)))
+
+(ert-deftest browse-url-tests-url-encode-chars ()
+ (should (equal (browse-url-url-encode-chars "foobar" "[ob]")
+ "f%6F%6F%62ar")))
+
+(ert-deftest browse-url-tests-encode-url ()
+ (should (equal (browse-url-encode-url "") ""))
+ (should (equal (browse-url-encode-url "a b c") "a b c"))
+ (should (equal (browse-url-encode-url "\"a\" \"b\"")
+ "\"a%22\"b\""))
+ (should (equal (browse-url-encode-url "(a) (b)") "(a%29(b)"))
+ (should (equal (browse-url-encode-url "a$ b$") "a%24b$")))
+
+(ert-deftest browse-url-tests-url-at-point ()
+ (with-temp-buffer
+ (insert "gnu.org")
+ (should (equal (browse-url-url-at-point) "http://gnu.org"))))
+
+(ert-deftest browse-url-tests-file-url ()
+ (should (equal (browse-url-file-url "/foo") "file:///foo"))
+ (should (equal (browse-url-file-url "/foo:") "ftp://foo/"))
+ (should (equal (browse-url-file-url "/ftp@foo:") "ftp://foo/"))
+ (should (equal (browse-url-file-url "/anonymous@foo:")
+ "ftp://foo/")))
+
+(ert-deftest browse-url-tests-delete-temp-file ()
+ (let ((browse-url-temp-file-name
+ (make-temp-file "browse-url-tests-")))
+ (browse-url-delete-temp-file)
+ (should-not (file-exists-p browse-url-temp-file-name)))
+ (let ((file (make-temp-file "browse-url-tests-")))
+ (browse-url-delete-temp-file file)
+ (should-not (file-exists-p file))))
+
+(ert-deftest browse-url-tests-add-buttons ()
+ (with-temp-buffer
+ (insert "Visit https://gnu.org")
+ (goto-char (point-min))
+ (browse-url-add-buttons)
+ (goto-char (- (point-max) 1))
+ (should (eq (get-text-property (point) 'face)
+ 'browse-url-button))
+ (should (get-text-property (point) 'browse-url-data))))
+
+(ert-deftest browse-url-tests-button-copy ()
+ (with-temp-buffer
+ (insert "Visit https://gnu.org")
+ (goto-char (point-min))
+ (browse-url-add-buttons)
+ (should-error (browse-url-button-copy))
+ (goto-char (- (point-max) 1))
+ (browse-url-button-copy)
+ (should (equal (car kill-ring) "https://gnu.org"))))
+
+(provide 'browse-url-tests)
+;;; browse-url-tests.el ends here
diff --git a/test/lisp/net/dbus-resources/org.gnu.Emacs.TestDBus.xml b/test/lisp/net/dbus-resources/org.gnu.Emacs.TestDBus.xml
new file mode 100644
index 00000000000..620f10510f2
--- /dev/null
+++ b/test/lisp/net/dbus-resources/org.gnu.Emacs.TestDBus.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.freedesktop.DBus.Introspectable">
+ <method name="Introspect">
+ <arg name="xml" type="s" direction="out"/>
+ </method>
+ </interface>
+ <interface name="org.freedesktop.DBus.Properties">
+ <method name="Get">
+ <arg name="interface" type="s" direction="in"/>
+ <arg name="name" type="s" direction="in"/>
+ <arg name="value" type="v" direction="out"/>
+ </method>
+ <method name="Set">
+ <arg name="interface" type="s" direction="in"/>
+ <arg name="name" type="s" direction="in"/>
+ <arg name="value" type="v" direction="in"/>
+ </method>
+ <method name="GetAll">
+ <arg name="interface" type="s" direction="in"/>
+ <arg name="properties" type="a{sv}" direction="out"/>
+ </method>
+ <signal name="PropertiesChanged">
+ <arg name="interface" type="s"/>
+ <arg name="changed_properties" type="a{sv}"/>
+ <arg name="invalidated_properties" type="as"/>
+ </signal>
+ </interface>
+ <interface name="org.gnu.Emacs.TestDBus.Interface">
+ <method name="Connect">
+ <arg name="uuid" type="s" direction="in"/>
+ <arg name="mode" type="y" direction="in"/>
+ <arg name="options" type="a{sv}" direction="in"/>
+ <arg name="interface" type="s" direction="out"/>
+ </method>
+ <method name="DeprecatedMethod0">
+ <annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
+ </method>
+ <method name="DeprecatedMethod1">
+ <annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
+ </method>
+ <property name="Connected" type="b" access="read"/>
+ <property name="Player" type="o" access="read"/>
+ <annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
+ </interface>
+ <node name="node0"/>
+ <node name="node1"/>
+</node>
diff --git a/test/lisp/net/dbus-tests.el b/test/lisp/net/dbus-tests.el
index 4463d74be7d..34a2af188f0 100644
--- a/test/lisp/net/dbus-tests.el
+++ b/test/lisp/net/dbus-tests.el
@@ -1,40 +1,52 @@
-;;; dbus-tests.el --- Tests of D-Bus integration into Emacs
+;;; dbus-tests.el --- Tests of D-Bus integration into Emacs -*- lexical-binding:t -*-
;; Copyright (C) 2013-2021 Free Software Foundation, Inc.
;; Author: Michael Albinus <michael.albinus@gmx.de>
-;; This program 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.
-;;
-;; This program 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.
-;;
+;; 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 `https://www.gnu.org/licenses/'.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Code:
(require 'ert)
+(require 'ert-x)
(require 'dbus)
(defvar dbus-debug nil)
(declare-function dbus-get-unique-name "dbusbind.c" (bus))
-(defvar dbus--test-enabled-session-bus
+(defconst dbus--test-enabled-session-bus
(and (featurep 'dbusbind)
(dbus-ignore-errors (dbus-get-unique-name :session)))
"Check, whether we are registered at the session bus.")
-(defvar dbus--test-enabled-system-bus
+(defconst dbus--test-enabled-system-bus
(and (featurep 'dbusbind)
(dbus-ignore-errors (dbus-get-unique-name :system)))
"Check, whether we are registered at the system bus.")
+(defconst dbus--test-service "org.gnu.Emacs.TestDBus"
+ "Test service.")
+
+(defconst dbus--test-path "/org/gnu/Emacs/TestDBus"
+ "Test object path.")
+
+(defconst dbus--test-interface "org.gnu.Emacs.TestDBus.Interface"
+ "Test interface.")
+
(defun dbus--test-availability (bus)
"Test availability of D-Bus BUS."
(should (dbus-list-names bus))
@@ -54,6 +66,8 @@
(ert-deftest dbus-test01-type-conversion ()
"Check type conversion functions."
+ (skip-unless dbus--test-enabled-session-bus)
+
(let ((ustr "0123abc_xyz\x01\xff")
(mstr "Grüß Göttin"))
(should
@@ -82,31 +96,391 @@
(string-equal
(dbus-unescape-from-identifier (dbus-escape-as-identifier mstr)) mstr))))
+(ert-deftest dbus-test01-basic-types ()
+ "Check basic D-Bus type arguments."
+ (skip-unless dbus--test-enabled-session-bus)
+
+ ;; No argument or unknown keyword.
+ (should-error
+ (dbus-check-arguments :session dbus--test-service)
+ :type 'wrong-number-of-arguments)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :keyword)
+ :type 'wrong-type-argument)
+
+ ;; `:string'.
+ (should (dbus-check-arguments :session dbus--test-service "string"))
+ (should (dbus-check-arguments :session dbus--test-service :string "string"))
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :string)
+ :type 'wrong-type-argument)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :string 0.5)
+ :type 'wrong-type-argument)
+
+ ;; `:object-path'.
+ (should
+ (dbus-check-arguments
+ :session dbus--test-service :object-path "/object/path"))
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :object-path)
+ :type 'wrong-type-argument)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :object-path "string")
+ :type 'dbus-error)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :object-path 0.5)
+ :type 'wrong-type-argument)
+
+ ;; `:signature'.
+ (should (dbus-check-arguments :session dbus--test-service :signature "as"))
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :signature)
+ :type 'wrong-type-argument)
+ ;; Raises an error on stderr.
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :signature "string")
+ :type 'dbus-error)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :signature 0.5)
+ :type 'wrong-type-argument)
+
+ ;; `:boolean'.
+ (should (dbus-check-arguments :session dbus--test-service nil))
+ (should (dbus-check-arguments :session dbus--test-service t))
+ (should (dbus-check-arguments :session dbus--test-service :boolean nil))
+ (should (dbus-check-arguments :session dbus--test-service :boolean t))
+ (should (dbus-check-arguments :session dbus--test-service :boolean 'whatever))
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :boolean)
+ :type 'wrong-type-argument)
+
+ ;; `:byte'.
+ (should (dbus-check-arguments :session dbus--test-service :byte 0))
+ ;; Only the least significant byte is taken into account.
+ (should
+ (dbus-check-arguments :session dbus--test-service :byte most-positive-fixnum))
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :byte)
+ :type 'wrong-type-argument)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :byte -1)
+ :type 'wrong-type-argument)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :byte 0.5)
+ :type 'wrong-type-argument)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :byte "string")
+ :type 'wrong-type-argument)
+
+ ;; `:int16'.
+ (should (dbus-check-arguments :session dbus--test-service :int16 0))
+ (should (dbus-check-arguments :session dbus--test-service :int16 #x7fff))
+ (should (dbus-check-arguments :session dbus--test-service :int16 #x-8000))
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :int16)
+ :type 'wrong-type-argument)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :int16 #x8000)
+ :type 'args-out-of-range)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :int16 #x-8001)
+ :type 'args-out-of-range)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :int16 0.5)
+ :type 'wrong-type-argument)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :int16 "string")
+ :type 'wrong-type-argument)
+
+ ;; `:uint16'.
+ (should (dbus-check-arguments :session dbus--test-service :uint16 0))
+ (should (dbus-check-arguments :session dbus--test-service :uint16 #xffff))
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :uint16)
+ :type 'wrong-type-argument)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :uint16 #x10000)
+ :type 'args-out-of-range)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :uint16 -1)
+ :type 'wrong-type-argument)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :uint16 0.5)
+ :type 'wrong-type-argument)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :uint16 "string")
+ :type 'wrong-type-argument)
+
+ ;; `:int32'.
+ (should (dbus-check-arguments :session dbus--test-service :int32 0))
+ (should (dbus-check-arguments :session dbus--test-service :int32 #x7fffffff))
+ (should (dbus-check-arguments :session dbus--test-service :int32 #x-80000000))
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :int32)
+ :type 'wrong-type-argument)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :int32 #x80000000)
+ :type 'args-out-of-range)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :int32 #x-80000001)
+ :type 'args-out-of-range)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :int32 0.5)
+ :type 'args-out-of-range)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :int32 "string")
+ :type 'wrong-type-argument)
+
+ ;; `:uint32'.
+ (should (dbus-check-arguments :session dbus--test-service 0))
+ (should (dbus-check-arguments :session dbus--test-service :uint32 0))
+ (should (dbus-check-arguments :session dbus--test-service :uint32 #xffffffff))
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :uint32)
+ :type 'wrong-type-argument)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :uint32 #x100000000)
+ :type 'args-out-of-range)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :uint32 -1)
+ :type 'args-out-of-range)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :uint32 0.5)
+ :type 'args-out-of-range)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :uint32 "string")
+ :type 'wrong-type-argument)
+
+ ;; `:int64'.
+ (should (dbus-check-arguments :session dbus--test-service :int64 0))
+ (should
+ (dbus-check-arguments :session dbus--test-service :int64 #x7fffffffffffffff))
+ (should
+ (dbus-check-arguments :session dbus--test-service :int64 #x-8000000000000000))
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :int64)
+ :type 'wrong-type-argument)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :int64 #x8000000000000000)
+ :type 'args-out-of-range)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :int64 #x-8000000000000001)
+ :type 'args-out-of-range)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :int64 0.5)
+ :type 'args-out-of-range)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :int64 "string")
+ :type 'wrong-type-argument)
+
+ ;; `:uint64'.
+ (should (dbus-check-arguments :session dbus--test-service :uint64 0))
+ (should
+ (dbus-check-arguments :session dbus--test-service :uint64 #xffffffffffffffff))
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :uint64)
+ :type 'wrong-type-argument)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :uint64 #x10000000000000000)
+ :type 'args-out-of-range)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :uint64 -1)
+ :type 'args-out-of-range)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :uint64 0.5)
+ :type 'args-out-of-range)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :uint64 "string")
+ :type 'wrong-type-argument)
+
+ ;; `:double'.
+ (should (dbus-check-arguments :session dbus--test-service :double 0))
+ (should (dbus-check-arguments :session dbus--test-service :double 0.5))
+ (should (dbus-check-arguments :session dbus--test-service :double -0.5))
+ (should (dbus-check-arguments :session dbus--test-service :double -1))
+ ;; Shall both be supported?
+ (should (dbus-check-arguments :session dbus--test-service :double 1.0e+INF))
+ (should (dbus-check-arguments :session dbus--test-service :double 0.0e+NaN))
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :double)
+ :type 'wrong-type-argument)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :double "string")
+ :type 'wrong-type-argument)
+
+ ;; `:unix-fd'. UNIX file descriptors are transferred out-of-band.
+ ;; We do not support this, and so we cannot do much testing here for
+ ;; `:unix-fd' being an argument (which is an index to the file
+ ;; descriptor in the array of file descriptors that accompany the
+ ;; D-Bus message). Mainly testing, that values out of `:uint32'
+ ;; type range fail.
+ (should (dbus-check-arguments :session dbus--test-service :unix-fd 0))
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :unix-fd)
+ :type 'wrong-type-argument)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :unix-fd -1)
+ :type 'args-out-of-range)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :unix-fd 0.5)
+ :type 'args-out-of-range)
+ (should-error
+ (dbus-check-arguments :session dbus--test-service :unix-fd "string")
+ :type 'wrong-type-argument))
+
+(ert-deftest dbus-test01-compound-types ()
+ "Check basic D-Bus type arguments."
+ (skip-unless dbus--test-enabled-session-bus)
+
+ ;; `:array'. It contains several elements of the same type.
+ (should (dbus-check-arguments :session dbus--test-service '("string")))
+ (should (dbus-check-arguments :session dbus--test-service '(:array "string")))
+ (should
+ (dbus-check-arguments :session dbus--test-service '(:array :string "string")))
+ (should
+ (dbus-check-arguments
+ :session dbus--test-service '(:array :string "string1" "string2")))
+ (should
+ (dbus-check-arguments
+ :session dbus--test-service '(:array :signature "s" :signature "ao")))
+ ;; Empty array (of strings).
+ (should (dbus-check-arguments :session dbus--test-service '(:array)))
+ ;; Empty array (of object paths).
+ (should
+ (dbus-check-arguments :session dbus--test-service '(:array :signature "o")))
+ ;; Different element types.
+ (should-error
+ (dbus-check-arguments
+ :session dbus--test-service
+ '(:array :string "string" :object-path "/object/path"))
+ :type 'wrong-type-argument)
+ ;; Different variant types in array don't matter.
+ (should
+ (dbus-check-arguments
+ :session dbus--test-service
+ '(:array
+ (:variant :string "string1")
+ (:variant (:struct :string "string2" :object-path "/object/path")))))
+
+ ;; `:variant'. It contains exactly one element.
+ (should
+ (dbus-check-arguments
+ :session dbus--test-service '(:variant :string "string")))
+ (should
+ (dbus-check-arguments
+ :session dbus--test-service '(:variant (:array "string"))))
+ ;; Empty variant.
+ (should-error
+ (dbus-check-arguments :session dbus--test-service '(:variant))
+ :type 'wrong-type-argument)
+ ;; More than one element.
+ (should-error
+ (dbus-check-arguments
+ :session dbus--test-service
+ '(:variant :string "string" :object-path "/object/path"))
+ :type 'wrong-type-argument)
+
+ ;; `:dict-entry'. It must contain two elements; the first one must
+ ;; be of a basic type. It must be an element of an array.
+ (should
+ (dbus-check-arguments
+ :session dbus--test-service
+ '(:array (:dict-entry :string "string" :boolean nil))))
+ ;; This is an alternative syntax.
+ (should
+ (dbus-check-arguments
+ :session dbus--test-service
+ '(:array :dict-entry (:string "string" :boolean t))))
+ ;; Empty dict-entry.
+ (should-error
+ (dbus-check-arguments
+ :session dbus--test-service '(:array (:dict-entry)))
+ :type 'wrong-type-argument)
+ ;; One element.
+ (should-error
+ (dbus-check-arguments
+ :session dbus--test-service '(:array (:dict-entry :string "string")))
+ :type 'wrong-type-argument)
+ (should-error
+ (dbus-check-arguments
+ :session dbus--test-service
+ '(:array (:dict-entry :string "string" :boolean t :boolean t)))
+ :type 'wrong-type-argument)
+ ;; The first element ist not of a basic type.
+ (should-error
+ (dbus-check-arguments
+ :session dbus--test-service
+ '(:array (:dict-entry (:array :string "string") :boolean t)))
+ :type 'wrong-type-argument)
+ ;; It is not an element of an array.
+ (should-error
+ (dbus-check-arguments
+ :session dbus--test-service '(:dict-entry :string "string" :boolean t))
+ :type 'wrong-type-argument)
+ ;; Different dict entry types in array.
+ (should-error
+ (dbus-check-arguments
+ :session dbus--test-service
+ '(:array
+ (:dict-entry :string "string1" :boolean t)
+ (:dict-entry :string "string2" :object-path "/object/path")))
+ :type 'wrong-type-argument)
+
+ ;; `:struct'. There is no restriction what could be an element of a struct.
+ (should
+ (dbus-check-arguments
+ :session dbus--test-service
+ '(:struct
+ :string "string"
+ :object-path "/object/path"
+ (:variant (:array :unix-fd 1 :unix-fd 2 :unix-fd 3 :unix-fd 4)))))
+ ;; Empty struct.
+ (should-error
+ (dbus-check-arguments :session dbus--test-service '(:struct))
+ :type 'wrong-type-argument)
+ ;; Different struct types in array.
+ (should-error
+ (dbus-check-arguments
+ :session dbus--test-service
+ '(:array
+ (:struct :string "string1" :boolean t)
+ (:struct :object-path "/object/path")))
+ :type 'wrong-type-argument))
+
(defun dbus--test-register-service (bus)
"Check service registration at BUS."
;; Cleanup.
- (dbus-ignore-errors (dbus-unregister-service bus dbus-service-emacs))
+ (dbus-ignore-errors (dbus-unregister-service bus dbus--test-service))
;; Register an own service.
- (should (eq (dbus-register-service bus dbus-service-emacs) :primary-owner))
- (should (member dbus-service-emacs (dbus-list-known-names bus)))
- (should (eq (dbus-register-service bus dbus-service-emacs) :already-owner))
- (should (member dbus-service-emacs (dbus-list-known-names bus)))
+ (should (eq (dbus-register-service bus dbus--test-service) :primary-owner))
+ (should (member dbus--test-service (dbus-list-known-names bus)))
+ (should (eq (dbus-register-service bus dbus--test-service) :already-owner))
+ (should (member dbus--test-service (dbus-list-known-names bus)))
;; Unregister the service.
- (should (eq (dbus-unregister-service bus dbus-service-emacs) :released))
- (should-not (member dbus-service-emacs (dbus-list-known-names bus)))
- (should (eq (dbus-unregister-service bus dbus-service-emacs) :non-existent))
- (should-not (member dbus-service-emacs (dbus-list-known-names bus)))
+ (should (eq (dbus-unregister-service bus dbus--test-service) :released))
+ (should-not (member dbus--test-service (dbus-list-known-names bus)))
+ (should (eq (dbus-unregister-service bus dbus--test-service) :non-existent))
+ (should-not (member dbus--test-service (dbus-list-known-names bus)))
;; `dbus-service-dbus' is reserved for the BUS itself.
- (should-error (dbus-register-service bus dbus-service-dbus))
- (should-error (dbus-unregister-service bus dbus-service-dbus)))
+ (should
+ (equal
+ (butlast
+ (should-error (dbus-register-service bus dbus-service-dbus)))
+ `(dbus-error ,dbus-error-invalid-args)))
+ (should
+ (equal
+ (butlast
+ (should-error (dbus-unregister-service bus dbus-service-dbus)))
+ `(dbus-error ,dbus-error-invalid-args))))
(ert-deftest dbus-test02-register-service-session ()
"Check service registration at `:session' bus."
(skip-unless (and dbus--test-enabled-session-bus
- (dbus-register-service :session dbus-service-emacs)))
+ (dbus-register-service :session dbus--test-service)))
(dbus--test-register-service :session)
(let ((service "org.freedesktop.Notifications"))
@@ -124,7 +498,7 @@
(ert-deftest dbus-test02-register-service-system ()
"Check service registration at `:system' bus."
(skip-unless (and dbus--test-enabled-system-bus
- (dbus-register-service :system dbus-service-emacs)))
+ (dbus-register-service :system dbus--test-service)))
(dbus--test-register-service :system))
(ert-deftest dbus-test02-register-service-own-bus ()
@@ -148,7 +522,7 @@ This includes initialization and closing the bus."
(featurep 'dbusbind)
(dbus-init-bus bus)
(dbus-get-unique-name bus)
- (dbus-register-service bus dbus-service-emacs))))
+ (dbus-register-service bus dbus--test-service))))
;; Run the test.
(dbus--test-register-service bus))
@@ -159,25 +533,1472 @@ This includes initialization and closing the bus."
"Check `dbus-interface-peer' methods."
(skip-unless
(and dbus--test-enabled-session-bus
- (dbus-register-service :session dbus-service-emacs)
+ (dbus-register-service :session dbus--test-service)
;; "GetMachineId" is not implemented (yet). When it returns a
;; value, another D-Bus client like dbus-monitor is reacting
;; on `dbus-interface-peer'. We cannot test then.
(not
(dbus-ignore-errors
(dbus-call-method
- :session dbus-service-emacs dbus-path-dbus
+ :session dbus--test-service dbus-path-dbus
dbus-interface-peer "GetMachineId" :timeout 100)))))
- (should (dbus-ping :session dbus-service-emacs 100))
- (dbus-unregister-service :session dbus-service-emacs)
- (should-not (dbus-ping :session dbus-service-emacs 100)))
+ (should (dbus-ping :session dbus--test-service 100))
+ (dbus-unregister-service :session dbus--test-service)
+ (should-not (dbus-ping :session dbus--test-service 100)))
+
+(defun dbus--test-method-handler (&rest args)
+ "Method handler for `dbus-test04-register-method'."
+ (cond
+ ;; No argument.
+ ((null args)
+ :ignore)
+ ;; One argument.
+ ((= 1 (length args))
+ (car args))
+ ;; Two arguments.
+ ((= 2 (length args))
+ `(:error ,dbus-error-invalid-args
+ ,(format-message "Wrong arguments %s" args)))
+ ;; More than two arguments.
+ (t (signal 'dbus-error (cons "D-Bus signal" args)))))
+
+(ert-deftest dbus-test04-register-method ()
+ "Check method registration for an own service."
+ (skip-unless dbus--test-enabled-session-bus)
+ (dbus-ignore-errors (dbus-unregister-service :session dbus--test-service))
+
+ (unwind-protect
+ (let ((method1 "Method1")
+ (method2 "Method2")
+ (handler #'dbus--test-method-handler)
+ registered)
+
+ ;; The service is not registered yet.
+ (should
+ (equal
+ (butlast
+ (should-error
+ (dbus-call-method
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface method1 :timeout 10 "foo")))
+ `(dbus-error ,dbus-error-service-unknown)))
+
+ ;; Register.
+ (should
+ (equal
+ (setq
+ registered
+ (dbus-register-method
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface method1 handler))
+ `((:method :session ,dbus--test-interface ,method1)
+ (,dbus--test-service ,dbus--test-path ,handler))))
+ (should
+ (equal
+ (dbus-register-method
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface method2 handler)
+ `((:method :session ,dbus--test-interface ,method2)
+ (,dbus--test-service ,dbus--test-path ,handler))))
+
+ ;; No argument, returns nil.
+ (should-not
+ (dbus-call-method
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface method1))
+ ;; One argument, returns the argument.
+ (should
+ (string-equal
+ (dbus-call-method
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface method1 "foo")
+ "foo"))
+ ;; Two arguments, D-Bus error activated as `(:error ...)' list.
+ (should
+ (equal
+ (should-error
+ (dbus-call-method
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface method1 "foo" "bar"))
+ `(dbus-error ,dbus-error-invalid-args "Wrong arguments (foo bar)")))
+ ;; Three arguments, D-Bus error activated by `dbus-error' signal.
+ (should
+ (equal
+ (should-error
+ (dbus-call-method
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface method1 "foo" "bar" "baz"))
+ `(dbus-error
+ ,dbus-error-failed
+ "D-Bus error: \"D-Bus signal\", \"foo\", \"bar\", \"baz\"")))
+
+ ;; Unregister method.
+ (should (dbus-unregister-object registered))
+ (should-not (dbus-unregister-object registered))
+ (should
+ (equal
+ (butlast
+ (should-error
+ (dbus-call-method
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface method1 :timeout 10 "foo")))
+ `(dbus-error ,dbus-error-no-reply))))
+
+ ;; Cleanup.
+ (dbus-unregister-service :session dbus--test-service)))
+
+(defun dbus--test-method-reentry-handler (&rest _args)
+ "Method handler for `dbus-test04-method-reentry'."
+ (dbus-get-all-managed-objects :session dbus--test-service dbus--test-path)
+ 42)
+
+(ert-deftest dbus-test04-method-reentry ()
+ "Check receiving method call while awaiting response.
+Ensure that incoming method calls are handled when call to `dbus-call-method'
+is in progress."
+ :tags '(:expensive-test)
+ ;; Simulate application registration. (Bug#43251)
+ (skip-unless dbus--test-enabled-session-bus)
+ (dbus-ignore-errors (dbus-unregister-service :session dbus--test-service))
+
+ (unwind-protect
+ (let ((method "Reentry"))
+ (should
+ (equal
+ (dbus-register-method
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface method #'dbus--test-method-reentry-handler)
+ `((:method :session ,dbus--test-interface ,method)
+ (,dbus--test-service ,dbus--test-path
+ dbus--test-method-reentry-handler))))
+
+ (should
+ (=
+ (dbus-call-method
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface method)
+ 42)))
+
+ ;; Cleanup.
+ (dbus-unregister-service :session dbus--test-service)))
+
+(ert-deftest dbus-test04-call-method-timeout ()
+ "Verify `dbus-call-method' request timeout."
+ :tags '(:expensive-test)
+ (skip-unless dbus--test-enabled-session-bus)
+ (dbus-ignore-errors (dbus-unregister-service :session dbus--test-service))
+ (dbus-register-service :session dbus--test-service)
+
+ (unwind-protect
+ (let ((start (current-time)))
+ ;; Test timeout override for method call.
+ (should-error
+ (dbus-call-method
+ :session dbus--test-service dbus--test-path
+ dbus-interface-introspectable "Introspect" :timeout 2500)
+ :type 'dbus-error)
+
+ (should
+ (< 2.4 (float-time (time-since start)) 2.7)))
+
+ ;; Cleanup.
+ (dbus-unregister-service :session dbus--test-service)))
+
+(defvar dbus--test-signal-received nil
+ "Received signal value in `dbus--test-signal-handler'.")
+
+(defun dbus--test-signal-handler (&rest args)
+ "Signal handler for `dbus-test*-signal' and `dbus-test08-register-monitor'."
+ (setq dbus--test-signal-received args))
+
+(defun dbus--test-timeout-handler (&rest _ignore)
+ "Timeout handler, reporting a failed test."
+ (ert-fail (format "`%s' timed out" (ert-test-name (ert-running-test)))))
+
+(ert-deftest dbus-test05-register-signal ()
+ "Check signal registration for an own service."
+ (skip-unless dbus--test-enabled-session-bus)
+ (dbus-ignore-errors (dbus-unregister-service :session dbus--test-service))
+
+ (unwind-protect
+ (let ((member "Member")
+ (handler #'dbus--test-signal-handler)
+ registered)
+
+ ;; Register signal handler.
+ (should
+ (equal
+ (setq
+ registered
+ (dbus-register-signal
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface member handler))
+ `((:signal :session ,dbus--test-interface ,member)
+ (,dbus--test-service ,dbus--test-path ,handler))))
+
+ ;; Send one argument, basic type.
+ (setq dbus--test-signal-received nil)
+ (dbus-send-signal
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface member "foo")
+ (with-timeout (1 (dbus--test-timeout-handler))
+ (while (null dbus--test-signal-received)
+ (read-event nil nil 0.1)))
+ (should (equal dbus--test-signal-received '("foo")))
+
+ ;; Send two arguments, compound types.
+ (setq dbus--test-signal-received nil)
+ (dbus-send-signal
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface member
+ '(:array :byte 1 :byte 2 :byte 3) '(:variant :string "bar"))
+ (with-timeout (1 (dbus--test-timeout-handler))
+ (while (null dbus--test-signal-received)
+ (read-event nil nil 0.1)))
+ (should (equal dbus--test-signal-received '((1 2 3) ("bar"))))
+
+ ;; Unregister signal.
+ (should (dbus-unregister-object registered))
+ (should-not (dbus-unregister-object registered)))
+
+ ;; Cleanup.
+ (dbus-unregister-service :session dbus--test-service)))
+
+(ert-deftest dbus-test06-register-property ()
+ "Check property registration for an own service."
+ (skip-unless dbus--test-enabled-session-bus)
+ (dbus-ignore-errors (dbus-unregister-service :session dbus--test-service))
+
+ (unwind-protect
+ (let ((property1 "Property1")
+ (property2 "Property2")
+ (property3 "Property3")
+ (property4 "Property4")
+ registered)
+
+ ;; `:read' property.
+ (should
+ (equal
+ (setq
+ registered
+ (dbus-register-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property1 :read "foo"))
+ `((:property :session ,dbus--test-interface ,property1)
+ (,dbus--test-service ,dbus--test-path))))
+ (should
+ (string-equal
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property1)
+ "foo"))
+ ;; Due to `:read' access type, we don't get a proper reply
+ ;; from `dbus-set-property'.
+ (should
+ (equal
+ (butlast
+ (should-error
+ (dbus-set-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property1 "foofoo")))
+ `(dbus-error ,dbus-error-property-read-only)))
+ (should
+ (string-equal
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property1)
+ "foo"))
+
+ ;; `:write' property.
+ (should
+ (equal
+ (dbus-register-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property2 :write "bar")
+ `((:property :session ,dbus--test-interface ,property2)
+ (,dbus--test-service ,dbus--test-path))))
+ ;; Due to `:write' access type, we don't get a proper reply
+ ;; from `dbus-get-property'.
+ (should
+ (equal
+ (butlast
+ (should-error
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property2)))
+ `(dbus-error ,dbus-error-access-denied)))
+ (should
+ (string-equal
+ (dbus-set-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property2 "barbar")
+ "barbar"))
+ ;; Still `:write' access type.
+ (should
+ (equal
+ (butlast
+ (should-error
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property2)))
+ `(dbus-error ,dbus-error-access-denied)))
+
+ ;; `:readwrite' property, typed value (Bug#43252).
+ (should
+ (equal
+ (dbus-register-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property3 :readwrite :object-path "/baz")
+ `((:property :session ,dbus--test-interface ,property3)
+ (,dbus--test-service ,dbus--test-path))))
+ (should
+ (string-equal
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property3)
+ "/baz"))
+ (should
+ (string-equal
+ (dbus-set-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property3 :object-path "/baz/baz")
+ "/baz/baz"))
+ (should
+ (string-equal
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property3)
+ "/baz/baz"))
+
+ ;; Not registered property.
+ (should
+ (equal
+ (butlast
+ (should-error
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property4)))
+ `(dbus-error ,dbus-error-unknown-property)))
+ (should
+ (equal
+ (butlast
+ (should-error
+ (dbus-set-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property4 "foobarbaz")))
+ `(dbus-error ,dbus-error-unknown-property)))
+
+ ;; `dbus-get-all-properties'. We cannot retrieve a value for
+ ;; the property with `:write' access type.
+ (let ((result
+ (dbus-get-all-properties
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface)))
+ (should (string-equal (cdr (assoc property1 result)) "foo"))
+ (should (string-equal (cdr (assoc property3 result)) "/baz/baz"))
+ (should-not (assoc property2 result)))
+
+ ;; `dbus-get-all-managed-objects'. We cannot retrieve a value for
+ ;; the property with `:write' access type.
+ (let ((result
+ (dbus-get-all-managed-objects
+ :session dbus--test-service dbus--test-path)))
+ (should (setq result (cadr (assoc dbus--test-path result))))
+ (should (setq result (cadr (assoc dbus--test-interface result))))
+ (should (string-equal (cdr (assoc property1 result)) "foo"))
+ (should (string-equal (cdr (assoc property3 result)) "/baz/baz"))
+ (should-not (assoc property2 result)))
+
+ ;; Unregister property.
+ (should (dbus-unregister-object registered))
+ (should-not (dbus-unregister-object registered))
+ (should
+ (equal
+ (butlast
+ (should-error
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property1)))
+ `(dbus-error ,dbus-error-unknown-property))))
+
+ ;; Cleanup.
+ (dbus-unregister-service :session dbus--test-service)))
+
+;; The following test is inspired by Bug#43146.
+(ert-deftest dbus-test06-register-property-several-paths ()
+ "Check property registration for an own service at several paths."
+ (skip-unless dbus--test-enabled-session-bus)
+ (dbus-ignore-errors (dbus-unregister-service :session dbus--test-service))
+
+ (unwind-protect
+ (let ((property1 "Property1")
+ (property2 "Property2")
+ (property3 "Property3"))
+
+ ;; First path.
+ (should
+ (equal
+ (dbus-register-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property1 :readwrite "foo")
+ `((:property :session ,dbus--test-interface ,property1)
+ (,dbus--test-service ,dbus--test-path))))
+ (should
+ (equal
+ (dbus-register-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property2 :readwrite "bar")
+ `((:property :session ,dbus--test-interface ,property2)
+ (,dbus--test-service ,dbus--test-path))))
+ (should
+ (string-equal
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property1)
+ "foo"))
+ (should
+ (string-equal
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property2)
+ "bar"))
+
+ (should
+ (string-equal
+ (dbus-set-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property1 "foofoo")
+ "foofoo"))
+ (should
+ (string-equal
+ (dbus-set-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property2 "barbar")
+ "barbar"))
+ (should
+ (string-equal
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property1)
+ "foofoo"))
+ (should
+ (string-equal
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property2)
+ "barbar"))
+
+ ;; Second path.
+ (should
+ (equal
+ (dbus-register-property
+ :session dbus--test-service (concat dbus--test-path dbus--test-path)
+ dbus--test-interface property2 :readwrite "foo")
+ `((:property :session ,dbus--test-interface ,property2)
+ (,dbus--test-service ,(concat dbus--test-path dbus--test-path)))))
+ (should
+ (equal
+ (dbus-register-property
+ :session dbus--test-service (concat dbus--test-path dbus--test-path)
+ dbus--test-interface property3 :readwrite "bar")
+ `((:property :session ,dbus--test-interface ,property3)
+ (,dbus--test-service ,(concat dbus--test-path dbus--test-path)))))
+ (should
+ (string-equal
+ (dbus-get-property
+ :session dbus--test-service (concat dbus--test-path dbus--test-path)
+ dbus--test-interface property2)
+ "foo"))
+ (should
+ (string-equal
+ (dbus-get-property
+ :session dbus--test-service (concat dbus--test-path dbus--test-path)
+ dbus--test-interface property3)
+ "bar"))
+
+ (should
+ (string-equal
+ (dbus-set-property
+ :session dbus--test-service (concat dbus--test-path dbus--test-path)
+ dbus--test-interface property2 "foofoo")
+ "foofoo"))
+ (should
+ (string-equal
+ (dbus-set-property
+ :session dbus--test-service (concat dbus--test-path dbus--test-path)
+ dbus--test-interface property3 "barbar")
+ "barbar"))
+ (should
+ (string-equal
+ (dbus-get-property
+ :session dbus--test-service (concat dbus--test-path dbus--test-path)
+ dbus--test-interface property2)
+ "foofoo"))
+ (should
+ (string-equal
+ (dbus-get-property
+ :session dbus--test-service (concat dbus--test-path dbus--test-path)
+ dbus--test-interface property3)
+ "barbar"))
+
+ ;; Everything is still fine, tested with `dbus-get-all-properties'.
+ (let ((result
+ (dbus-get-all-properties
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface)))
+ (should (string-equal (cdr (assoc property1 result)) "foofoo"))
+ (should (string-equal (cdr (assoc property2 result)) "barbar"))
+ (should-not (assoc property3 result)))
+
+ (let ((result
+ (dbus-get-all-properties
+ :session dbus--test-service
+ (concat dbus--test-path dbus--test-path) dbus--test-interface)))
+ (should (string-equal (cdr (assoc property2 result)) "foofoo"))
+ (should (string-equal (cdr (assoc property3 result)) "barbar"))
+ (should-not (assoc property1 result)))
+
+ ;; Final check with `dbus-get-all-managed-objects'.
+ (let ((result
+ (dbus-get-all-managed-objects :session dbus--test-service "/"))
+ result1)
+ (should (setq result1 (cadr (assoc dbus--test-path result))))
+ (should (setq result1 (cadr (assoc dbus--test-interface result1))))
+ (should (string-equal (cdr (assoc property1 result1)) "foofoo"))
+ (should (string-equal (cdr (assoc property2 result1)) "barbar"))
+ (should-not (assoc property3 result1))
+
+ (should
+ (setq
+ result1
+ (cadr (assoc (concat dbus--test-path dbus--test-path) result))))
+ (should (setq result1 (cadr (assoc dbus--test-interface result1))))
+ (should (string-equal (cdr (assoc property2 result1)) "foofoo"))
+ (should (string-equal (cdr (assoc property3 result1)) "barbar"))
+ (should-not (assoc property1 result1))))
+
+ ;; Cleanup.
+ (dbus-unregister-service :session dbus--test-service)))
+
+(ert-deftest dbus-test06-register-property-emits-signal ()
+ "Check property registration for an own service, including signalling."
+ (skip-unless dbus--test-enabled-session-bus)
+ (dbus-ignore-errors (dbus-unregister-service :session dbus--test-service))
+
+ (unwind-protect
+ (let ((property "Property")
+ (handler #'dbus--test-signal-handler))
+
+ ;; Register signal handler.
+ (should
+ (equal
+ (dbus-register-signal
+ :session dbus--test-service dbus--test-path
+ dbus-interface-properties "PropertiesChanged" handler)
+ `((:signal :session ,dbus-interface-properties "PropertiesChanged")
+ (,dbus--test-service ,dbus--test-path ,handler))))
+
+ ;; Register property.
+ (setq dbus--test-signal-received nil)
+ (should
+ (equal
+ (dbus-register-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property :readwrite "foo" 'emits-signal)
+ `((:property :session ,dbus--test-interface ,property)
+ (,dbus--test-service ,dbus--test-path))))
+ (with-timeout (1 (dbus--test-timeout-handler))
+ (while (null dbus--test-signal-received)
+ (read-event nil nil 0.1)))
+ ;; It returns three arguments, "interface" (a string),
+ ;; "changed_properties" (an array of dict entries) and
+ ;; "invalidated_properties" (an array of strings).
+ (should
+ (equal dbus--test-signal-received
+ `(,dbus--test-interface ((,property ("foo"))) ())))
+
+ (should
+ (equal
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property)
+ "foo"))
+
+ ;; Set property. The new value shall be signalled.
+ (setq dbus--test-signal-received nil)
+ (should
+ (equal
+ (dbus-set-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property
+ '(:array :byte 1 :byte 2 :byte 3))
+ '(1 2 3)))
+ (with-timeout (1 (dbus--test-timeout-handler))
+ (while (null dbus--test-signal-received)
+ (read-event nil nil 0.1)))
+ (should
+ (equal
+ dbus--test-signal-received
+ `(,dbus--test-interface ((,property ((1 2 3)))) ())))
+
+ (should
+ (equal
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface property)
+ '(1 2 3))))
+
+ ;; Cleanup.
+ (dbus-unregister-service :session dbus--test-service)))
+
+(defsubst dbus--test-run-property-test (selector name value expected)
+ "Generate a property test: register, set, get, getall sequence.
+This is a helper function for the macro `dbus--test-property'.
+The argument SELECTOR indicates whether the test should expand to
+`dbus-register-property' (if SELECTOR is `register') or
+`dbus-set-property' (if SELECTOR is `set').
+The argument NAME is the property name.
+The argument VALUE is the value to register or set.
+The argument EXPECTED is a transformed VALUE representing the
+form `dbus-get-property' should return."
+ (cond
+ ((eq selector 'register)
+ (should
+ (equal
+ (dbus-register-property
+ :session dbus--test-service dbus--test-path dbus--test-interface name
+ :readwrite value)
+ `((:property :session ,dbus--test-interface ,name)
+ (,dbus--test-service ,dbus--test-path)))))
+
+ ((eq selector 'set)
+ (should
+ (equal
+ (dbus-set-property
+ :session dbus--test-service dbus--test-path dbus--test-interface name
+ value)
+ expected)))
+
+ (t (signal 'wrong-type-argument "Selector should be 'register or 'set.")))
+
+ (should
+ (equal
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path dbus--test-interface name)
+ expected))
+
+ (let ((result
+ (dbus-get-all-properties
+ :session dbus--test-service dbus--test-path dbus--test-interface)))
+ (should (equal (cdr (assoc name result)) expected)))
+
+ (let ((result
+ (dbus-get-all-managed-objects :session dbus--test-service "/"))
+ result1)
+ (should (setq result1 (cadr (assoc dbus--test-path result))))
+ (should (setq result1 (cadr (assoc dbus--test-interface result1))))
+ (should (equal (cdr (assoc name result1)) expected))))
+
+(defsubst dbus--test-property (name &rest value-list)
+ "Test a D-Bus property named by string argument NAME.
+The argument VALUE-LIST is a sequence of pairs, where each pair
+represents a value form and an expected returned value form. The
+first pair in VALUES is used for `dbus-register-property'.
+Subsequent pairs of the list are tested with `dbus-set-property'."
+ (let ((values (car value-list)))
+ (dbus--test-run-property-test
+ 'register name (car values) (cdr values)))
+ (dolist (values (cdr value-list))
+ (dbus--test-run-property-test
+ 'set name (car values) (cdr values))))
+
+(ert-deftest dbus-test06-property-types ()
+ "Check property access and mutation for an own service."
+ (skip-unless dbus--test-enabled-session-bus)
+ (dbus-ignore-errors (dbus-unregister-service :session dbus--test-service))
+ (dbus-register-service :session dbus--test-service)
+
+ (unwind-protect
+ (progn
+ (dbus--test-property
+ "ByteArray"
+ '((:array :byte 1 :byte 2 :byte 3) . (1 2 3))
+ '((:array :byte 4 :byte 5 :byte 6) . (4 5 6)))
+
+ (dbus--test-property
+ "StringArray"
+ '((:array "one" "two" :string "three") . ("one" "two" "three"))
+ '((:array :string "four" :string "five" "six") . ("four" "five" "six")))
+
+ (dbus--test-property
+ "ObjectArray"
+ '((:array
+ :object-path "/node00"
+ :object-path "/node01"
+ :object-path "/node0/node02")
+ . ("/node00" "/node01" "/node0/node02"))
+ '((:array
+ :object-path "/node10"
+ :object-path "/node11"
+ :object-path "/node0/node12")
+ . ("/node10" "/node11" "/node0/node12")))
+
+ (dbus--test-property
+ "Dictionary"
+ '((:array
+ :dict-entry (:string "four" (:variant :string "value of four"))
+ :dict-entry ("five" (:variant :object-path "/node0"))
+ :dict-entry ("six" (:variant (:array :byte 4 :byte 5 :byte 6))))
+ . (("four"
+ ("value of four"))
+ ("five"
+ ("/node0"))
+ ("six"
+ ((4 5 6)))))
+ '((:array
+ :dict-entry
+ (:string "key0" (:variant (:array :byte 7 :byte 8 :byte 9)))
+ :dict-entry ("key1" (:variant :string "value"))
+ :dict-entry ("key2" (:variant :object-path "/node0/node1")))
+ . (("key0"
+ ((7 8 9)))
+ ("key1"
+ ("value"))
+ ("key2"
+ ("/node0/node1")))))
+
+ (dbus--test-property ; Syntax emphasizing :dict compound type.
+ "Dictionary"
+ '((:array
+ (:dict-entry :string "seven" (:variant :string "value of seven"))
+ (:dict-entry "eight" (:variant :object-path "/node8"))
+ (:dict-entry "nine" (:variant (:array :byte 9 :byte 27 :byte 81))))
+ . (("seven"
+ ("value of seven"))
+ ("eight"
+ ("/node8"))
+ ("nine"
+ ((9 27 81)))))
+ '((:array
+ (:dict-entry
+ :string "key4" (:variant (:array :byte 7 :byte 49 :byte 125)))
+ (:dict-entry "key5" (:variant :string "obsolete"))
+ (:dict-entry "key6" (:variant :object-path "/node6/node7")))
+ . (("key4"
+ ((7 49 125)))
+ ("key5"
+ ("obsolete"))
+ ("key6"
+ ("/node6/node7")))))
+
+ (dbus--test-property
+ "ByteDictionary"
+ '((:array
+ (:dict-entry :byte 8 (:variant :string "byte-eight"))
+ (:dict-entry :byte 16 (:variant :object-path "/byte/sixteen"))
+ (:dict-entry :byte 48 (:variant (:array :byte 8 :byte 9 :byte 10))))
+ . (( 8 ("byte-eight"))
+ (16 ("/byte/sixteen"))
+ (48 ((8 9 10))))))
+
+ (dbus--test-property
+ "Variant"
+ '((:variant "Variant string") . ("Variant string"))
+ '((:variant :byte 42) . (42))
+ '((:variant :uint32 1000000) . (1000000))
+ '((:variant :object-path "/variant/path") . ("/variant/path"))
+ '((:variant :signature "a{sa{sv}}") . ("a{sa{sv}}"))
+ '((:variant
+ (:struct
+ 42 "string" (:object-path "/structure/path") (:variant "last")))
+ . ((42 "string" ("/structure/path") ("last")))))
+
+ ;; Test that :read prevents writes.
+ (should
+ (equal
+ (dbus-register-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "StringArray" :read '(:array "one" "two" :string "three"))
+ `((:property :session ,dbus--test-interface "StringArray")
+ (,dbus--test-service ,dbus--test-path))))
+
+ (should-error ; Cannot set property with :read access.
+ (dbus-set-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "StringArray" '(:array "seven" "eight" :string "nine"))
+ :type 'dbus-error)
+
+ (should ; Property value preserved on error.
+ (equal
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "StringArray")
+ '("one" "two" "three")))
+
+ ;; Test mismatched types in array.
+ (should-error
+ (dbus-register-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "MixedArray" :readwrite
+ '(:array
+ :object-path "/node00"
+ :string "/node01"
+ :object-path "/node0/node02"))
+ :type 'wrong-type-argument)
+
+ ;; Test in-range integer values.
+ (should
+ (equal
+ (dbus-register-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "ByteValue" :readwrite :byte 255)
+ `((:property :session ,dbus--test-interface "ByteValue")
+ (,dbus--test-service ,dbus--test-path))))
+
+ (should
+ (=
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "ByteValue")
+ 255))
+
+ (should
+ (equal
+ (dbus-register-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "ShortValue" :readwrite :int16 32767)
+ `((:property :session ,dbus--test-interface "ShortValue")
+ (,dbus--test-service ,dbus--test-path))))
+
+ (should
+ (=
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "ShortValue")
+ 32767))
+
+ (should
+ (equal
+ (dbus-register-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "UShortValue" :readwrite :uint16 65535)
+ `((:property :session ,dbus--test-interface "UShortValue")
+ (,dbus--test-service ,dbus--test-path))))
+
+ (should
+ (=
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "UShortValue")
+ 65535))
+
+ (should
+ (equal
+ (dbus-register-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "IntValue" :readwrite :int32 2147483647)
+ `((:property :session ,dbus--test-interface "IntValue")
+ (,dbus--test-service ,dbus--test-path))))
+
+ (should
+ (=
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface "IntValue")
+ 2147483647))
+
+ (should
+ (equal
+ (dbus-register-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "UIntValue" :readwrite :uint32 4294967295)
+ `((:property :session ,dbus--test-interface "UIntValue")
+ (,dbus--test-service ,dbus--test-path))))
+
+ (should
+ (=
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "UIntValue")
+ 4294967295))
+
+ (should
+ (equal
+ (dbus-register-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "LongValue" :readwrite :int64 9223372036854775807)
+ `((:property :session ,dbus--test-interface "LongValue")
+ (,dbus--test-service ,dbus--test-path))))
+
+ (should
+ (=
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "LongValue")
+ 9223372036854775807))
+
+ (should
+ (equal
+ (dbus-register-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "ULongValue" :readwrite :uint64 18446744073709551615)
+ `((:property :session ,dbus--test-interface "ULongValue")
+ (,dbus--test-service ,dbus--test-path))))
+
+ (should
+ (=
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "ULongValue")
+ 18446744073709551615))
+
+ ;; Test integer overflow.
+ (should
+ (=
+ (dbus-set-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "ByteValue" :byte 520)
+ 8))
+
+ (should
+ (=
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "ByteValue")
+ 8))
+
+ (should-error
+ (dbus-register-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "ShortValue" :readwrite :int16 32800)
+ :type 'args-out-of-range)
+
+ (should-error
+ (dbus-register-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "UShortValue" :readwrite :uint16 65600)
+ :type 'args-out-of-range)
+
+ (should-error
+ (dbus-register-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "IntValue" :readwrite :int32 2147483700)
+ :type 'args-out-of-range)
+
+ (should-error
+ (dbus-register-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "UIntValue" :readwrite :uint32 4294967300)
+ :type 'args-out-of-range)
+
+ (should-error
+ (dbus-register-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "LongValue" :readwrite :int64 9223372036854775900)
+ :type 'args-out-of-range)
+
+ (should-error
+ (dbus-register-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "ULongValue" :readwrite :uint64 18446744073709551700)
+ :type 'args-out-of-range)
+
+ ;; dbus-set-property may change property type.
+ (should
+ (=
+ (dbus-set-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "ByteValue" 1024)
+ 1024))
+
+ (should
+ (=
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "ByteValue")
+ 1024))
+
+ (should ; Another change property type test.
+ (equal
+ (dbus-set-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "ByteValue" :boolean t)
+ t))
+
+ (should
+ (eq
+ (dbus-get-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "ByteValue")
+ t))
+
+ ;; Test invalid type specification.
+ (should-error
+ (dbus-register-property
+ :session dbus--test-service dbus--test-path dbus--test-interface
+ "InvalidType" :readwrite :keyword 128)
+ :type 'wrong-type-argument))
+
+ ;; Cleanup.
+ (dbus-unregister-service :session dbus--test-service)))
+
+(defun dbus--test-introspect ()
+ "Return test introspection string."
+ (when (string-equal dbus--test-path (dbus-event-path-name last-input-event))
+ (with-temp-buffer
+ (insert-file-contents-literally
+ (ert-resource-file "org.gnu.Emacs.TestDBus.xml"))
+ (buffer-string))))
+
+(defsubst dbus--test-validate-interface
+ (iface-name expected-properties expected-methods expected-signals
+ expected-annotations)
+ "Validate an interface definition for `dbus-test07-introspection'.
+The argument IFACE-NAME is a string naming the interface to validate.
+The arguments EXPECTED-PROPERTIES, EXPECTED-METHODS, EXPECTED-SIGNALS, and
+EXPECTED-ANNOTATIONS represent the names of the interface's properties,
+methods, signals, and annotations, respectively."
+
+ (let ((interface
+ (dbus-introspect-get-interface
+ :session dbus--test-service dbus--test-path iface-name)))
+ (pcase-let ((`(interface ((name . ,name)) . ,rest) interface))
+ (should
+ (string-equal name iface-name))
+ (should
+ (string-equal name (dbus-introspect-get-attribute interface "name")))
+
+ (let (properties methods signals annotations)
+ (mapc (lambda (x)
+ (let ((name (dbus-introspect-get-attribute x "name")))
+ (cond
+ ((eq 'property (car x)) (push name properties))
+ ((eq 'method (car x)) (push name methods))
+ ((eq 'signal (car x)) (push name signals))
+ ((eq 'annotation (car x)) (push name annotations)))))
+ rest)
+
+ (should
+ (equal
+ (nreverse properties)
+ expected-properties))
+ (should
+ (equal
+ (nreverse methods)
+ expected-methods))
+ (should
+ (equal
+ (nreverse signals)
+ expected-signals))
+ (should
+ (equal
+ (nreverse annotations)
+ expected-annotations))))))
+
+(defsubst dbus--test-validate-annotations (annotations expected-annotations)
+ "Validate a list of D-Bus ANNOTATIONS.
+Ensure each string in EXPECTED-ANNOTATIONS names an element of ANNOTATIONS.
+And ensure each ANNOTATIONS has a value attribute marked \"true\"."
+ (mapc
+ (lambda (annotation)
+ (let ((name (dbus-introspect-get-attribute annotation "name"))
+ (value (dbus-introspect-get-attribute annotation "value")))
+ (should
+ (member name expected-annotations))
+ (should
+ (equal value "true"))))
+ annotations))
+
+(defsubst dbus--test-validate-property
+ (interface property-name _expected-annotations &rest expected-args)
+ "Validate a property definition for `dbus-test07-introspection'.
+
+The argument INTERFACE is a string naming the interface owning PROPERTY-NAME.
+The argument PROPERTY-NAME is a string naming the property to validate.
+The arguments EXPECTED-ANNOTATIONS is a list of strings matching
+the annotation names defined for the method or signal.
+The argument EXPECTED-ARGS is a list of expected arguments for the property."
+ (let* ((property
+ (dbus-introspect-get-property
+ :session dbus--test-service dbus--test-path interface property-name))
+ (name (dbus-introspect-get-attribute property "name"))
+ (type (dbus-introspect-get-attribute property "type"))
+ (access (dbus-introspect-get-attribute property "access"))
+ (expected (assoc-string name expected-args)))
+ (should expected)
+
+ (should
+ (string-equal name property-name))
+
+ (should
+ (string-equal
+ (nth 0 expected)
+ name))
+
+ (should
+ (string-equal
+ (nth 1 expected)
+ type))
+
+ (should
+ (string-equal
+ (nth 2 expected)
+ access))))
+
+(defsubst dbus--test-validate-m-or-s (tree expected-annotations expected-args)
+ "Validate a method or signal definition for `dbus-test07-introspection'.
+The argument TREE is an sexp returned from either `dbus-introspect-get-method'
+or `dbus-introspect-get-signal'
+The arguments EXPECTED-ANNOTATIONS is a list of strings matching
+the annotation names defined for the method or signal.
+The argument EXPECTED-ARGS is a list of expected arguments for
+the method or signal."
+ (let (args annotations)
+ (mapc (lambda (elem)
+ (cond
+ ((eq 'arg (car elem)) (push elem args))
+ ((eq 'annotation (car elem)) (push elem annotations))))
+ tree)
+ (should
+ (equal
+ (nreverse args)
+ expected-args))
+ (dbus--test-validate-annotations annotations expected-annotations)))
+
+(defsubst dbus--test-validate-signal
+ (interface signal-name expected-annotations &rest expected-args)
+ "Validate a signal definition for `dbus-test07-introspection'.
+
+The argument INTERFACE is a string naming the interface owning SIGNAL-NAME.
+The argument SIGNAL-NAME is a string naming the signal to validate.
+The arguments EXPECTED-ANNOTATIONS is a list of strings matching
+the annotation names defined for the signal.
+The argument EXPECTED-ARGS is a list of expected arguments for the signal."
+ (let ((signal
+ (dbus-introspect-get-signal
+ :session dbus--test-service dbus--test-path interface signal-name)))
+ (pcase-let ((`(signal ((name . ,name)) . ,rest) signal))
+ (should
+ (string-equal name signal-name))
+ (should
+ (string-equal name (dbus-introspect-get-attribute signal "name")))
+ (dbus--test-validate-m-or-s rest expected-annotations expected-args))))
+
+(defsubst dbus--test-validate-method
+ (interface method-name expected-annotations &rest expected-args)
+ "Validate a method definition for `dbus-test07-introspection'.
+
+The argument INTERFACE is a string naming the interface owning METHOD-NAME.
+The argument METHOD-NAME is a string naming the method to validate.
+The arguments EXPECTED-ANNOTATIONS is a list of strings matching
+the annotation names defined for the method.
+The argument EXPECTED-ARGS is a list of expected arguments for the method."
+ (let ((method
+ (dbus-introspect-get-method
+ :session dbus--test-service dbus--test-path interface method-name)))
+ (pcase-let ((`(method ((name . ,name)) . ,rest) method))
+ (should
+ (string-equal name method-name))
+ (should
+ (string-equal name (dbus-introspect-get-attribute method "name")))
+ (dbus--test-validate-m-or-s rest expected-annotations expected-args))))
+
+(ert-deftest dbus-test07-introspection ()
+ "Register an Introspection interface then query it."
+ (skip-unless dbus--test-enabled-session-bus)
+ (dbus-ignore-errors (dbus-unregister-service :session dbus--test-service))
+ (dbus-register-service :session dbus--test-service)
+
+ ;; Prepare introspection response.
+ (dbus-register-method
+ :session dbus--test-service dbus--test-path dbus-interface-introspectable
+ "Introspect" 'dbus--test-introspect)
+ (dbus-register-method
+ :session dbus--test-service (concat dbus--test-path "/node0")
+ dbus-interface-introspectable
+ "Introspect" 'dbus--test-introspect)
+ (dbus-register-method
+ :session dbus--test-service (concat dbus--test-path "/node1")
+ dbus-interface-introspectable
+ "Introspect" 'dbus--test-introspect)
+ (unwind-protect
+ (let ((start (current-time)))
+ ;; dbus-introspect-get-node-names
+ (should
+ (equal
+ (dbus-introspect-get-node-names
+ :session dbus--test-service dbus--test-path)
+ '("node0" "node1")))
+
+ ;; dbus-introspect-get-all-nodes
+ (should
+ (equal
+ (dbus-introspect-get-all-nodes
+ :session dbus--test-service dbus--test-path)
+ (list dbus--test-path
+ (concat dbus--test-path "/node0")
+ (concat dbus--test-path "/node1"))))
+
+ ;; dbus-introspect-get-interface-names
+ (let ((interfaces
+ (dbus-introspect-get-interface-names
+ :session dbus--test-service dbus--test-path)))
+
+ (should
+ (equal
+ interfaces
+ `(,dbus-interface-introspectable
+ ,dbus-interface-properties
+ ,dbus--test-interface)))
+
+ (dbus--test-validate-interface
+ dbus-interface-introspectable nil '("Introspect") nil nil)
+
+ ;; dbus-introspect-get-interface via `dbus--test-validate-interface'.
+ (dbus--test-validate-interface
+ dbus-interface-properties nil
+ '("Get" "Set" "GetAll") '("PropertiesChanged") nil)
+
+ (dbus--test-validate-interface
+ dbus--test-interface '("Connected" "Player")
+ '("Connect" "DeprecatedMethod0" "DeprecatedMethod1") nil
+ `(,dbus-annotation-deprecated)))
+
+ ;; dbus-introspect-get-method-names
+ (let ((methods
+ (dbus-introspect-get-method-names
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface)))
+ (should
+ (equal
+ methods
+ '("Connect" "DeprecatedMethod0" "DeprecatedMethod1")))
+
+ ;; dbus-introspect-get-method via `dbus--test-validate-method'.
+ (dbus--test-validate-method
+ dbus--test-interface "Connect" nil
+ '(arg ((name . "uuid") (type . "s") (direction . "in")))
+ '(arg ((name . "mode") (type . "y") (direction . "in")))
+ '(arg ((name . "options") (type . "a{sv}") (direction . "in")))
+ '(arg ((name . "interface") (type . "s") (direction . "out"))))
+
+ (dbus--test-validate-method
+ dbus--test-interface "DeprecatedMethod0"
+ `(,dbus-annotation-deprecated))
+
+ (dbus--test-validate-method
+ dbus--test-interface "DeprecatedMethod1"
+ `(,dbus-annotation-deprecated)))
+
+ ;; dbus-introspect-get-signal-names
+ (let ((signals
+ (dbus-introspect-get-signal-names
+ :session dbus--test-service dbus--test-path
+ dbus-interface-properties)))
+ (should
+ (equal
+ signals
+ '("PropertiesChanged")))
+
+ ;; dbus-introspect-get-signal via `dbus--test-validate-signal'.
+ (dbus--test-validate-signal
+ dbus-interface-properties "PropertiesChanged" nil
+ '(arg ((name . "interface") (type . "s")))
+ '(arg ((name . "changed_properties") (type . "a{sv}")))
+ '(arg ((name . "invalidated_properties") (type . "as")))))
+
+ ;; dbus-intropct-get-property-names
+ (let ((properties
+ (dbus-introspect-get-property-names
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface)))
+ (should
+ (equal
+ properties
+ '("Connected" "Player")))
+
+ ;; dbus-introspect-get-property via `dbus--test-validate-property'.
+ (dbus--test-validate-property
+ dbus--test-interface "Connected" nil
+ '("Connected" "b" "read")
+ '("Player" "o" "read")))
+
+ ;; Elapsed time over a second suggests timeouts.
+ (should
+ (< 0.0 (float-time (time-since start)) 1.0)))
+
+ ;; Cleanup.
+ (dbus-unregister-service :session dbus--test-service)))
+
+(ert-deftest dbus-test07-introspection-timeout ()
+ "Verify introspection request timeouts."
+ :tags '(:expensive-test)
+ (skip-unless dbus--test-enabled-session-bus)
+ (dbus-ignore-errors (dbus-unregister-service :session dbus--test-service))
+ (dbus-register-service :session dbus--test-service)
+
+ (unwind-protect
+ (let ((start (current-time)))
+ (dbus-introspect-xml :session dbus--test-service dbus--test-path)
+ ;; Introspection internal timeout is one second.
+ (should
+ (< 1.0 (float-time (time-since start)))))
+
+ ;; Cleanup.
+ (dbus-unregister-service :session dbus--test-service)))
+
+(ert-deftest dbus-test08-register-monitor ()
+ "Check monitor registration."
+ :tags '(:expensive-test)
+ (skip-unless dbus--test-enabled-session-bus)
+
+ (unwind-protect
+ (let (registered)
+ (should
+ (equal
+ (setq registered
+ (dbus-register-monitor :session #'dbus--test-signal-handler))
+ '((:monitor :session-private)
+ (nil nil dbus--test-signal-handler))))
+
+ ;; Send a signal, shall be traced.
+ (setq dbus--test-signal-received nil)
+ (dbus-send-signal
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface "Foo" "foo")
+ (with-timeout (1 (dbus--test-timeout-handler))
+ (while (null dbus--test-signal-received)
+ (read-event nil nil 0.1)))
+
+ ;; Unregister monitor.
+ (should (dbus-unregister-object registered))
+ (should-not (dbus-unregister-object registered))
+
+ ;; Send a signal, shall not be traced.
+ (setq dbus--test-signal-received nil)
+ (dbus-send-signal
+ :session dbus--test-service dbus--test-path
+ dbus--test-interface "Foo" "foo")
+ (with-timeout (1 (ignore))
+ (while (null dbus--test-signal-received)
+ (read-event nil nil 0.1)))
+ (should-not dbus--test-signal-received))
+
+ ;; Cleanup.
+ (dbus-unregister-service :session dbus--test-service)))
+
+(ert-deftest dbus-test09-get-managed-objects ()
+ "Check `dbus-get-all-managed-objects'."
+ :tags '(:expensive-test)
+ (skip-unless dbus--test-enabled-session-bus)
+ (dbus-ignore-errors (dbus-unregister-service :session dbus--test-service))
+ (dbus-register-service :session dbus--test-service)
+
+ (unwind-protect
+ (let ((interfaces
+ `((,(concat dbus--test-interface ".I0")
+ ((,(concat dbus--test-path "/obj1")
+ (("I0Property1" . "Zero one one")
+ ("I0Property2" . "Zero one two")
+ ("I0Property3" . "Zero one three")))
+ (,(concat dbus--test-path "/obj0/obj2")
+ (("I0Property1" . "Zero two one")
+ ("I0Property2" . "Zero two two")
+ ("I0Property3" . "Zero two three")))
+ (,(concat dbus--test-path "/obj0/obj3")
+ (("I0Property1" . "Zero three one")
+ ("I0Property2" . "Zero three two")
+ ("I0Property3" . "Zero three three")))))
+ (,(concat dbus--test-interface ".I1")
+ ((,(concat dbus--test-path "/obj0/obj2")
+ (("I1Property1" . "One one one")
+ ("I1Property2" . "One one two")))
+ (,(concat dbus--test-path "/obj0/obj3")
+ (("I1Property1" . "One two one")
+ ("I1Property2" . "One two two"))))))))
+
+ (should-not
+ (dbus-get-all-managed-objects
+ :session dbus--test-service dbus--test-path))
+
+ (dolist (interface interfaces)
+ (pcase-let ((`(,iname ,objs) interface))
+ (dolist (obj objs)
+ (pcase-let ((`(,path ,props) obj))
+ (dolist (prop props)
+ (should
+ (equal
+ (dbus-register-property
+ :session dbus--test-service path iname
+ (car prop) :readwrite (cdr prop))
+ `((:property :session ,iname ,(car prop))
+ (,dbus--test-service ,path)))))))))
+
+ (let ((result (dbus-get-all-managed-objects
+ :session dbus--test-service dbus--test-path)))
+ (should
+ (= 3 (length result)))
+
+ (dolist (interface interfaces)
+ (pcase-let ((`(,iname ,objs) interface))
+ (dolist (obj objs)
+ (pcase-let ((`(,path ,props) obj))
+ (let* ((object (cadr (assoc-string path result)))
+ (iface (cadr (assoc-string iname object))))
+ (should object)
+ (should iface)
+ (dolist (prop props)
+ (should (equal (cdr (assoc-string (car prop) iface))
+ (cdr prop))))))))))
+
+ (let ((result (dbus-get-all-managed-objects
+ :session dbus--test-service
+ (concat dbus--test-path "/obj0"))))
+ (should
+ (= 2 (length result)))
+
+ (dolist (interface interfaces)
+ (pcase-let ((`(,iname ,objs) interface))
+ (dolist (obj objs)
+ (pcase-let ((`(,path ,props) obj))
+ (when (string-prefix-p (concat dbus--test-path "/obj0/") path)
+ (let* ((object (cadr (assoc-string path result)))
+ (iface (cadr (assoc-string iname object))))
+ (should object)
+ (should iface)
+ (dolist (prop props)
+ (should (equal (cdr (assoc-string (car prop) iface))
+ (cdr prop)))))))))))
+
+ (let ((result (dbus-get-all-managed-objects
+ :session dbus--test-service
+ (concat dbus--test-path "/obj0/obj2"))))
+ (should
+ (= 1 (length result)))
+
+ (dolist (interface interfaces)
+ (pcase-let ((`(,iname ,objs) interface))
+ (dolist (obj objs)
+ (pcase-let ((`(,path ,props) obj))
+ (when (string-prefix-p
+ (concat dbus--test-path "/obj0/obj2") path)
+ (let* ((object (cadr (assoc-string path result)))
+ (iface (cadr (assoc-string iname object))))
+ (should object)
+ (should iface)
+ (dolist (prop props)
+ (should (equal (cdr (assoc-string (car prop) iface))
+ (cdr prop))))))))))))
+
+ ;; Cleanup.
+ (dbus-unregister-service :session dbus--test-service)))
(defun dbus-test-all (&optional interactive)
"Run all tests for \\[dbus]."
(interactive "p")
- (funcall
- (if interactive 'ert-run-tests-interactively 'ert-run-tests-batch) "^dbus"))
+ (funcall (if interactive #'ert-run-tests-interactively #'ert-run-tests-batch)
+ "^dbus"))
(provide 'dbus-tests)
;;; dbus-tests.el ends here
diff --git a/test/lisp/net/dig-tests.el b/test/lisp/net/dig-tests.el
new file mode 100644
index 00000000000..780985cb6d3
--- /dev/null
+++ b/test/lisp/net/dig-tests.el
@@ -0,0 +1,56 @@
+;;; dig-tests.el --- Tests for dig.el -*- lexical-binding:t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+(require 'dig)
+
+(defvar dig-test-result-data "
+; <<>> DiG 9.11.16-2-Debian <<>> gnu.org
+;; global options: +cmd
+;; Got answer:
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7777
+;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
+
+;; OPT PSEUDOSECTION:
+; EDNS: version: 0, flags:; udp: 4096
+;; QUESTION SECTION:
+;gnu.org. IN A
+
+;; ANSWER SECTION:
+gnu.org. 300 IN A 111.11.111.111
+
+;; Query time: 127 msec
+;; SERVER: 192.168.0.1#53(192.168.0.1)
+;; WHEN: Sun Apr 26 00:47:55 CEST 2020
+;; MSG SIZE rcvd: 52
+
+" "Data used to test dig.el.")
+
+(ert-deftest dig-test-dig-extract-rr ()
+ (with-temp-buffer
+ (insert dig-test-result-data)
+ (should (equal (dig-extract-rr "gnu.org")
+ "gnu.org. 300 IN A 111.11.111.111"))))
+
+(provide 'dig-tests)
+;;; dig-tests.el ends here
diff --git a/test/lisp/net/gnutls-tests.el b/test/lisp/net/gnutls-tests.el
index 9a66081fcfd..76c00b7eaac 100644
--- a/test/lisp/net/gnutls-tests.el
+++ b/test/lisp/net/gnutls-tests.el
@@ -1,4 +1,4 @@
-;;; gnutls-tests.el --- Test suite for gnutls.el
+;;; gnutls-tests.el --- Test suite for gnutls.el -*- lexical-binding:t -*-
;; Copyright (C) 2017-2021 Free Software Foundation, Inc.
@@ -241,6 +241,7 @@
(ert-deftest test-gnutls-005-aead-ciphers ()
"Test the GnuTLS AEAD ciphers"
+ :tags '(:expensive-test)
(skip-unless (memq 'AEAD-ciphers (gnutls-available-p)))
(setq gnutls-tests-message-prefix "AEAD verification: ")
(let ((keys '("mykey" "mykey2"))
diff --git a/test/lisp/net/hmac-md5-tests.el b/test/lisp/net/hmac-md5-tests.el
new file mode 100644
index 00000000000..8e01353fa3f
--- /dev/null
+++ b/test/lisp/net/hmac-md5-tests.el
@@ -0,0 +1,80 @@
+;;; hmac-md5-tests.el --- Tests for hmac-md5.el -*- lexical-binding:t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+(require 'hmac-md5)
+
+;; Test cases from RFC 2202, "Test Cases for HMAC-MD5 and HMAC-SHA-1",
+;; moved here from hmac-md5.el
+
+(ert-deftest hmac-md5-test-encode-string ()
+ ;; RFC 2202 -- test_case 1
+ (should (equal (encode-hex-string
+ (hmac-md5 "Hi There" (make-string 16 ?\x0b)))
+ "9294727a3638bb1c13f48ef8158bfc9d"))
+
+ ;; RFC 2202 -- test_case 2
+ (should (equal (encode-hex-string
+ (hmac-md5 "what do ya want for nothing?" "Jefe"))
+ "750c783e6ab0b503eaa86e310a5db738"))
+
+ ;; RFC 2202 -- test_case 3
+ (should (equal (encode-hex-string
+ (hmac-md5 (decode-hex-string (make-string 100 ?d))
+ (decode-hex-string (make-string 32 ?a))))
+ "56be34521d144c88dbb8c733f0e8b3f6"))
+
+ ;; RFC 2202 -- test_case 4
+ (should (equal (encode-hex-string
+ (hmac-md5 (decode-hex-string
+ (mapconcat (lambda (c) (concat (list c) "d"))
+ (make-string 50 ?c) ""))
+ (decode-hex-string "0102030405060708090a0b0c0d0e0f10111213141516171819")))
+ "697eaf0aca3a3aea3a75164746ffaa79"))
+
+ ;; RFC 2202 -- test_case 5 (a)
+ (should (equal (encode-hex-string
+ (hmac-md5 "Test With Truncation" (make-string 16 ?\x0c)))
+ "56461ef2342edc00f9bab995690efd4c"))
+
+ ;; RFC 2202 -- test_case 5 (b)
+ (should (equal (encode-hex-string
+ (hmac-md5-96 "Test With Truncation" (make-string 16 ?\x0c)))
+ "56461ef2342edc00f9bab995"))
+
+ ;; RFC 2202 -- test_case 6
+ (should (equal (encode-hex-string
+ (hmac-md5
+ "Test Using Larger Than Block-Size Key - Hash Key First"
+ (decode-hex-string (make-string 160 ?a))))
+ "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd"))
+
+ ;; RFC 2202 -- test_case 7
+ (should (equal (encode-hex-string
+ (hmac-md5
+ "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"
+ (decode-hex-string (make-string 160 ?a))))
+ "6f630fad67cda0ee1fb1f562db3aa53e")))
+
+(provide 'hmac-md5-tests)
+;;; hmac-md5-tests.el ends here
diff --git a/test/data/mailcap/mime.types b/test/lisp/net/mailcap-resources/mime.types
index 4bedfaf9702..4bedfaf9702 100644
--- a/test/data/mailcap/mime.types
+++ b/test/lisp/net/mailcap-resources/mime.types
diff --git a/test/lisp/net/mailcap-tests.el b/test/lisp/net/mailcap-tests.el
index 4bd335523d1..a1a08322c0f 100644
--- a/test/lisp/net/mailcap-tests.el
+++ b/test/lisp/net/mailcap-tests.el
@@ -24,13 +24,10 @@
;;; Code:
(require 'ert)
+(require 'ert-x)
(require 'mailcap)
-(defconst mailcap-tests-data-dir
- (expand-file-name "test/data/mailcap" source-directory))
-
-(defconst mailcap-tests-path
- (expand-file-name "mime.types" mailcap-tests-data-dir)
+(defconst mailcap-tests-path (ert-resource-file "mime.types")
"String used as PATH argument of `mailcap-parse-mimetypes'.")
(defconst mailcap-tests-mime-extensions (copy-alist mailcap-mime-extensions))
diff --git a/test/lisp/net/netrc-resources/authinfo b/test/lisp/net/netrc-resources/authinfo
new file mode 100644
index 00000000000..88aa1712e9d
--- /dev/null
+++ b/test/lisp/net/netrc-resources/authinfo
@@ -0,0 +1,2 @@
+machine imap.example.org login jrh@example.org password "*foobar*"
+machine ftp.example.org login jrh password "*baz*"
diff --git a/test/lisp/net/netrc-resources/services b/test/lisp/net/netrc-resources/services
new file mode 100644
index 00000000000..fd8a0348df2
--- /dev/null
+++ b/test/lisp/net/netrc-resources/services
@@ -0,0 +1,6 @@
+tcpmux 1/tcp # TCP port service multiplexer
+smtp 25/tcp mail
+http 80/tcp www # WorldWideWeb HTTP
+kerberos 88/tcp kerberos5 krb5 kerberos-sec # Kerberos v5
+kerberos 88/udp kerberos5 krb5 kerberos-sec # Kerberos v5
+rtmp 1/ddp # Routing Table Maintenance Protocol
diff --git a/test/lisp/net/netrc-tests.el b/test/lisp/net/netrc-tests.el
new file mode 100644
index 00000000000..1328b191494
--- /dev/null
+++ b/test/lisp/net/netrc-tests.el
@@ -0,0 +1,53 @@
+;;; netrc-tests.el --- Tests for netrc.el -*- lexical-binding:t -*-
+
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+;; Author: Stefan Kangas <stefankangas@gmail.com>
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(require 'ert-x)
+(require 'netrc)
+
+(ert-deftest test-netrc-parse-services ()
+ (let ((netrc-services-file (ert-resource-file "services")))
+ (should (equal (netrc-parse-services)
+ '(("tcpmux" 1 tcp)
+ ("smtp" 25 tcp)
+ ("http" 80 tcp)
+ ("kerberos" 88 tcp)
+ ("kerberos" 88 udp)
+ ("rtmp" 1 ddp))))))
+
+(ert-deftest test-netrc-find-service-name ()
+ (let ((netrc-services-file (ert-resource-file "services")))
+ (should (equal (netrc-find-service-name 25) "smtp"))
+ (should (equal (netrc-find-service-name 88 'udp) "kerberos"))
+ (should-not (netrc-find-service-name 12345))))
+
+(ert-deftest test-netrc-credentials ()
+ (let ((netrc-file (ert-resource-file "authinfo")))
+ (should (equal (netrc-credentials "imap.example.org")
+ '("jrh@example.org" "*foobar*")))
+ (should (equal (netrc-credentials "ftp.example.org")
+ '("jrh" "*baz*")))))
+
+(provide 'netrc-tests)
+
+;;; netrc-tests.el ends here
diff --git a/test/data/net/cert.pem b/test/lisp/net/network-stream-resources/cert.pem
index 4df4e92e0bf..4df4e92e0bf 100644
--- a/test/data/net/cert.pem
+++ b/test/lisp/net/network-stream-resources/cert.pem
diff --git a/test/data/net/key.pem b/test/lisp/net/network-stream-resources/key.pem
index 5db58f573ca..5db58f573ca 100644
--- a/test/data/net/key.pem
+++ b/test/lisp/net/network-stream-resources/key.pem
diff --git a/test/lisp/net/network-stream-tests.el b/test/lisp/net/network-stream-tests.el
index d0b0c053e47..e0a06a28eec 100644
--- a/test/lisp/net/network-stream-tests.el
+++ b/test/lisp/net/network-stream-tests.el
@@ -24,6 +24,8 @@
;;; Code:
+(require 'ert)
+(require 'ert-x)
(require 'gnutls)
(require 'network-stream)
;; The require above is needed for 'open-network-stream' to work, but
@@ -136,7 +138,20 @@
(t
))))
+(defun network-test--resolve-system-name ()
+ (cl-loop for address in (network-lookup-address-info (system-name))
+ when (or (and (= (length address) 5)
+ ;; IPv4 localhost addresses start with 127.
+ (= (elt address 0) 127))
+ (and (= (length address) 9)
+ ;; IPv6 localhost address.
+ (equal address [0 0 0 0 0 0 0 1 0])))
+ return t))
+
(ert-deftest echo-server-with-dns ()
+ (unless (network-test--resolve-system-name)
+ (ert-skip "Can't test resolver for (system-name)"))
+
(let* ((server (make-server (system-name)))
(port (aref (process-contact server :local) 4))
(proc (make-network-process :name "foo"
@@ -226,16 +241,13 @@
(should (equal (buffer-string) "foo\n")))
(delete-process server)))
-(defconst network-stream-tests--datadir
- (expand-file-name "test/data/net" source-directory))
-
(defun make-tls-server (port)
(start-process "gnutls" (generate-new-buffer "*tls*")
"gnutls-serv" "--http"
"--x509keyfile"
- (concat network-stream-tests--datadir "/key.pem")
+ (ert-resource-file "key.pem")
"--x509certfile"
- (concat network-stream-tests--datadir "/cert.pem")
+ (ert-resource-file "cert.pem")
"--port" (format "%s" port)))
(ert-deftest connect-to-tls-ipv4-wait ()
@@ -724,4 +736,56 @@
44777
(vector :nowait t))))
+(ert-deftest check-network-process-coding-system-bind ()
+ "Check that binding coding-system-for-{read,write} works."
+ (let* ((coding-system-for-read 'binary)
+ (coding-system-for-write 'utf-8-unix)
+ (server
+ (make-network-process
+ :name "server"
+ :server t
+ :noquery t
+ :family 'ipv4
+ :service t
+ :host 'local))
+ (coding (process-coding-system server)))
+ (should (eq (car coding) 'binary))
+ (should (eq (cdr coding) 'utf-8-unix))
+ (delete-process server)))
+
+(ert-deftest check-network-process-coding-system-no-override ()
+ "Check that coding-system-for-{read,write} is not overridden by :coding nil."
+ (let* ((coding-system-for-read 'binary)
+ (coding-system-for-write 'utf-8-unix)
+ (server
+ (make-network-process
+ :name "server"
+ :server t
+ :noquery t
+ :family 'ipv4
+ :service t
+ :coding nil
+ :host 'local))
+ (coding (process-coding-system server)))
+ (should (eq (car coding) 'binary))
+ (should (eq (cdr coding) 'utf-8-unix))
+ (delete-process server)))
+
+(ert-deftest check-network-process-coding-system-override ()
+ "Check that :coding non-nil overrides coding-system-for-{read,write}."
+ (let* ((coding-system-for-read 'binary)
+ (coding-system-for-write 'utf-8-unix)
+ (server
+ (make-network-process
+ :name "server"
+ :server t
+ :noquery t
+ :family 'ipv4
+ :service t
+ :coding 'georgian-academy
+ :host 'local))
+ (coding (process-coding-system server)))
+ (should (eq (car coding) 'georgian-academy))
+ (should (eq (cdr coding) 'georgian-academy))
+ (delete-process server)))
;;; network-stream-tests.el ends here
diff --git a/test/lisp/net/newsticker-tests.el b/test/lisp/net/newsticker-tests.el
index 9f16e077491..e08f3110161 100644
--- a/test/lisp/net/newsticker-tests.el
+++ b/test/lisp/net/newsticker-tests.el
@@ -1,4 +1,4 @@
-;;; newsticker-testsuite.el --- Test suite for newsticker.
+;;; newsticker-tests.el --- Test suite for newsticker. -*- lexical-binding:t -*-
;; Copyright (C) 2003-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/net/ntlm-tests.el b/test/lisp/net/ntlm-tests.el
new file mode 100644
index 00000000000..6408ac13349
--- /dev/null
+++ b/test/lisp/net/ntlm-tests.el
@@ -0,0 +1,52 @@
+;;; ntlm-tests.el --- tests for ntlm.el -*- lexical-binding: t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+(require 'ert)
+(require 'ntlm)
+
+;; This is the Lisp bignum implementation of `ntlm--time-to-timestamp',
+;; for reference.
+(defun ntlm-tests--time-to-timestamp (time)
+ "Convert TIME to an NTLMv2 timestamp.
+Return a unibyte string representing the number of tenths of a
+microsecond since January 1, 1601 as a 64-bit little-endian
+signed integer. TIME must be on the form (HIGH LOW USEC PSEC)."
+ (let* ((s (+ (ash (nth 0 time) 16) (nth 1 time)))
+ (us (nth 2 time))
+ (ps (nth 3 time))
+ (tenths-of-us-since-jan-1-1601
+ (+ (* s 10000000) (* us 10) (/ ps 100000)
+ ;; tenths of microseconds between 1601-01-01 and 1970-01-01
+ 116444736000000000)))
+ (apply #'unibyte-string
+ (mapcar (lambda (i)
+ (logand (ash tenths-of-us-since-jan-1-1601 (* i -8))
+ #xff))
+ (number-sequence 0 7)))))
+
+(ert-deftest ntlm-time-to-timestamp ()
+ ;; Verify poor man's bignums in implementation that can run on Emacs < 27.1.
+ (let ((time '(24471 63910 412962 0)))
+ (should (equal (ntlm--time-to-timestamp time)
+ (ntlm-tests--time-to-timestamp time))))
+ (let ((time '(397431 65535 999999 999999)))
+ (should (equal (ntlm--time-to-timestamp time)
+ (ntlm-tests--time-to-timestamp time)))))
+
+(provide 'ntlm-tests)
diff --git a/test/lisp/net/puny-tests.el b/test/lisp/net/puny-tests.el
index f368d353705..b37168f5ca7 100644
--- a/test/lisp/net/puny-tests.el
+++ b/test/lisp/net/puny-tests.el
@@ -1,4 +1,4 @@
-;;; puny-tests.el --- tests for net/puny.el -*- coding: utf-8; -*-
+;;; puny-tests.el --- tests for net/puny.el -*- coding: utf-8; lexical-binding:t -*-
;; Copyright (C) 2017-2021 Free Software Foundation, Inc.
@@ -38,4 +38,25 @@
"Test puny decoding."
(should (string= (puny-decode-string "xn--9dbdkw") "חנוך")))
+(ert-deftest puny-test-encode-domain ()
+ (should (string= (puny-encode-domain "åäö.se") "xn--4cab6c.se")))
+
+(ert-deftest puny-test-decode-domain ()
+ (should (string= (puny-decode-domain "xn--4cab6c.se") "åäö.se")))
+
+(ert-deftest puny-highly-restrictive-domain-p ()
+ (should (puny-highly-restrictive-domain-p "foo.bar.org"))
+ (should (puny-highly-restrictive-domain-p "foo.abcåäö.org"))
+ (should (puny-highly-restrictive-domain-p "foo.ர.org"))
+ ;; Disallow unicode character 2044, visually similar to "/".
+ (should-not (puny-highly-restrictive-domain-p "www.yourbank.com⁄login⁄checkUser.jsp?inxs.ch"))
+ ;; Disallow mixing scripts.
+ (should-not (puny-highly-restrictive-domain-p "åர.org"))
+ ;; Only allowed in moderately restrictive.
+ (should-not (puny-highly-restrictive-domain-p "Teχ.org"))
+ (should-not (puny-highly-restrictive-domain-p "HλLF-LIFE.org"))
+ (should-not (puny-highly-restrictive-domain-p "Ωmega.org"))
+ ;; Only allowed in unrestricted.
+ (should-not (puny-highly-restrictive-domain-p "I♥NY.org")))
+
;;; puny-tests.el ends here
diff --git a/test/lisp/net/rcirc-tests.el b/test/lisp/net/rcirc-tests.el
index 7750db111bc..fd96b7ba714 100644
--- a/test/lisp/net/rcirc-tests.el
+++ b/test/lisp/net/rcirc-tests.el
@@ -2,18 +2,20 @@
;; Copyright (C) 2019-2021 Free Software Foundation, Inc.
-;; This program is free software: you can redistribute it and/or
+;; 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.
;;
-;; This program is distributed in the hope that it will be useful, but
+;; 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 `https://www.gnu.org/licenses/'.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Code:
@@ -49,4 +51,16 @@
"MODE #cchan +kl :a:b"
nil "MODE" '("#cchan" "+kl" "a:b")))
+(ert-deftest rcirc-rename-nicks ()
+ (should (equal (rcirc--make-new-nick "foo" 16)
+ "foo`"))
+ (should (equal (rcirc--make-new-nick "123456789012345" 16)
+ "123456789012345`"))
+ (should (equal (rcirc--make-new-nick "1234567890123456" 16)
+ "123456789012345`"))
+ (should (equal (rcirc--make-new-nick "123456789012345`" 16)
+ "12345678901234``"))
+ (should (equal (rcirc--make-new-nick "123456789012````" 16)
+ "12345678901`````")))
+
;;; rcirc-tests.el ends here
diff --git a/test/lisp/net/rfc2104-tests.el b/test/lisp/net/rfc2104-tests.el
index 27dd168a630..f3498e760a3 100644
--- a/test/lisp/net/rfc2104-tests.el
+++ b/test/lisp/net/rfc2104-tests.el
@@ -1,21 +1,23 @@
-;;; rfc2104-tests.el --- Tests of RFC2104 hashes
+;;; rfc2104-tests.el --- Tests of RFC2104 hashes -*- lexical-binding:t -*-
;; Copyright (C) 2019-2021 Free Software Foundation, Inc.
;; Author: Lars Ingebrigtsen <larsi@gnus.org>
-;; This program is free software: you can redistribute it and/or
+;; 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.
;;
-;; This program is distributed in the hope that it will be useful, but
+;; 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 `https://www.gnu.org/licenses/'.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Code:
diff --git a/test/lisp/net/sasl-scram-rfc-tests.el b/test/lisp/net/sasl-scram-rfc-tests.el
index 2f021b9d598..3e9879a49d4 100644
--- a/test/lisp/net/sasl-scram-rfc-tests.el
+++ b/test/lisp/net/sasl-scram-rfc-tests.el
@@ -1,4 +1,4 @@
-;;; sasl-scram-rfc-tests.el --- tests for SCRAM-SHA-1 -*- lexical-binding: t; -*-
+;;; sasl-scram-rfc-tests.el --- tests for SCRAM -*- lexical-binding: t; -*-
;; Copyright (C) 2014-2021 Free Software Foundation, Inc.
@@ -19,7 +19,7 @@
;;; Commentary:
-;; Test cases from RFC 5802.
+;; Test cases from RFC 5802 and RFC 7677.
;;; Code:
@@ -47,4 +47,26 @@
(sasl-scram-sha-1-authenticate-server client (vector nil "v=rmF9pqV8S7suAoZWja4dJRkFsKQ=
"))))
+(require 'sasl-scram-sha256)
+
+(ert-deftest sasl-scram-sha-256-test ()
+ ;; The following strings are taken from section 3 of RFC 7677.
+ (let ((client
+ (sasl-make-client (sasl-find-mechanism '("SCRAM-SHA-256"))
+ "user"
+ "imap"
+ "localhost"))
+ (data "r=rOprNGfwEbeRWgbNEkqO%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0,s=W22ZaJ0SNY7soEsUEjb6gQ==,i=4096")
+ (c-nonce "rOprNGfwEbeRWgbNEkqO")
+ (sasl-read-passphrase
+ (lambda (_prompt) (copy-sequence "pencil"))))
+ (sasl-client-set-property client 'c-nonce c-nonce)
+ (should
+ (equal
+ (sasl-scram-sha-256-client-final-message client (vector nil data))
+ "c=biws,r=rOprNGfwEbeRWgbNEkqO%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0,p=dHzbZapWIk4jUhN+Ute9ytag9zjfMHgsqmmiz7AndVQ="))
+
+ ;; This should not throw an error:
+ (sasl-scram-sha-256-authenticate-server client (vector nil "v=6rriTRBi23WpRR/wtup+mMhUZUn/dB5nLTJRsjl95G4="))))
+
;;; sasl-scram-rfc-tests.el ends here
diff --git a/test/lisp/net/secrets-tests.el b/test/lisp/net/secrets-tests.el
index 525e5bf97c5..b392c4d1847 100644
--- a/test/lisp/net/secrets-tests.el
+++ b/test/lisp/net/secrets-tests.el
@@ -4,18 +4,20 @@
;; Author: Michael Albinus <michael.albinus@gmx.de>
-;; This program is free software: you can redistribute it and/or
+;; 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.
;;
-;; This program is distributed in the hope that it will be useful, but
+;; 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 `https://www.gnu.org/licenses/'.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Code:
diff --git a/test/data/shr/div-div.html b/test/lisp/net/shr-resources/div-div.html
index 1c191ae44d8..1c191ae44d8 100644
--- a/test/data/shr/div-div.html
+++ b/test/lisp/net/shr-resources/div-div.html
diff --git a/test/data/shr/div-div.txt b/test/lisp/net/shr-resources/div-div.txt
index 62715e12513..62715e12513 100644
--- a/test/data/shr/div-div.txt
+++ b/test/lisp/net/shr-resources/div-div.txt
diff --git a/test/data/shr/div-p.html b/test/lisp/net/shr-resources/div-p.html
index fcbdfc43293..fcbdfc43293 100644
--- a/test/data/shr/div-p.html
+++ b/test/lisp/net/shr-resources/div-p.html
diff --git a/test/data/shr/div-p.txt b/test/lisp/net/shr-resources/div-p.txt
index 859d731da89..859d731da89 100644
--- a/test/data/shr/div-p.txt
+++ b/test/lisp/net/shr-resources/div-p.txt
diff --git a/test/data/shr/li-div.html b/test/lisp/net/shr-resources/li-div.html
index eca3c511bd9..eca3c511bd9 100644
--- a/test/data/shr/li-div.html
+++ b/test/lisp/net/shr-resources/li-div.html
diff --git a/test/data/shr/li-div.txt b/test/lisp/net/shr-resources/li-div.txt
index 9fc54f2bdc6..9fc54f2bdc6 100644
--- a/test/data/shr/li-div.txt
+++ b/test/lisp/net/shr-resources/li-div.txt
diff --git a/test/data/shr/li-empty.html b/test/lisp/net/shr-resources/li-empty.html
index 05cfee7bdd4..05cfee7bdd4 100644
--- a/test/data/shr/li-empty.html
+++ b/test/lisp/net/shr-resources/li-empty.html
diff --git a/test/data/shr/li-empty.txt b/test/lisp/net/shr-resources/li-empty.txt
index 906fd8df8b3..906fd8df8b3 100644
--- a/test/data/shr/li-empty.txt
+++ b/test/lisp/net/shr-resources/li-empty.txt
diff --git a/test/data/shr/nonbr.html b/test/lisp/net/shr-resources/nonbr.html
index 56282cf4ca5..56282cf4ca5 100644
--- a/test/data/shr/nonbr.html
+++ b/test/lisp/net/shr-resources/nonbr.html
diff --git a/test/data/shr/nonbr.txt b/test/lisp/net/shr-resources/nonbr.txt
index 0c3cffa93f9..0c3cffa93f9 100644
--- a/test/data/shr/nonbr.txt
+++ b/test/lisp/net/shr-resources/nonbr.txt
diff --git a/test/data/shr/ol.html b/test/lisp/net/shr-resources/ol.html
index f9a15f26409..f9a15f26409 100644
--- a/test/data/shr/ol.html
+++ b/test/lisp/net/shr-resources/ol.html
diff --git a/test/data/shr/ol.txt b/test/lisp/net/shr-resources/ol.txt
index 0d46e2a8ddb..0d46e2a8ddb 100644
--- a/test/data/shr/ol.txt
+++ b/test/lisp/net/shr-resources/ol.txt
diff --git a/test/data/shr/ul-empty.html b/test/lisp/net/shr-resources/ul-empty.html
index e5a75ab9216..e5a75ab9216 100644
--- a/test/data/shr/ul-empty.html
+++ b/test/lisp/net/shr-resources/ul-empty.html
diff --git a/test/data/shr/ul-empty.txt b/test/lisp/net/shr-resources/ul-empty.txt
index 8993555425b..8993555425b 100644
--- a/test/data/shr/ul-empty.txt
+++ b/test/lisp/net/shr-resources/ul-empty.txt
diff --git a/test/lisp/net/shr-tests.el b/test/lisp/net/shr-tests.el
index 35b6c6f5acd..a06e31a4f88 100644
--- a/test/lisp/net/shr-tests.el
+++ b/test/lisp/net/shr-tests.el
@@ -23,14 +23,13 @@
;;; Code:
+(require 'ert)
+(require 'ert-x)
(require 'shr)
-(defconst shr-tests--datadir
- (expand-file-name "test/data/shr" source-directory))
-
(defun shr-test (name)
(with-temp-buffer
- (insert-file-contents (format (concat shr-tests--datadir "/%s.html") name))
+ (insert-file-contents (format (concat (ert-resource-directory) "/%s.html") name))
(let ((dom (libxml-parse-html-region (point-min) (point-max)))
(shr-width 80)
(shr-use-fonts nil))
@@ -39,7 +38,7 @@
(cons (buffer-substring-no-properties (point-min) (point-max))
(with-temp-buffer
(insert-file-contents
- (format (concat shr-tests--datadir "/%s.txt") name))
+ (format (concat (ert-resource-directory) "/%s.txt") name))
(while (re-search-forward "%\\([0-9A-F][0-9A-F]\\)" nil t)
(replace-match (string (string-to-number (match-string 1) 16))
t t))
@@ -47,7 +46,7 @@
(ert-deftest rendering ()
(skip-unless (fboundp 'libxml-parse-html-region))
- (dolist (file (directory-files shr-tests--datadir nil "\\.html\\'"))
+ (dolist (file (directory-files (ert-resource-directory) nil "\\.html\\'"))
(let* ((name (replace-regexp-in-string "\\.html\\'" "" file))
(result (shr-test name)))
(unless (equal (car result) (cdr result))
diff --git a/test/lisp/net/tramp-archive-tests.el b/test/lisp/net/tramp-archive-tests.el
index b0016203ffa..6a6b56f4a1d 100644
--- a/test/lisp/net/tramp-archive-tests.el
+++ b/test/lisp/net/tramp-archive-tests.el
@@ -4,18 +4,20 @@
;; Author: Michael Albinus <michael.albinus@gmx.de>
-;; This program is free software: you can redistribute it and/or
+;; 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.
;;
-;; This program is distributed in the hope that it will be useful, but
+;; 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 `https://www.gnu.org/licenses/'.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
@@ -27,40 +29,74 @@
;; tests in tramp-tests.el.
(require 'ert)
+(require 'ert-x)
(require 'tramp-archive)
(defvar tramp-copy-size-limit)
(defvar tramp-persistency-file-name)
-(defconst tramp-archive-test-resource-directory
- (let ((default-directory
- (if load-in-progress
- (file-name-directory load-file-name)
- default-directory)))
- (cond
- ((file-accessible-directory-p (expand-file-name "resources"))
- (expand-file-name "resources"))
- ((file-accessible-directory-p (expand-file-name "tramp-archive-resources"))
- (expand-file-name "tramp-archive-resources"))))
- "The resources directory test files are located in.")
-
-(defconst tramp-archive-test-file-archive
- (file-truename
- (expand-file-name "foo.tar.gz" tramp-archive-test-resource-directory))
+;; `ert-resource-file' was introduced in Emacs 28.1.
+(unless (macrop 'ert-resource-file)
+ (eval-and-compile
+ (defvar ert-resource-directory-format "%s-resources/"
+ "Format for `ert-resource-directory'.")
+ (defvar ert-resource-directory-trim-left-regexp ""
+ "Regexp for `string-trim' (left) used by `ert-resource-directory'.")
+ (defvar ert-resource-directory-trim-right-regexp "\\(-tests?\\)?\\.el"
+ "Regexp for `string-trim' (right) used by `ert-resource-directory'.")
+
+ (defmacro ert-resource-directory ()
+ "Return absolute file name of the resource directory for this file.
+
+The path to the resource directory is the \"resources\" directory
+in the same directory as the test file.
+
+If that directory doesn't exist, use the directory named like the
+test file but formatted by `ert-resource-directory-format' and trimmed
+using `string-trim' with arguments
+`ert-resource-directory-trim-left-regexp' and
+`ert-resource-directory-trim-right-regexp'. The default values mean
+that if called from a test file named \"foo-tests.el\", return
+the absolute file name for \"foo-resources\"."
+ `(let* ((testfile ,(or (bound-and-true-p byte-compile-current-file)
+ (and load-in-progress load-file-name)
+ buffer-file-name))
+ (default-directory (file-name-directory testfile)))
+ (file-truename
+ (if (file-accessible-directory-p "resources/")
+ (expand-file-name "resources/")
+ (expand-file-name
+ (format
+ ert-resource-directory-format
+ (string-trim testfile
+ ert-resource-directory-trim-left-regexp
+ ert-resource-directory-trim-right-regexp)))))))
+
+ (defmacro ert-resource-file (file)
+ "Return file name of resource file named FILE.
+A resource file is in the resource directory as per
+`ert-resource-directory'."
+ `(expand-file-name ,file (ert-resource-directory)))))
+
+(defconst tramp-archive-test-file-archive (ert-resource-file "foo.tar.gz")
"The test file archive.")
+(defun tramp-archive-test-file-archive-hexlified ()
+ "Return hexlified `tramp-archive-test-file-archive'.
+Do not hexlify \"/\". This hexlified string is used in `file:///' URLs."
+ (let* ((url-unreserved-chars (cons ?/ url-unreserved-chars)))
+ (url-hexify-string tramp-archive-test-file-archive)))
+
(defconst tramp-archive-test-archive
(file-name-as-directory tramp-archive-test-file-archive)
"The test archive.")
(defconst tramp-archive-test-directory
- (file-truename
- (expand-file-name "foo.iso" tramp-archive-test-resource-directory))
+ (file-truename (ert-resource-file "foo.iso"))
"A directory file name, which looks like an archive.")
(setq password-cache-expiry nil
tramp-cache-read-persistent-data t ;; For auth-sources.
tramp-copy-size-limit nil
- tramp-message-show-message nil
tramp-persistency-file-name nil
tramp-verbose 0)
@@ -175,7 +211,8 @@ variables, so we check the Emacs version directly."
(should
(string-equal
host
- (url-hexify-string (concat "file://" tramp-archive-test-file-archive))))
+ (url-hexify-string
+ (concat "file://" (tramp-archive-test-file-archive-hexlified)))))
(should-not port)
(should (string-equal localname "/"))
(should (string-equal archive tramp-archive-test-file-archive)))
@@ -194,7 +231,8 @@ variables, so we check the Emacs version directly."
(should
(string-equal
host
- (url-hexify-string (concat "file://" tramp-archive-test-file-archive))))
+ (url-hexify-string
+ (concat "file://" (tramp-archive-test-file-archive-hexlified)))))
(should-not port)
(should (string-equal localname "/foo"))
(should (string-equal archive tramp-archive-test-file-archive)))
@@ -238,7 +276,8 @@ variables, so we check the Emacs version directly."
;; archive boundaries. So we must cut the
;; trailing slash ourselves.
(substring
- (file-name-directory tramp-archive-test-file-archive)
+ (file-name-directory
+ (tramp-archive-test-file-archive-hexlified))
0 -1)))
nil "/"))
(file-name-nondirectory tramp-archive-test-file-archive)))))
@@ -971,4 +1010,5 @@ If INTERACTIVE is non-nil, the tests are run interactively."
"^tramp-archive"))
(provide 'tramp-archive-tests)
+
;;; tramp-archive-tests.el ends here
diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el
index 8c19cf2d38f..896b9978e7c 100644
--- a/test/lisp/net/tramp-tests.el
+++ b/test/lisp/net/tramp-tests.el
@@ -4,18 +4,20 @@
;; Author: Michael Albinus <michael.albinus@gmx.de>
-;; This program is free software: you can redistribute it and/or
+;; 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.
;;
-;; This program is distributed in the hope that it will be useful, but
+;; 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 `https://www.gnu.org/licenses/'.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
@@ -43,6 +45,7 @@
(require 'dired)
(require 'ert)
(require 'ert-x)
+(require 'trace)
(require 'tramp)
(require 'vc)
(require 'vc-bzr)
@@ -50,14 +53,13 @@
(require 'vc-hg)
(declare-function tramp-find-executable "tramp-sh")
+(declare-function tramp-get-remote-chmod-h "tramp-sh")
(declare-function tramp-get-remote-gid "tramp-sh")
(declare-function tramp-get-remote-path "tramp-sh")
(declare-function tramp-get-remote-perl "tramp-sh")
(declare-function tramp-get-remote-stat "tramp-sh")
(declare-function tramp-list-tramp-buffers "tramp-cmds")
-(declare-function tramp-method-out-of-band-p "tramp-sh")
(declare-function tramp-smb-get-localname "tramp-smb")
-(declare-function tramp-time-diff "tramp")
(defvar ange-ftp-make-backup-files)
(defvar auto-save-file-name-transforms)
(defvar tramp-connection-properties)
@@ -68,8 +70,6 @@
(defvar tramp-remote-path)
(defvar tramp-remote-process-environment)
-;; Needed for Emacs 24.
-(defvar inhibit-message)
;; Needed for Emacs 25.
(defvar connection-local-criteria-alist)
(defvar connection-local-profile-alist)
@@ -98,25 +98,30 @@
'("mock"
(tramp-login-program "sh")
(tramp-login-args (("-i")))
+ (tramp-direct-async-args (("-c")))
(tramp-remote-shell "/bin/sh")
(tramp-remote-shell-args ("-c"))
(tramp-connection-timeout 10)))
(add-to-list
'tramp-default-host-alist
`("\\`mock\\'" nil ,(system-name)))
- ;; Emacs' Makefile sets $HOME to a nonexistent value. Needed in
- ;; batch mode only, therefore.
+ ;; Emacs's Makefile sets $HOME to a nonexistent value. Needed
+ ;; in batch mode only, therefore.
(unless (and (null noninteractive) (file-directory-p "~/"))
(setenv "HOME" temporary-file-directory))
(format "/mock::%s" temporary-file-directory)))
"Temporary directory for Tramp tests.")
+(defconst tramp-test-vec
+ (and (file-remote-p tramp-test-temporary-file-directory)
+ (tramp-dissect-file-name tramp-test-temporary-file-directory))
+ "The used `tramp-file-name' structure.")
+
(setq auth-source-save-behavior nil
password-cache-expiry nil
remote-file-name-inhibit-cache nil
tramp-cache-read-persistent-data t ;; For auth-sources.
tramp-copy-size-limit nil
- tramp-message-show-message nil
tramp-persistency-file-name nil
tramp-verbose 0)
@@ -144,9 +149,7 @@ being the result.")
(when (cdr tramp--test-enabled-checked)
;; Cleanup connection.
(ignore-errors
- (tramp-cleanup-connection
- (tramp-dissect-file-name tramp-test-temporary-file-directory)
- nil 'keep-password)))
+ (tramp-cleanup-connection tramp-test-vec nil 'keep-password)))
;; Return result.
(cdr tramp--test-enabled-checked))
@@ -177,38 +180,46 @@ This shall used dynamically bound only.")
(defmacro tramp--test-instrument-test-case (verbose &rest body)
"Run BODY with `tramp-verbose' equal VERBOSE.
Print the content of the Tramp connection and debug buffers, if
-`tramp-verbose' is greater than 3. `should-error' is not handled
-properly. BODY shall not contain a timeout."
+`tramp-verbose' is greater than 3. Print traces if `tramp-verbose'
+is greater than 10.
+`should-error' is not handled properly. BODY shall not contain a timeout."
(declare (indent 1) (debug (natnump body)))
- `(let ((tramp-verbose (max (or ,verbose 0) (or tramp-verbose 0)))
- (tramp-message-show-message t)
- (debug-ignored-errors
- (append
- '("^make-symbolic-link not supported$"
- "^error with add-name-to-file")
- debug-ignored-errors))
- inhibit-message)
+ `(let* ((tramp-verbose (max (or ,verbose 0) (or tramp-verbose 0)))
+ (trace-buffer
+ (when (> tramp-verbose 10) (generate-new-buffer " *temp*")))
+ (debug-ignored-errors
+ (append
+ '("^make-symbolic-link not supported$"
+ "^error with add-name-to-file")
+ debug-ignored-errors))
+ inhibit-message)
+ (when trace-buffer
+ (dolist (elt (all-completions "tramp-" obarray 'functionp))
+ (trace-function-background (intern elt))))
(unwind-protect
(let ((tramp--test-instrument-test-case-p t)) ,@body)
;; Unwind forms.
+ (when trace-buffer
+ (untrace-all))
(when (and (null tramp--test-instrument-test-case-p) (> tramp-verbose 3))
- (dolist (buf (tramp-list-tramp-buffers))
+ (dolist
+ (buf (if trace-buffer
+ (cons (get-buffer trace-buffer) (tramp-list-tramp-buffers))
+ (tramp-list-tramp-buffers)))
(with-current-buffer buf
- (message ";; %s\n%s" buf (buffer-string))))))))
+ (message ";; %s\n%s" buf (buffer-string)))))
+ (when trace-buffer
+ (kill-buffer trace-buffer)))))
(defsubst tramp--test-message (fmt-string &rest arguments)
"Emit a message into ERT *Messages*."
(tramp--test-instrument-test-case 0
- (apply
- #'tramp-message
- (tramp-dissect-file-name tramp-test-temporary-file-directory) 0
- fmt-string arguments)))
+ (apply #'tramp-message tramp-test-vec 0 fmt-string arguments)))
(defsubst tramp--test-backtrace ()
"Dump a backtrace into ERT *Messages*."
(tramp--test-instrument-test-case 10
- (tramp-backtrace
- (tramp-dissect-file-name tramp-test-temporary-file-directory))))
+ (tramp-backtrace tramp-test-vec)))
(defmacro tramp--test-print-duration (message &rest body)
"Run BODY and print a message with duration, prompted by MESSAGE."
@@ -1970,9 +1981,9 @@ properly. BODY shall not contain a timeout."
;; Host names must match rules in case the command template of a
;; method doesn't use them.
(dolist (m '("su" "sg" "sudo" "doas" "ksu"))
- (let ((vec (tramp-dissect-file-name tramp-test-temporary-file-directory))
- tramp-connection-properties tramp-default-proxies-alist)
- (ignore-errors (tramp-cleanup-connection vec nil 'keep-password))
+ (let (tramp-connection-properties tramp-default-proxies-alist)
+ (ignore-errors
+ (tramp-cleanup-connection tramp-test-vec nil 'keep-password))
;; Single hop. The host name must match `tramp-local-host-regexp'.
(should-error
(find-file (format "/%s:foo:" m))
@@ -1992,16 +2003,17 @@ properly. BODY shall not contain a timeout."
(skip-unless (tramp--test-enabled))
;; Multi hops are allowed for inline methods only.
- (should-error
- (file-remote-p "/ssh:user1@host1|method:user2@host2:/path/to/file")
- :type 'user-error)
- (should-error
- (file-remote-p "/method:user1@host1|ssh:user2@host2:/path/to/file")
- :type 'user-error)
+ (let (non-essential)
+ (should-error
+ (expand-file-name "/ssh:user1@host1|method:user2@host2:/path/to/file")
+ :type 'user-error)
+ (should-error
+ (expand-file-name "/method:user1@host1|ssh:user2@host2:/path/to/file")
+ :type 'user-error))
;; Samba does not support file names with periods followed by
;; spaces, and trailing periods or spaces.
- (when (tramp-smb-file-name-p tramp-test-temporary-file-directory)
+ (when (tramp--test-smb-p)
(dolist (file '("foo." "foo. bar" "foo "))
(should-error
(tramp-smb-get-localname
@@ -2013,8 +2025,12 @@ properly. BODY shall not contain a timeout."
"Check `substitute-in-file-name'."
(skip-unless (eq tramp-syntax 'default))
- ;; Suppress method name check.
- (let ((tramp-methods (cons '("method") tramp-methods)))
+ ;; Suppress method name check. We cannot use the string "foo" as
+ ;; user name, because (substitute-in-string "/~foo") returns
+ ;; different values depending on the existence of user "foo" (see
+ ;; Bug#43052).
+ (let ((tramp-methods (cons '("method") tramp-methods))
+ (foo (downcase (md5 (current-time-string)))))
(should
(string-equal (substitute-in-file-name "/method:host:///foo") "/foo"))
(should
@@ -2043,39 +2059,43 @@ properly. BODY shall not contain a timeout."
"/method:host:/:/path//foo"))
;; Forwhatever reasons, the following tests let Emacs crash for
- ;; Emacs 24 and Emacs 25, occasionally. No idea what's up.
+ ;; Emacs 25, occasionally. No idea what's up.
(when (tramp--test-emacs26-p)
(should
- (string-equal (substitute-in-file-name "/method:host://~foo") "/~foo"))
+ (string-equal
+ (substitute-in-file-name (concat "/method:host://~" foo))
+ (concat "/~" foo)))
(should
(string-equal
- (substitute-in-file-name "/method:host:/~foo") "/method:host:/~foo"))
+ (substitute-in-file-name (concat "/method:host:/~" foo))
+ (concat "/method:host:/~" foo)))
(should
(string-equal
- (substitute-in-file-name "/method:host:/path//~foo") "/~foo"))
+ (substitute-in-file-name (concat "/method:host:/path//~" foo))
+ (concat "/~" foo)))
;; (substitute-in-file-name "/path/~foo") expands only for a local
;; user "foo" to "/~foo"". Otherwise, it doesn't expand.
(should
(string-equal
- (substitute-in-file-name "/method:host:/path/~foo")
- "/method:host:/path/~foo"))
+ (substitute-in-file-name (concat "/method:host:/path/~" foo))
+ (concat "/method:host:/path/~" foo)))
;; Quoting local part.
(should
(string-equal
- (substitute-in-file-name "/method:host:/://~foo")
- "/method:host:/://~foo"))
+ (substitute-in-file-name (concat "/method:host:/://~" foo))
+ (concat "/method:host:/://~" foo)))
(should
(string-equal
- (substitute-in-file-name
- "/method:host:/:/~foo") "/method:host:/:/~foo"))
+ (substitute-in-file-name (concat "/method:host:/:/~" foo))
+ (concat "/method:host:/:/~" foo)))
(should
(string-equal
- (substitute-in-file-name "/method:host:/:/path//~foo")
- "/method:host:/:/path//~foo"))
+ (substitute-in-file-name (concat "/method:host:/:/path//~" foo))
+ (concat "/method:host:/:/path//~" foo)))
(should
(string-equal
- (substitute-in-file-name "/method:host:/:/path/~foo")
- "/method:host:/:/path/~foo")))
+ (substitute-in-file-name (concat "/method:host:/:/path/~" foo))
+ (concat "/method:host:/:/path/~" foo))))
(let (process-environment)
(should
@@ -2215,11 +2235,10 @@ This checks also `file-name-as-directory', `file-name-directory',
;; Bug#10085.
(when (tramp--test-enabled) ;; Packages like tramp-gvfs.el might be disabled.
- (dolist (n-e '(nil t))
+ (dolist (non-essential '(nil t))
;; We must clear `tramp-default-method'. On hydra, it is "ftp",
;; which ruins the tests.
- (let ((non-essential n-e)
- (tramp-default-method
+ (let ((tramp-default-method
(file-remote-p tramp-test-temporary-file-directory 'method))
(host (file-remote-p tramp-test-temporary-file-directory 'host)))
(dolist
@@ -2235,7 +2254,7 @@ This checks also `file-name-as-directory', `file-name-directory',
(should
(string-equal
(file-name-as-directory file)
- (if (tramp-completion-mode-p)
+ (if non-essential
file (concat file (if (tramp--test-ange-ftp-p) "/" "./")))))
(should (string-equal (file-name-directory file) file))
(should (string-equal (file-name-nondirectory file) "")))))))
@@ -2250,7 +2269,28 @@ This checks also `file-name-as-directory', `file-name-directory',
(write-region "foo" nil tmp-name)
(should (file-exists-p tmp-name))
(delete-file tmp-name)
- (should-not (file-exists-p tmp-name)))))
+ (should-not (file-exists-p tmp-name))
+
+ ;; Trashing files doesn't work for crypted remote files.
+ (unless (tramp--test-crypt-p)
+ (let ((trash-directory (tramp--test-make-temp-name 'local quoted))
+ (delete-by-moving-to-trash t))
+ (make-directory trash-directory)
+ (should-not (file-exists-p tmp-name))
+ (write-region "foo" nil tmp-name)
+ (should (file-exists-p tmp-name))
+ (delete-file tmp-name 'trash)
+ (should-not (file-exists-p tmp-name))
+ (should
+ (or (file-exists-p
+ (expand-file-name
+ (file-name-nondirectory tmp-name) trash-directory))
+ ;; Gdrive.
+ (file-symlink-p
+ (expand-file-name
+ (file-name-nondirectory tmp-name) trash-directory))))
+ (delete-directory trash-directory 'recursive)
+ (should-not (file-exists-p trash-directory)))))))
(ert-deftest tramp-test08-file-local-copy ()
"Check `file-local-copy'."
@@ -2293,16 +2333,25 @@ This checks also `file-name-as-directory', `file-name-directory',
(unwind-protect
(with-temp-buffer
(write-region "foo" nil tmp-name)
- (insert-file-contents tmp-name)
- (should (string-equal (buffer-string) "foo"))
- (insert-file-contents tmp-name)
- (should (string-equal (buffer-string) "foofoo"))
+ (let ((point (point)))
+ (insert-file-contents tmp-name)
+ (should (string-equal (buffer-string) "foo"))
+ (should (= point (point))))
+ (goto-char (1+ (point)))
+ (let ((point (point)))
+ (insert-file-contents tmp-name)
+ (should (string-equal (buffer-string) "ffoooo"))
+ (should (= point (point))))
;; Insert partly.
- (insert-file-contents tmp-name nil 1 3)
- (should (string-equal (buffer-string) "oofoofoo"))
+ (let ((point (point)))
+ (insert-file-contents tmp-name nil 1 3)
+ (should (string-equal (buffer-string) "foofoooo"))
+ (should (= point (point))))
;; Replace.
- (insert-file-contents tmp-name nil nil nil 'replace)
- (should (string-equal (buffer-string) "foo"))
+ (let ((point (point)))
+ (insert-file-contents tmp-name nil nil nil 'replace)
+ (should (string-equal (buffer-string) "foo"))
+ (should (= point (point))))
;; Error case.
(delete-file tmp-name)
(should-error
@@ -2380,7 +2429,7 @@ This checks also `file-name-as-directory', `file-name-directory',
;; Check message.
;; Macro `ert-with-message-capture' was introduced in Emacs 26.1.
(with-no-warnings (when (symbol-plist 'ert-with-message-capture)
- (let ((tramp-message-show-message t))
+ (let (inhibit-message)
(dolist
(noninteractive (unless (tramp--test-ange-ftp-p) '(nil t)))
(dolist (visit '(nil t "string" no-message))
@@ -2406,7 +2455,7 @@ This checks also `file-name-as-directory', `file-name-directory',
(should-error
(cl-letf (((symbol-function #'y-or-n-p) #'ignore)
;; Ange-FTP.
- ((symbol-function 'yes-or-no-p) 'ignore))
+ ((symbol-function #'yes-or-no-p) #'ignore))
(write-region "foo" nil tmp-name nil nil nil 'mustbenew))
:type 'file-already-exists)
(should-error
@@ -2733,7 +2782,53 @@ This tests also `file-directory-p' and `file-accessible-directory-p'."
(delete-directory tmp-name1)
:type 'file-error)
(delete-directory tmp-name1 'recursive)
- (should-not (file-directory-p tmp-name1)))))
+ (should-not (file-directory-p tmp-name1))
+
+ ;; Trashing directories works only since Emacs 27.1. It doesn't
+ ;; work for crypted remote directories and for ange-ftp.
+ (when (and (not (tramp--test-crypt-p)) (not (tramp--test-ftp-p))
+ (tramp--test-emacs27-p))
+ (let ((trash-directory (tramp--test-make-temp-name 'local quoted))
+ (delete-by-moving-to-trash t))
+ (make-directory trash-directory)
+ ;; Delete empty directory.
+ (make-directory tmp-name1)
+ (should (file-directory-p tmp-name1))
+ (delete-directory tmp-name1 nil 'trash)
+ (should-not (file-directory-p tmp-name1))
+ (should
+ (file-exists-p
+ (expand-file-name
+ (file-name-nondirectory tmp-name1) trash-directory)))
+ (delete-directory trash-directory 'recursive)
+ (should-not (file-exists-p trash-directory))
+ ;; Delete non-empty directory.
+ (make-directory tmp-name1)
+ (should (file-directory-p tmp-name1))
+ (write-region "foo" nil (expand-file-name "bla" tmp-name1))
+ (should (file-exists-p (expand-file-name "bla" tmp-name1)))
+ (make-directory tmp-name2)
+ (should (file-directory-p tmp-name2))
+ (write-region "foo" nil (expand-file-name "bla" tmp-name2))
+ (should (file-exists-p (expand-file-name "bla" tmp-name2)))
+ (should-error
+ (delete-directory tmp-name1 nil 'trash)
+ ;; tramp-rclone.el calls the local `delete-directory'.
+ ;; This raises another error.
+ :type (if (tramp--test-rclone-p) 'error 'file-error))
+ (delete-directory tmp-name1 'recursive 'trash)
+ (should-not (file-directory-p tmp-name1))
+ (should
+ (file-exists-p
+ (format
+ "%s/%s/bla" trash-directory (file-name-nondirectory tmp-name1))))
+ (should
+ (file-exists-p
+ (format
+ "%s/%s/%s/bla" trash-directory (file-name-nondirectory tmp-name1)
+ (file-name-nondirectory tmp-name2))))
+ (delete-directory trash-directory 'recursive)
+ (should-not (file-exists-p trash-directory)))))))
(ert-deftest tramp-test15-copy-directory ()
"Check `copy-directory'."
@@ -2833,7 +2928,15 @@ This tests also `file-directory-p' and `file-accessible-directory-p'."
'("bla" "foo")))
(should (equal (directory-files
tmp-name1 'full directory-files-no-dot-files-regexp)
- `(,tmp-name2 ,tmp-name3))))
+ `(,tmp-name2 ,tmp-name3)))
+ ;; Check the COUNT arg. It exists since Emacs 28.
+ (when (tramp--test-emacs28-p)
+ (with-no-warnings
+ (should
+ (equal
+ (directory-files
+ tmp-name1 nil directory-files-no-dot-files-regexp nil 1)
+ '("bla"))))))
;; Cleanup.
(ignore-errors (delete-directory tmp-name1 'recursive))))))
@@ -2910,6 +3013,9 @@ This tests also `file-directory-p' and `file-accessible-directory-p'."
;; (this is performed by `dired'). If FULL is nil, it shows just
;; one file. So we refrain from testing.
(skip-unless (not (tramp--test-ange-ftp-p)))
+ ;; `insert-directory' of crypted remote directories works only since
+ ;; Emacs 27.1.
+ (skip-unless (or (not (tramp--test-crypt-p)) (tramp--test-emacs27-p)))
(dolist (quoted (if (tramp--test-expensive-test) '(nil t) '(nil)))
(let* ((tmp-name1
@@ -2980,6 +3086,8 @@ This tests also `file-directory-p' and `file-accessible-directory-p'."
(skip-unless (tramp--test-enabled))
(skip-unless (tramp--test-sh-p))
(skip-unless (not (tramp--test-rsync-p)))
+ ;; Wildcards are not supported in tramp-crypt.el.
+ (skip-unless (not (tramp--test-crypt-p)))
;; Since Emacs 26.1.
(skip-unless (fboundp 'insert-directory-wildcard-in-dir-p))
@@ -3129,8 +3237,7 @@ This tests also `access-file', `file-readable-p',
(setq test-file-ownership-preserved-p
(= (tramp-compat-file-attribute-group-id
(file-attributes tmp-name1))
- (tramp-get-remote-gid
- (tramp-dissect-file-name tmp-name1) 'integer)))
+ (tramp-get-remote-gid tramp-test-vec 'integer)))
(delete-file tmp-name1))
(should-error
@@ -3347,7 +3454,14 @@ They might differ only in time attributes or directory size."
(file-attributes (car elt)) (cdr elt))))
(setq attr (directory-files-and-attributes tmp-name2 nil "\\`b"))
- (should (equal (mapcar #'car attr) '("bar" "boz"))))
+ (should (equal (mapcar #'car attr) '("bar" "boz")))
+
+ ;; Check the COUNT arg. It exists since Emacs 28.
+ (when (tramp--test-emacs28-p)
+ (with-no-warnings
+ (setq attr (directory-files-and-attributes
+ tmp-name2 nil "\\`b" nil nil 1))
+ (should (equal (mapcar #'car attr) '("bar"))))))
;; Cleanup.
(ignore-errors (delete-directory tmp-name1 'recursive))))))
@@ -3365,25 +3479,80 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'."
"ftp" (file-remote-p tramp-test-temporary-file-directory 'method)))))
(dolist (quoted (if (tramp--test-expensive-test) '(nil t) '(nil)))
- (let ((tmp-name (tramp--test-make-temp-name nil quoted)))
+ (let ((tmp-name1 (tramp--test-make-temp-name nil quoted))
+ (tmp-name2 (tramp--test-make-temp-name nil quoted)))
+
(unwind-protect
(progn
- (write-region "foo" nil tmp-name)
- (should (file-exists-p tmp-name))
- (set-file-modes tmp-name #o777)
- (should (= (file-modes tmp-name) #o777))
- (should (file-executable-p tmp-name))
- (should (file-writable-p tmp-name))
- (set-file-modes tmp-name #o444)
- (should (= (file-modes tmp-name) #o444))
- (should-not (file-executable-p tmp-name))
+ (write-region "foo" nil tmp-name1)
+ (should (file-exists-p tmp-name1))
+ (set-file-modes tmp-name1 #o777)
+ (should (= (file-modes tmp-name1) #o777))
+ (should (file-executable-p tmp-name1))
+ (should (file-writable-p tmp-name1))
+ (set-file-modes tmp-name1 #o444)
+ (should (= (file-modes tmp-name1) #o444))
+ (should-not (file-executable-p tmp-name1))
;; A file is always writable for user "root".
(unless (zerop (tramp-compat-file-attribute-user-id
- (file-attributes tmp-name)))
- (should-not (file-writable-p tmp-name))))
+ (file-attributes tmp-name1)))
+ (should-not (file-writable-p tmp-name1)))
+ ;; Check the NOFOLLOW arg. It exists since Emacs 28. For
+ ;; regular files, there shouldn't be a difference.
+ (when (tramp--test-emacs28-p)
+ (with-no-warnings
+ (set-file-modes tmp-name1 #o222 'nofollow)
+ (should (= (file-modes tmp-name1 'nofollow) #o222)))))
;; Cleanup.
- (ignore-errors (delete-file tmp-name))))))
+ (ignore-errors (delete-file tmp-name1)))
+
+ ;; Check the NOFOLLOW arg. It exists since Emacs 28. It is
+ ;; implemented for tramp-gvfs.el and tramp-sh.el. However,
+ ;; tramp-gvfs,el does not support creating symbolic links. And
+ ;; in tramp-sh.el, we must ensure that the remote chmod command
+ ;; supports the "-h" argument.
+ (when (and (tramp--test-emacs28-p) (tramp--test-sh-p)
+ (tramp-get-remote-chmod-h tramp-test-vec))
+ (unwind-protect
+ (with-no-warnings
+ (write-region "foo" nil tmp-name1)
+ (should (file-exists-p tmp-name1))
+ (make-symbolic-link tmp-name1 tmp-name2)
+ (should
+ (string-equal
+ (funcall
+ (if quoted #'tramp-compat-file-name-unquote #'identity)
+ (file-remote-p tmp-name1 'localname))
+ (file-symlink-p tmp-name2)))
+ ;; Both report the modes of `tmp-name1'.
+ (should
+ (= (file-modes tmp-name1) (file-modes tmp-name2)))
+ ;; `tmp-name1' is a regular file. NOFOLLOW doesn't matter.
+ (should
+ (= (file-modes tmp-name1) (file-modes tmp-name1 'nofollow)))
+ ;; `tmp-name2' is a symbolic link. It has different permissions.
+ (should-not
+ (= (file-modes tmp-name2) (file-modes tmp-name2 'nofollow)))
+ (should-not
+ (= (file-modes tmp-name1 'nofollow)
+ (file-modes tmp-name2 'nofollow)))
+ ;; Change permissions.
+ (set-file-modes tmp-name1 #o200)
+ (set-file-modes tmp-name2 #o200)
+ (should
+ (= (file-modes tmp-name1) (file-modes tmp-name2) #o200))
+ ;; Change permissions with NOFOLLOW.
+ (set-file-modes tmp-name1 #o300 'nofollow)
+ (set-file-modes tmp-name2 #o300 'nofollow)
+ (should
+ (= (file-modes tmp-name1 'nofollow)
+ (file-modes tmp-name2 'nofollow)))
+ (should-not (= (file-modes tmp-name1) (file-modes tmp-name2))))
+
+ ;; Cleanup.
+ (ignore-errors (delete-file tmp-name1))
+ (ignore-errors (delete-file tmp-name2)))))))
;; Method "smb" could run into "NT_STATUS_REVISION_MISMATCH" error.
(defmacro tramp--test-ignore-add-name-to-file-error (&rest body)
@@ -3467,7 +3636,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
;; `tmp-name3' is a local file name. Therefore, the link
;; target remains unchanged, even if quoted.
;; `make-symbolic-link' might not be permitted on w32 systems.
- (unless (tramp--test-windows-nt)
+ (unless (tramp--test-windows-nt-p)
(make-symbolic-link tmp-name1 tmp-name3)
(should
(string-equal tmp-name1 (file-symlink-p tmp-name3))))
@@ -3581,7 +3750,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(concat (file-remote-p tmp-name2) penguin)))))
;; `tmp-name3' is a local file name.
;; `make-symbolic-link' might not be permitted on w32 systems.
- (unless (tramp--test-windows-nt)
+ (unless (tramp--test-windows-nt-p)
(make-symbolic-link tmp-name1 tmp-name3)
(should (file-symlink-p tmp-name3))
(should-not (string-equal tmp-name3 (file-truename tmp-name3)))
@@ -3642,7 +3811,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(tramp--test-ignore-make-symbolic-link-error
(make-symbolic-link tmp-name2 tmp-name1)
(should (file-symlink-p tmp-name1))
- (if (tramp-smb-file-name-p tramp-test-temporary-file-directory)
+ (if (tramp--test-smb-p)
;; The symlink command of `smbclient' detects the
;; cycle already.
(should-error
@@ -3705,7 +3874,17 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(should (file-newer-than-file-p tmp-name2 tmp-name1))
;; `tmp-name3' does not exist.
(should (file-newer-than-file-p tmp-name2 tmp-name3))
- (should-not (file-newer-than-file-p tmp-name3 tmp-name1))))
+ (should-not (file-newer-than-file-p tmp-name3 tmp-name1))
+ ;; Check the NOFOLLOW arg. It exists since Emacs 28. For
+ ;; regular files, there shouldn't be a difference.
+ (when (tramp--test-emacs28-p)
+ (with-no-warnings
+ (set-file-times tmp-name1 (seconds-to-time 1) 'nofollow)
+ (should
+ (tramp-compat-time-equal-p
+ (tramp-compat-file-attribute-modification-time
+ (file-attributes tmp-name1))
+ (seconds-to-time 1)))))))
;; Cleanup.
(ignore-errors
@@ -3745,6 +3924,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
"Check that `file-acl' and `set-file-acl' work proper."
(skip-unless (tramp--test-enabled))
(skip-unless (file-acl tramp-test-temporary-file-directory))
+ (skip-unless (not (tramp--test-crypt-p)))
;; `filename-non-special' has been fixed in Emacs 27.1, see Bug#29579.
(dolist (quoted (if (and (tramp--test-expensive-test) (tramp--test-emacs27-p))
@@ -3823,6 +4003,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(skip-unless
(not (equal (file-selinux-context tramp-test-temporary-file-directory)
'(nil nil nil nil))))
+ (skip-unless (not (tramp--test-crypt-p)))
;; `filename-non-special' has been fixed in Emacs 27.1, see Bug#29579.
(dolist (quoted (if (and (tramp--test-expensive-test) (tramp--test-emacs27-p))
@@ -3966,7 +4147,6 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(when (not (memq system-type '(cygwin windows-nt)))
(let ((method (file-remote-p tramp-test-temporary-file-directory 'method))
(host (file-remote-p tramp-test-temporary-file-directory 'host))
- (vec (tramp-dissect-file-name tramp-test-temporary-file-directory))
(orig-syntax tramp-syntax))
(when (and (stringp host) (string-match tramp-host-with-port-regexp host))
(setq host (match-string 1 host)))
@@ -3979,7 +4159,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(tramp-change-syntax syntax)
;; This has cleaned up all connection data, which are used
;; for completion. We must refill the cache.
- (tramp-set-connection-property vec "property" nil)
+ (tramp-set-connection-property tramp-test-vec "property" nil)
(let ;; This is needed for the `simplified' syntax.
((method-marker
@@ -4035,10 +4215,9 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
;; Cleanup.
(tramp-change-syntax orig-syntax))))
- (dolist (n-e '(nil t))
+ (dolist (non-essential '(nil t))
(dolist (quoted (if (tramp--test-expensive-test) '(nil t) '(nil)))
- (let ((non-essential n-e)
- (tmp-name (tramp--test-make-temp-name nil quoted)))
+ (let ((tmp-name (tramp--test-make-temp-name nil quoted)))
(unwind-protect
(progn
@@ -4128,6 +4307,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
:tags '(:expensive-test)
(skip-unless (tramp--test-enabled))
(skip-unless (or (tramp--test-adb-p) (tramp--test-sh-p)))
+ (skip-unless (not (tramp--test-crypt-p)))
(dolist (quoted (if (tramp--test-expensive-test) '(nil t) '(nil)))
(let* ((tmp-name (tramp--test-make-temp-name nil quoted))
@@ -4206,6 +4386,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
:tags '(:expensive-test)
(skip-unless (tramp--test-enabled))
(skip-unless (or (tramp--test-adb-p) (tramp--test-sh-p)))
+ (skip-unless (not (tramp--test-crypt-p)))
(dolist (quoted (if (tramp--test-expensive-test) '(nil t) '(nil)))
(let ((default-directory tramp-test-temporary-file-directory)
@@ -4224,9 +4405,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(with-timeout (10 (tramp--test-timeout-handler))
(while (< (- (point-max) (point-min)) (length "foo"))
(while (accept-process-output proc 0 nil t))))
- ;; We cannot use `string-equal', because tramp-adb.el
- ;; echoes also the sent string.
- (should (string-match "\\`foo" (buffer-string))))
+ (should (string-match "foo" (buffer-string))))
;; Cleanup.
(ignore-errors (delete-process proc)))
@@ -4245,7 +4424,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(with-timeout (10 (tramp--test-timeout-handler))
(while (< (- (point-max) (point-min)) (length "foo"))
(while (accept-process-output proc 0 nil t))))
- (should (string-equal (buffer-string) "foo")))
+ (should (string-match "foo" (buffer-string))))
;; Cleanup.
(ignore-errors
@@ -4267,9 +4446,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(with-timeout (10 (tramp--test-timeout-handler))
(while (< (- (point-max) (point-min)) (length "foo"))
(while (accept-process-output proc 0 nil t))))
- ;; We cannot use `string-equal', because tramp-adb.el
- ;; echoes also the sent string.
- (should (string-match "\\`foo" (buffer-string))))
+ (should (string-match "foo" (buffer-string))))
;; Cleanup.
(ignore-errors (delete-process proc)))
@@ -4277,27 +4454,62 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
;; PTY.
(unwind-protect
(with-temp-buffer
- (if (not (tramp--test-sh-p))
+ ;; It works only for tramp-sh.el, and not direct async processes.
+ (if (or (not (tramp--test-sh-p)) (tramp-direct-async-process-p))
(should-error
(start-file-process "test4" (current-buffer) nil)
:type 'wrong-type-argument)
+
(setq proc (start-file-process "test4" (current-buffer) nil))
(should (processp proc))
(should (equal (process-status proc) 'run))
;; On MS Windows, `process-tty-name' returns nil.
- (unless (tramp--test-windows-nt)
+ (unless (tramp--test-windows-nt-p)
(should (stringp (process-tty-name proc))))))
;; Cleanup.
(ignore-errors (delete-process proc))))))
+(defmacro tramp--test--deftest-direct-async-process
+ (test docstring &optional unstable)
+ "Define ert test `TEST-direct-async' for direct async processes.
+If UNSTABLE is non-nil, the test is tagged as `:unstable'."
+ (declare (indent 1))
+ ;; `make-process' supports file name handlers since Emacs 27.
+ (when (let ((file-name-handler-alist '(("" . (lambda (&rest _) t)))))
+ (ignore-errors (make-process :file-handler t)))
+ `(ert-deftest ,(intern (concat (symbol-name test) "-direct-async")) ()
+ ,docstring
+ :tags (if ,unstable '(:expensive-test :unstable) '(:expensive-test))
+ (skip-unless (tramp--test-enabled))
+ (let ((default-directory tramp-test-temporary-file-directory)
+ (ert-test (ert-get-test ',test))
+ (tramp-connection-properties
+ (cons '(nil "direct-async-process" t)
+ tramp-connection-properties)))
+ (skip-unless (tramp-direct-async-process-p))
+ ;; For whatever reason, it doesn't cooperate with the "mock" method.
+ (skip-unless (not (tramp--test-mock-p)))
+ ;; We do expect an established connection already,
+ ;; `file-truename' does it by side-effect. Suppress
+ ;; `tramp--test-enabled', in order to keep the connection.
+ ;; Suppress "Process ... finished" messages.
+ (cl-letf (((symbol-function #'tramp--test-enabled) (lambda nil t))
+ ((symbol-function #'internal-default-process-sentinel)
+ #'ignore))
+ (file-truename tramp-test-temporary-file-directory)
+ (funcall (ert-test-body ert-test)))))))
+
+(tramp--test--deftest-direct-async-process tramp-test29-start-file-process
+ "Check direct async `start-file-process'.")
+
(ert-deftest tramp-test30-make-process ()
"Check `make-process'."
:tags '(:expensive-test)
(skip-unless (tramp--test-enabled))
(skip-unless (or (tramp--test-adb-p) (tramp--test-sh-p)))
- ;; `make-process' has been inserted in Emacs 25.1. It supports file
- ;; name handlers since Emacs 27.
+ (skip-unless (not (tramp--test-crypt-p)))
+ ;; `make-process' supports file name handlers since Emacs 27.
(skip-unless (tramp--test-emacs27-p))
(dolist (quoted (if (tramp--test-expensive-test) '(nil t) '(nil)))
@@ -4323,9 +4535,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(with-timeout (10 (tramp--test-timeout-handler))
(while (< (- (point-max) (point-min)) (length "foo"))
(while (accept-process-output proc 0 nil t))))
- ;; We cannot use `string-equal', because tramp-adb.el
- ;; echoes also the sent string.
- (should (string-match "\\`foo" (buffer-string))))
+ (should (string-match "foo" (buffer-string))))
;; Cleanup.
(ignore-errors (delete-process proc)))
@@ -4346,7 +4556,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(with-timeout (10 (tramp--test-timeout-handler))
(while (< (- (point-max) (point-min)) (length "foo"))
(while (accept-process-output proc 0 nil t))))
- (should (string-equal (buffer-string) "foo")))
+ (should (string-match "foo" (buffer-string))))
;; Cleanup.
(ignore-errors
@@ -4372,9 +4582,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(with-timeout (10 (tramp--test-timeout-handler))
(while (not (string-match "foo" (buffer-string)))
(while (accept-process-output proc 0 nil t))))
- ;; We cannot use `string-equal', because tramp-adb.el
- ;; echoes also the sent string.
- (should (string-match "\\`foo" (buffer-string))))
+ (should (string-match "foo" (buffer-string))))
;; Cleanup.
(ignore-errors (delete-process proc)))
@@ -4398,75 +4606,75 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
;; Read output.
(with-timeout (10 (tramp--test-timeout-handler))
(while (accept-process-output proc 0 nil t)))
- ;; We cannot use `string-equal', because tramp-adb.el
- ;; echoes also the sent string. And a remote macOS sends
- ;; a slightly modified string. On MS Windows,
- ;; `delete-process' sends an unknown signal.
- (should
- (string-match
- (if (eq system-type 'windows-nt)
- "unknown signal\n\\'" "killed.*\n\\'")
- (buffer-string))))
+ ;; On some MS Windows systems, it returns "unknown signal".
+ (should (string-match "unknown signal\\|killed" (buffer-string))))
;; Cleanup.
(ignore-errors (delete-process proc)))
;; Process with stderr buffer.
- (let ((stderr (generate-new-buffer "*stderr*")))
- (unwind-protect
- (with-temp-buffer
- (setq proc
- (with-no-warnings
- (make-process
- :name "test5" :buffer (current-buffer)
- :command '("cat" "/does-not-exist")
- :stderr stderr
- :file-handler t)))
- (should (processp proc))
- ;; Read stderr.
- (with-timeout (10 (tramp--test-timeout-handler))
- (while (accept-process-output proc 0 nil t)))
- (delete-process proc)
- (with-current-buffer stderr
- (should
- (string-match
- "cat:.* No such file or directory" (buffer-string)))))
+ (unless (tramp-direct-async-process-p)
+ (let ((stderr (generate-new-buffer "*stderr*")))
+ (unwind-protect
+ (with-temp-buffer
+ (setq proc
+ (with-no-warnings
+ (make-process
+ :name "test5" :buffer (current-buffer)
+ :command '("cat" "/does-not-exist")
+ :stderr stderr
+ :file-handler t)))
+ (should (processp proc))
+ ;; Read stderr.
+ (with-timeout (10 (tramp--test-timeout-handler))
+ (while (accept-process-output proc 0 nil t)))
+ (delete-process proc)
+ (with-current-buffer stderr
+ (should
+ (string-match
+ "cat:.* No such file or directory" (buffer-string)))))
- ;; Cleanup.
- (ignore-errors (delete-process proc))
- (ignore-errors (kill-buffer stderr))))
+ ;; Cleanup.
+ (ignore-errors (delete-process proc))
+ (ignore-errors (kill-buffer stderr)))))
;; Process with stderr file.
- (dolist (tmpfile `(,tmp-name1 ,tmp-name2))
- (unwind-protect
- (with-temp-buffer
- (setq proc
- (with-no-warnings
- (make-process
- :name "test6" :buffer (current-buffer)
- :command '("cat" "/does-not-exist")
- :stderr tmpfile
- :file-handler t)))
- (should (processp proc))
- ;; Read stderr.
- (with-timeout (10 (tramp--test-timeout-handler))
- (while (accept-process-output proc nil nil t)))
- (delete-process proc)
+ (unless (tramp-direct-async-process-p)
+ (dolist (tmpfile `(,tmp-name1 ,tmp-name2))
+ (unwind-protect
(with-temp-buffer
- (insert-file-contents tmpfile)
- (should
- (string-match
- "cat:.* No such file or directory" (buffer-string)))))
+ (setq proc
+ (with-no-warnings
+ (make-process
+ :name "test6" :buffer (current-buffer)
+ :command '("cat" "/does-not-exist")
+ :stderr tmpfile
+ :file-handler t)))
+ (should (processp proc))
+ ;; Read stderr.
+ (with-timeout (10 (tramp--test-timeout-handler))
+ (while (accept-process-output proc nil nil t)))
+ (delete-process proc)
+ (with-temp-buffer
+ (insert-file-contents tmpfile)
+ (should
+ (string-match
+ "cat:.* No such file or directory" (buffer-string)))))
- ;; Cleanup.
- (ignore-errors (delete-process proc))
- (ignore-errors (delete-file tmpfile)))))))
+ ;; Cleanup.
+ (ignore-errors (delete-process proc))
+ (ignore-errors (delete-file tmpfile))))))))
+
+(tramp--test--deftest-direct-async-process tramp-test30-make-process
+ "Check direct async `make-process'.")
(ert-deftest tramp-test31-interrupt-process ()
"Check `interrupt-process'."
- :tags '(:expensive-test)
+ :tags (if (getenv "EMACS_EMBA_CI")
+ '(:expensive-test :unstable) '(:expensive-test))
(skip-unless (tramp--test-enabled))
(skip-unless (tramp--test-sh-p))
+ (skip-unless (not (tramp--test-crypt-p)))
;; Since Emacs 26.1.
(skip-unless (boundp 'interrupt-process-functions))
@@ -4503,15 +4711,16 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'."
(command output-buffer &optional error-buffer input)
"Like `async-shell-command', reading the output.
INPUT, if non-nil, is a string sent to the process."
- (async-shell-command command output-buffer error-buffer)
- (let ((proc (get-buffer-process output-buffer))
+ (let ((proc (async-shell-command command output-buffer error-buffer))
(delete-exited-processes t))
- (when (stringp input)
- (process-send-string proc input))
- (with-timeout
- ((if (getenv "EMACS_EMBA_CI") 30 10) (tramp--test-timeout-handler))
- (while (or (accept-process-output proc nil nil t) (process-live-p proc))))
- (accept-process-output proc nil nil t)))
+ (cl-letf (((symbol-function #'shell-command-sentinel) #'ignore))
+ (when (stringp input)
+ (process-send-string proc input))
+ (with-timeout
+ ((if (getenv "EMACS_EMBA_CI") 30 10) (tramp--test-timeout-handler))
+ (while
+ (or (accept-process-output proc nil nil t) (process-live-p proc))))
+ (accept-process-output proc nil nil t))))
(defun tramp--test-shell-command-to-string-asynchronously (command)
"Like `shell-command-to-string', but for asynchronous processes."
@@ -4527,6 +4736,7 @@ INPUT, if non-nil, is a string sent to the process."
;; remote processes in Emacs. That doesn't work for tramp-adb.el.
(skip-unless (or (and (tramp--test-adb-p) (tramp--test-emacs27-p))
(tramp--test-sh-p)))
+ (skip-unless (not (tramp--test-crypt-p)))
(dolist (quoted (if (tramp--test-expensive-test) '(nil t) '(nil)))
(let ((tmp-name (tramp--test-make-temp-name nil quoted))
@@ -4564,19 +4774,20 @@ INPUT, if non-nil, is a string sent to the process."
(ignore-errors (delete-file tmp-name)))
;; Test `{async-}shell-command' with error buffer.
- (let ((stderr (generate-new-buffer "*stderr*")))
- (unwind-protect
- (with-temp-buffer
- (funcall
- this-shell-command
- "echo foo >&2; echo bar" (current-buffer) stderr)
- (should (string-equal "bar\n" (buffer-string)))
- ;; Check stderr.
- (with-current-buffer stderr
- (should (string-equal "foo\n" (buffer-string)))))
+ (unless (tramp-direct-async-process-p)
+ (let ((stderr (generate-new-buffer "*stderr*")))
+ (unwind-protect
+ (with-temp-buffer
+ (funcall
+ this-shell-command
+ "echo foo >&2; echo bar" (current-buffer) stderr)
+ (should (string-equal "bar\n" (buffer-string)))
+ ;; Check stderr.
+ (with-current-buffer stderr
+ (should (string-equal "foo\n" (buffer-string)))))
- ;; Cleanup.
- (ignore-errors (kill-buffer stderr)))))
+ ;; Cleanup.
+ (ignore-errors (kill-buffer stderr))))))
;; Test sending string to `async-shell-command'.
(unwind-protect
@@ -4612,6 +4823,9 @@ INPUT, if non-nil, is a string sent to the process."
(when (natnump cols)
(should (= cols async-shell-command-width))))))
+(tramp--test--deftest-direct-async-process tramp-test32-shell-command
+ "Check direct async `shell-command'." 'unstable)
+
;; This test is inspired by Bug#39067.
(ert-deftest tramp-test32-shell-command-dont-erase-buffer ()
"Check `shell-command-dont-erase-buffer'."
@@ -4619,7 +4833,9 @@ INPUT, if non-nil, is a string sent to the process."
;; this test cannot run properly.
:tags '(:expensive-test :unstable)
(skip-unless (tramp--test-enabled))
+ (skip-unless nil)
(skip-unless (or (tramp--test-adb-p) (tramp--test-sh-p)))
+ (skip-unless (not (tramp--test-crypt-p)))
;; Prior Emacs 27, `shell-command-dont-erase-buffer' wasn't working properly.
(skip-unless (tramp--test-emacs27-p))
@@ -4743,6 +4959,7 @@ INPUT, if non-nil, is a string sent to the process."
:tags '(:expensive-test)
(skip-unless (tramp--test-enabled))
(skip-unless (tramp--test-sh-p))
+ (skip-unless (not (tramp--test-crypt-p)))
(dolist (this-shell-command-to-string
'(;; Synchronously.
@@ -4755,67 +4972,79 @@ INPUT, if non-nil, is a string sent to the process."
(envvar (concat "VAR_" (upcase (md5 (current-time-string)))))
kill-buffer-query-functions)
- (unwind-protect
- ;; Set a value.
- (let ((process-environment
- (cons (concat envvar "=foo") process-environment)))
- ;; Default value.
- (should
- (string-match
- "foo"
- (funcall
- this-shell-command-to-string
- (format "echo -n ${%s:-bla}" envvar))))))
-
- (unwind-protect
- ;; Set the empty value.
- (let ((process-environment
- (cons (concat envvar "=") process-environment)))
- ;; Value is null.
+ ;; Check INSIDE_EMACS.
+ (setenv "INSIDE_EMACS")
+ (should
+ (string-equal
+ (format "%s,tramp:%s\n" emacs-version tramp-version)
+ (funcall this-shell-command-to-string "echo \"${INSIDE_EMACS:-bla}\"")))
+ (let ((process-environment
+ (cons (format "INSIDE_EMACS=%s,foo" emacs-version)
+ process-environment)))
+ (should
+ (string-equal
+ (format "%s,foo,tramp:%s\n" emacs-version tramp-version)
+ (funcall
+ this-shell-command-to-string "echo \"${INSIDE_EMACS:-bla}\""))))
+
+ ;; Set a value.
+ (let ((process-environment
+ (cons (concat envvar "=foo") process-environment)))
+ ;; Default value.
+ (should
+ (string-match
+ "foo"
+ (funcall
+ this-shell-command-to-string
+ (format "echo \"${%s:-bla}\"" envvar)))))
+
+ ;; Set the empty value.
+ (let ((process-environment
+ (cons (concat envvar "=") process-environment)))
+ ;; Value is null.
+ (should
+ (string-match
+ "bla"
+ (funcall
+ this-shell-command-to-string (format "echo \"${%s:-bla}\"" envvar))))
+ ;; Variable is set.
+ (should
+ (string-match
+ (regexp-quote envvar)
+ (funcall this-shell-command-to-string "set"))))
+
+ (unless (tramp-direct-async-process-p)
+ ;; We force a reconnect, in order to have a clean environment.
+ (tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password)
+ ;; Unset the variable.
+ (let ((tramp-remote-process-environment
+ (cons (concat envvar "=foo") tramp-remote-process-environment)))
+ ;; Set the initial value, we want to unset below.
+ (should
+ (string-match
+ "foo"
+ (funcall
+ this-shell-command-to-string
+ (format "echo \"${%s:-bla}\"" envvar))))
+ (let ((process-environment (cons envvar process-environment)))
+ ;; Variable is unset.
(should
(string-match
"bla"
(funcall
this-shell-command-to-string
- (format "echo -n ${%s:-bla}" envvar))))
- ;; Variable is set.
- (should
+ (format "echo \"${%s:-bla}\"" envvar))))
+ ;; Variable is unset.
+ (should-not
(string-match
(regexp-quote envvar)
- (funcall this-shell-command-to-string "set")))))
-
- ;; We force a reconnect, in order to have a clean environment.
- (tramp-cleanup-connection
- (tramp-dissect-file-name tramp-test-temporary-file-directory)
- 'keep-debug 'keep-password)
- (unwind-protect
- ;; Unset the variable.
- (let ((tramp-remote-process-environment
- (cons (concat envvar "=foo")
- tramp-remote-process-environment)))
- ;; Set the initial value, we want to unset below.
- (should
- (string-match
- "foo"
+ ;; We must remove PS1, the output is truncated otherwise.
(funcall
- this-shell-command-to-string
- (format "echo -n ${%s:-bla}" envvar))))
- (let ((process-environment
- (cons envvar process-environment)))
- ;; Variable is unset.
- (should
- (string-match
- "bla"
- (funcall
- this-shell-command-to-string
- (format "echo -n ${%s:-bla}" envvar))))
- ;; Variable is unset.
- (should-not
- (string-match
- (regexp-quote envvar)
- ;; We must remove PS1, the output is truncated otherwise.
- (funcall
- this-shell-command-to-string "printenv | grep -v PS1")))))))))
+ this-shell-command-to-string "printenv | grep -v PS1")))))))))
+
+(tramp--test--deftest-direct-async-process tramp-test33-environment-variables
+ "Check that remote processes set / unset environment variables properly.
+Use direct async.")
;; This test is inspired by Bug#27009.
(ert-deftest tramp-test33-environment-variables-and-port-numbers ()
@@ -4824,6 +5053,7 @@ INPUT, if non-nil, is a string sent to the process."
;; We test it only for the mock-up connection; otherwise there might
;; be problems with the used ports.
(skip-unless (and (eq tramp-syntax 'default) (tramp--test-mock-p)))
+ (skip-unless (not (tramp--test-crypt-p)))
;; We force a reconnect, in order to have a clean environment.
(dolist (dir `(,tramp-test-temporary-file-directory
@@ -4846,7 +5076,7 @@ INPUT, if non-nil, is a string sent to the process."
(should
(string-match
(number-to-string port)
- (shell-command-to-string (format "echo -n $%s" envvar))))))
+ (shell-command-to-string (format "echo $%s" envvar))))))
;; Cleanup.
(dolist (dir '("/mock:localhost#11111:" "/mock:localhost#22222:"))
@@ -4928,6 +5158,7 @@ INPUT, if non-nil, is a string sent to the process."
;; remote processes in Emacs. That doesn't work for tramp-adb.el.
(skip-unless (or (and (tramp--test-adb-p) (tramp--test-emacs27-p))
(tramp--test-sh-p)))
+ (skip-unless (not (tramp--test-crypt-p)))
;; Since Emacs 26.1.
(skip-unless (and (fboundp 'connection-local-set-profile-variables)
(fboundp 'connection-local-set-profiles)))
@@ -4984,6 +5215,7 @@ INPUT, if non-nil, is a string sent to the process."
"Check `exec-path' and `executable-find'."
(skip-unless (tramp--test-enabled))
(skip-unless (or (tramp--test-adb-p) (tramp--test-sh-p)))
+ (skip-unless (not (tramp--test-crypt-p)))
;; Since Emacs 27.1.
(skip-unless (fboundp 'exec-path))
@@ -5027,6 +5259,7 @@ INPUT, if non-nil, is a string sent to the process."
"Check loooong `tramp-remote-path'."
(skip-unless (tramp--test-enabled))
(skip-unless (tramp--test-sh-p))
+ (skip-unless (not (tramp--test-crypt-p)))
;; Since Emacs 27.1.
(skip-unless (fboundp 'exec-path))
@@ -5034,23 +5267,20 @@ INPUT, if non-nil, is a string sent to the process."
(default-directory tramp-test-temporary-file-directory)
(orig-exec-path (with-no-warnings (exec-path)))
(tramp-remote-path tramp-remote-path)
- (orig-tramp-remote-path tramp-remote-path))
+ (orig-tramp-remote-path tramp-remote-path)
+ path)
(unwind-protect
(progn
;; Non existing directories are removed.
(setq tramp-remote-path
(cons (file-remote-p tmp-name 'localname) tramp-remote-path))
- (tramp-cleanup-connection
- (tramp-dissect-file-name tramp-test-temporary-file-directory)
- 'keep-debug 'keep-password)
+ (tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password)
(should (equal (with-no-warnings (exec-path)) orig-exec-path))
(setq tramp-remote-path orig-tramp-remote-path)
;; Double entries are removed.
(setq tramp-remote-path (append '("/" "/") tramp-remote-path))
- (tramp-cleanup-connection
- (tramp-dissect-file-name tramp-test-temporary-file-directory)
- 'keep-debug 'keep-password)
+ (tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password)
(should
(equal (with-no-warnings (exec-path)) (cons "/" orig-exec-path)))
(setq tramp-remote-path orig-tramp-remote-path)
@@ -5062,26 +5292,30 @@ INPUT, if non-nil, is a string sent to the process."
(let ((dir (make-temp-file (file-name-as-directory tmp-name) 'dir)))
(should (file-directory-p dir))
(setq tramp-remote-path
- (cons (file-remote-p dir 'localname) tramp-remote-path)
+ (append
+ tramp-remote-path `(,(file-remote-p dir 'localname)))
orig-exec-path
- (cons (file-remote-p dir 'localname) orig-exec-path))))
- (tramp-cleanup-connection
- (tramp-dissect-file-name tramp-test-temporary-file-directory)
- 'keep-debug 'keep-password)
+ (append
+ (butlast orig-exec-path)
+ `(,(file-remote-p dir 'localname))
+ (last orig-exec-path)))))
+ (tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password)
(should (equal (with-no-warnings (exec-path)) orig-exec-path))
- (should
- (string-equal
- ;; Ignore trailing newline.
- (substring (shell-command-to-string "echo $PATH") nil -1)
+ ;; Ignore trailing newline.
+ (setq path (substring (shell-command-to-string "echo $PATH") nil -1))
+ ;; The shell doesn't handle such long strings.
+ (unless (<= (length path)
+ (tramp-get-connection-property
+ tramp-test-vec "pipe-buf" 4096))
;; The last element of `exec-path' is `exec-directory'.
- (mapconcat #'identity (butlast orig-exec-path) ":")))
+ (should
+ (string-equal
+ path (mapconcat #'identity (butlast orig-exec-path) ":"))))
;; The shell "sh" shall always exist.
(should (apply #'executable-find '("sh" remote))))
;; Cleanup.
- (tramp-cleanup-connection
- (tramp-dissect-file-name tramp-test-temporary-file-directory)
- 'keep-debug 'keep-password)
+ (tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password)
(setq tramp-remote-path orig-tramp-remote-path)
(ignore-errors (delete-directory tmp-name 'recursive)))))
@@ -5090,6 +5324,7 @@ INPUT, if non-nil, is a string sent to the process."
:tags '(:expensive-test)
(skip-unless (tramp--test-enabled))
(skip-unless (tramp--test-sh-p))
+ (skip-unless (not (tramp--test-crypt-p)))
(dolist (quoted (if (tramp--test-expensive-test) '(nil t) '(nil)))
;; We must use `file-truename' for the temporary directory, in
@@ -5118,8 +5353,7 @@ INPUT, if non-nil, is a string sent to the process."
tramp-remote-process-environment))
;; We must force a reconnect, in order to activate $BZR_HOME.
(tramp-cleanup-connection
- (tramp-dissect-file-name tramp-test-temporary-file-directory)
- 'keep-debug 'keep-password)
+ tramp-test-vec 'keep-debug 'keep-password)
'(Bzr))
(t nil))))
;; Suppress nasty messages.
@@ -5145,13 +5379,9 @@ INPUT, if non-nil, is a string sent to the process."
(error (ert-skip "`vc-create-repo' not supported")))
;; The structure of VC-FILESET is not documented. Let's
;; hope it won't change.
- (condition-case nil
- (vc-register
- (list (car vc-handled-backends)
- (list (file-name-nondirectory tmp-name2))))
- ;; `vc-register' has changed its arguments in Emacs
- ;; 25.1. Let's skip it for older Emacsen.
- (error (skip-unless (tramp--test-emacs25-p))))
+ (vc-register
+ (list (car vc-handled-backends)
+ (list (file-name-nondirectory tmp-name2))))
;; vc-git uses an own process sentinel, Tramp's sentinel
;; for flushing the cache isn't used.
(dired-uncache (concat (file-remote-p default-directory) "/"))
@@ -5408,12 +5638,6 @@ INPUT, if non-nil, is a string sent to the process."
(delete-directory tmp-file)
(should-not (file-exists-p tmp-file))))
-(defun tramp--test-emacs25-p ()
- "Check for Emacs version >= 25.1.
-Some semantics has been changed for there, w/o new functions or
-variables, so we check the Emacs version directly."
- (>= emacs-major-version 25))
-
(defun tramp--test-emacs26-p ()
"Check for Emacs version >= 26.1.
Some semantics has been changed for there, w/o new functions or
@@ -5449,6 +5673,10 @@ This does not support some special file names."
(string-equal
"docker" (file-remote-p tramp-test-temporary-file-directory 'method)))
+(defun tramp--test-crypt-p ()
+ "Check, whether the remote directory is crypted"
+ (tramp-crypt-file-name-p tramp-test-temporary-file-directory))
+
(defun tramp--test-ftp-p ()
"Check, whether an FTP-like method is used.
This does not support globbing characters in file names (yet)."
@@ -5504,9 +5732,7 @@ This does not support special file names."
(defun tramp--test-sh-p ()
"Check, whether the remote host runs a based method from tramp-sh.el."
- (eq
- (tramp-find-foreign-file-name-handler tramp-test-temporary-file-directory)
- 'tramp-sh-file-name-handler))
+ (tramp-sh-file-name-handler-p tramp-test-vec))
(defun tramp--test-share-p ()
"Check, whether the method needs a share."
@@ -5519,11 +5745,11 @@ This does not support special file names."
"Check, whether the sudoedit method is used."
(tramp-sudoedit-file-name-p tramp-test-temporary-file-directory))
-(defun tramp--test-windows-nt ()
+(defun tramp--test-windows-nt-p ()
"Check, whether the locale host runs MS Windows."
(eq system-type 'windows-nt))
-(defun tramp--test-windows-nt-and-batch ()
+(defun tramp--test-windows-nt-and-batch-p ()
"Check, whether the locale host runs MS Windows in batch mode.
This does not support special characters."
(and (eq system-type 'windows-nt) noninteractive))
@@ -5540,7 +5766,12 @@ This does not support utf8 based file transfer."
"Check, whether the locale or remote host runs MS Windows.
This requires restrictions of file name syntax."
(or (eq system-type 'windows-nt)
- (tramp-smb-file-name-p tramp-test-temporary-file-directory)))
+ (tramp--test-smb-p)))
+
+(defun tramp--test-smb-p ()
+ "Check, whether the locale or remote host runs MS Windows.
+This requires restrictions of file name syntax."
+ (tramp-smb-file-name-p tramp-test-temporary-file-directory))
(defun tramp--test-check-files (&rest files)
"Run a simple but comprehensive test over every file in FILES."
@@ -5664,8 +5895,7 @@ This requires restrictions of file name syntax."
;; It does not work in the "smb" case, only relative
;; symlinks to existing files are shown there.
(tramp--test-ignore-make-symbolic-link-error
- (unless
- (tramp-smb-file-name-p tramp-test-temporary-file-directory)
+ (unless (tramp--test-smb-p)
(make-symbolic-link file2 file3)
(should (file-symlink-p file3))
(should
@@ -5692,6 +5922,7 @@ This requires restrictions of file name syntax."
;; We do not run on macOS due to encoding problems. See
;; Bug#36940.
(when (and (tramp--test-expensive-test) (tramp--test-sh-p)
+ (not (tramp--test-crypt-p))
(not (eq system-type 'darwin)))
(dolist (elt files)
(let ((envvar (concat "VAR_" (upcase (md5 elt))))
@@ -5825,7 +6056,7 @@ Use the `ls' command."
(skip-unless (tramp--test-enabled))
(skip-unless (tramp--test-sh-p))
(skip-unless (not (tramp--test-rsync-p)))
- (skip-unless (not (tramp--test-windows-nt-and-batch)))
+ (skip-unless (not (tramp--test-windows-nt-and-batch-p)))
(skip-unless (not (tramp--test-windows-nt-and-pscp-psftp-p)))
(let ((tramp-connection-properties
@@ -5859,18 +6090,28 @@ Use the `ls' command."
"银河系漫游指南系列"
"Автостопом по гала́ктике"
;; Use codepoints without a name. See Bug#31272.
- "™›šbung")
+ "™›šbung"
+ ;; Use codepoints from Supplementary Multilingual Plane (U+10000
+ ;; to U+1FFFF).
+ "🌈🍒👋")
(when (tramp--test-expensive-test)
(delete-dups
(mapcar
- ;; Use all available language specific snippets. Filter out
- ;; strings which use unencodable characters.
+ ;; Use all available language specific snippets.
(lambda (x)
(and
(stringp (setq x (eval (get-language-info (car x) 'sample-text))))
- (not (unencodable-char-position
- 0 (length x) file-name-coding-system nil x))
+ ;; Filter out strings which use unencodable characters.
+ (not (and (or (tramp--test-gvfs-p) (tramp--test-smb-p))
+ (unencodable-char-position
+ 0 (length x) file-name-coding-system nil x)))
+ ;; Filter out not displayable characters.
+ (setq x (mapconcat
+ (lambda (y)
+ (and (char-displayable-p y) (char-to-string y)))
+ x ""))
+ (not (string-empty-p x))
;; ?\n and ?/ shouldn't be part of any file name. ?\t,
;; ?. and ?? do not work for "smb" method.
(replace-regexp-in-string "[\t\n/.?]" "" x)))
@@ -5881,9 +6122,10 @@ Use the `ls' command."
(skip-unless (tramp--test-enabled))
(skip-unless (not (tramp--test-docker-p)))
(skip-unless (not (tramp--test-rsync-p)))
- (skip-unless (not (tramp--test-windows-nt-and-batch)))
+ (skip-unless (not (tramp--test-windows-nt-and-batch-p)))
(skip-unless (not (tramp--test-windows-nt-and-pscp-psftp-p)))
(skip-unless (not (tramp--test-ksh-p)))
+ (skip-unless (not (tramp--test-crypt-p)))
(tramp--test-utf8))
@@ -5895,9 +6137,10 @@ Use the `stat' command."
(skip-unless (tramp--test-sh-p))
(skip-unless (not (tramp--test-docker-p)))
(skip-unless (not (tramp--test-rsync-p)))
- (skip-unless (not (tramp--test-windows-nt-and-batch)))
+ (skip-unless (not (tramp--test-windows-nt-and-batch-p)))
(skip-unless (not (tramp--test-windows-nt-and-pscp-psftp-p)))
(skip-unless (not (tramp--test-ksh-p)))
+ (skip-unless (not (tramp--test-crypt-p)))
(with-parsed-tramp-file-name tramp-test-temporary-file-directory nil
(skip-unless (tramp-get-remote-stat v)))
@@ -5916,9 +6159,10 @@ Use the `perl' command."
(skip-unless (tramp--test-sh-p))
(skip-unless (not (tramp--test-docker-p)))
(skip-unless (not (tramp--test-rsync-p)))
- (skip-unless (not (tramp--test-windows-nt-and-batch)))
+ (skip-unless (not (tramp--test-windows-nt-and-batch-p)))
(skip-unless (not (tramp--test-windows-nt-and-pscp-psftp-p)))
(skip-unless (not (tramp--test-ksh-p)))
+ (skip-unless (not (tramp--test-crypt-p)))
(with-parsed-tramp-file-name tramp-test-temporary-file-directory nil
(skip-unless (tramp-get-remote-perl v)))
@@ -5940,9 +6184,10 @@ Use the `ls' command."
(skip-unless (tramp--test-sh-p))
(skip-unless (not (tramp--test-docker-p)))
(skip-unless (not (tramp--test-rsync-p)))
- (skip-unless (not (tramp--test-windows-nt-and-batch)))
+ (skip-unless (not (tramp--test-windows-nt-and-batch-p)))
(skip-unless (not (tramp--test-windows-nt-and-pscp-psftp-p)))
(skip-unless (not (tramp--test-ksh-p)))
+ (skip-unless (not (tramp--test-crypt-p)))
(let ((tramp-connection-properties
(append
@@ -6016,14 +6261,15 @@ This is needed in timer functions as well as process filters and sentinels."
"Check parallel asynchronous requests.
Such requests could arrive from timers, process filters and
process sentinels. They shall not disturb each other."
- ;; The test fails from time to time, w/o a reproducible pattern. So
- ;; we mark it as unstable.
- :tags '(:expensive-test :unstable)
+ :tags (if (getenv "EMACS_EMBA_CI")
+ '(:expensive-test :unstable) '(:expensive-test))
(skip-unless (tramp--test-enabled))
;; Prior Emacs 27, `shell-file-name' was hard coded as "/bin/sh" for
;; remote processes in Emacs. That doesn't work for tramp-adb.el.
(skip-unless (or (and (tramp--test-adb-p) (tramp--test-emacs27-p))
(tramp--test-sh-p)))
+ (skip-unless (not (tramp--test-crypt-p)))
+ (skip-unless (not (tramp--test-docker-p)))
(with-timeout
(tramp--test-asynchronous-requests-timeout (tramp--test-timeout-handler))
@@ -6033,7 +6279,7 @@ process sentinels. They shall not disturb each other."
(shell-file-name (if (tramp--test-adb-p) "/system/bin/sh" "/bin/sh"))
;; It doesn't work on w32 systems.
(watchdog
- (unless (tramp--test-windows-nt)
+ (unless (tramp--test-windows-nt-p)
(start-process-shell-command
"*watchdog*" nil
(format
@@ -6062,10 +6308,10 @@ process sentinels. They shall not disturb each other."
((getenv "EMACS_HYDRA_CI") 10)
(t 1)))
;; We must distinguish due to performance reasons.
- ;; (timer-operation
- ;; (cond
- ;; ((tramp--test-mock-p) #'vc-registered)
- ;; (t #'file-attributes)))
+ (timer-operation
+ (cond
+ ((tramp--test-mock-p) #'vc-registered)
+ (t #'file-attributes)))
;; This is when all timers start. We check inside the
;; timer function, that we don't exceed timeout.
(timer-start (current-time))
@@ -6084,10 +6330,7 @@ process sentinels. They shall not disturb each other."
0 timer-repeat
(lambda ()
(tramp--test-with-proper-process-name-and-buffer
- (get-buffer-process
- (tramp-get-buffer
- (tramp-dissect-file-name
- tramp-test-temporary-file-directory)))
+ (get-buffer-process (tramp-get-buffer tramp-test-vec))
(when (> (- (time-to-seconds) (time-to-seconds timer-start))
tramp--test-asynchronous-requests-timeout)
(tramp--test-timeout-handler))
@@ -6096,10 +6339,15 @@ process sentinels. They shall not disturb each other."
(default-directory tmp-name)
(file
(buffer-name
- (nth (random (length buffers)) buffers))))
+ (nth (random (length buffers)) buffers)))
+ ;; A remote operation in a timer could
+ ;; confuse Tramp heavily. So we ignore this
+ ;; error here.
+ (debug-ignored-errors
+ (cons 'remote-file-error debug-ignored-errors)))
(tramp--test-message
"Start timer %s %s" file (current-time-string))
- ;; (funcall timer-operation file)
+ (funcall timer-operation file)
(tramp--test-message
"Stop timer %s %s" file (current-time-string))
;; Adjust timer if it takes too much time.
@@ -6209,6 +6457,9 @@ process sentinels. They shall not disturb each other."
(ignore-errors (cancel-timer timer))
(ignore-errors (delete-directory tmp-name 'recursive))))))
+;; (tramp--test--deftest-direct-async-process tramp-test43-asynchronous-requests
+;; "Check parallel direct asynchronous requests." 'unstable)
+
;; This test is inspired by Bug#29163.
(ert-deftest tramp-test44-auto-load ()
"Check that Tramp autoloads properly."
@@ -6355,12 +6606,14 @@ Since it unloads Tramp, it shall be the last test to run."
(and (or (and (boundp x) (null (local-variable-if-set-p x)))
(and (functionp x) (null (autoloadp (symbol-function x)))))
(string-match "^tramp" (symbol-name x))
+ ;; `tramp-completion-mode' is autoloaded in Emacs < 28.1.
+ (not (eq 'tramp-completion-mode x))
(not (string-match "^tramp\\(-archive\\)?--?test" (symbol-name x)))
(not (string-match "unload-hook$" (symbol-name x)))
(ert-fail (format "`%s' still bound" x)))))
;; The defstruct `tramp-file-name' and all its internal functions
- ;; shall be purged. `cl--find-class' must be protected in Emacs 24.
- (with-no-warnings (should-not (cl--find-class 'tramp-file-name)))
+ ;; shall be purged.
+ (should-not (cl--find-class 'tramp-file-name))
(mapatoms
(lambda (x)
(and (functionp x)
@@ -6392,17 +6645,19 @@ If INTERACTIVE is non-nil, the tests are run interactively."
;; * file-equal-p (partly done in `tramp-test21-file-links')
;; * file-in-directory-p
;; * file-name-case-insensitive-p
+;; * tramp-get-remote-gid
+;; * tramp-get-remote-uid
;; * tramp-set-file-uid-gid
;; * Work on skipped tests. Make a comment, when it is impossible.
;; * Revisit expensive tests, once problems in `tramp-error' are solved.
-;; * Fix `tramp-test05-expand-file-name-relative' in `expand-file-name'.
;; * Fix `tramp-test06-directory-file-name' for `ftp'.
;; * Investigate, why `tramp-test11-copy-file' and `tramp-test12-rename-file'
;; do not work properly for `nextcloud'.
-;; * Implement `tramp-test31-interrupt-process' for `adb'.
-;; * Fix Bug#16928 in `tramp-test43-asynchronous-requests'. A remote
-;; file name operation cannot run in the timer. Remove `:unstable' tag?
+;; * Implement `tramp-test31-interrupt-process' for `adb' and for
+;; direct async processes.
+;; * Fix `tramp-test44-threads'.
(provide 'tramp-tests)
+
;;; tramp-tests.el ends here
diff --git a/test/lisp/net/webjump-tests.el b/test/lisp/net/webjump-tests.el
new file mode 100644
index 00000000000..f767099925c
--- /dev/null
+++ b/test/lisp/net/webjump-tests.el
@@ -0,0 +1,73 @@
+;;; webjump-tests.el --- Tests for webjump.el -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+;; Author: Simen Heggestøyl <simenheg@gmail.com>
+;; Keywords:
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'ert)
+(require 'webjump)
+
+(ert-deftest webjump-tests-builtin ()
+ (should (equal (webjump-builtin '[name] "gnu.org") "gnu.org")))
+
+(ert-deftest webjump-tests-builtin-check-args ()
+ (should (webjump-builtin-check-args [1 2 3] "Foo" 2))
+ (should-error (webjump-builtin-check-args [1 2 3] "Foo" 3)))
+
+(ert-deftest webjump-tests-mirror-default ()
+ (should (equal (webjump-mirror-default
+ '("https://ftp.gnu.org/pub/gnu/"
+ "https://ftpmirror.gnu.org"))
+ "https://ftp.gnu.org/pub/gnu/")))
+
+(ert-deftest webjump-tests-null-or-blank-string-p ()
+ (should (webjump-null-or-blank-string-p nil))
+ (should (webjump-null-or-blank-string-p ""))
+ (should (webjump-null-or-blank-string-p " "))
+ (should-not (webjump-null-or-blank-string-p " . ")))
+
+(ert-deftest webjump-tests-url-encode ()
+ (should (equal (webjump-url-encode "") ""))
+ (should (equal (webjump-url-encode "a b c") "a+b+c"))
+ (should (equal (webjump-url-encode "foo?") "foo%3F"))
+ (should (equal (webjump-url-encode "/foo\\") "/foo%5C"))
+ (should (equal (webjump-url-encode "f&o") "f%26o")))
+
+(ert-deftest webjump-tests-url-fix ()
+ (should (equal (webjump-url-fix nil) ""))
+ (should (equal (webjump-url-fix "/tmp/") "file:///tmp/"))
+ (should (equal (webjump-url-fix "gnu.org") "http://gnu.org/"))
+ (should (equal (webjump-url-fix "ftp.x.org") "ftp://ftp.x.org/"))
+ (should (equal (webjump-url-fix "https://gnu.org")
+ "https://gnu.org/")))
+
+(ert-deftest webjump-tests-url-fix-trailing-slash ()
+ (should (equal (webjump-url-fix-trailing-slash "https://gnu.org")
+ "https://gnu.org/"))
+ (should (equal (webjump-url-fix-trailing-slash "https://gnu.org/")
+ "https://gnu.org/")))
+
+(provide 'webjump-tests)
+;;; webjump-tests.el ends here
diff --git a/test/lisp/nxml/nxml-mode-tests.el b/test/lisp/nxml/nxml-mode-tests.el
index 61ce6566a73..4baab1f7600 100644
--- a/test/lisp/nxml/nxml-mode-tests.el
+++ b/test/lisp/nxml/nxml-mode-tests.el
@@ -132,5 +132,26 @@
<sub/>
</t>"))))
+(ert-deftest nxml-mode-test-comment-bug-17264 ()
+ "Test for Bug#17264."
+ (with-temp-buffer
+ (nxml-mode)
+ (let ((data "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
+<spocosy version=\"1.0\" responsetime=\"2011-03-15 13:53:12\" exec=\"0.171\">
+ <!--
+ <query-response requestid=\"\" service=\"objectquery\">
+ <sport name=\"Soccer\" enetSportCode=\"s\" del=\"no\" n=\"1\" ut=\"2009-12-29
+ 15:36:24\" id=\"1\">
+ </sport>
+ </query-response>
+ -->
+</spocosy>
+"))
+ (insert data)
+ (goto-char (point-min))
+ (search-forward "<query-response")
+ ;; Inside comment
+ (should (eq (nth 4 (syntax-ppss)) t)))))
+
(provide 'nxml-mode-tests)
;;; nxml-mode-tests.el ends here
diff --git a/test/lisp/nxml/xsd-regexp-tests.el b/test/lisp/nxml/xsd-regexp-tests.el
new file mode 100644
index 00000000000..4dbc8999247
--- /dev/null
+++ b/test/lisp/nxml/xsd-regexp-tests.el
@@ -0,0 +1,30 @@
+;;; xsd-regexp-tests.el --- Test NXML Mode -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2019-2021 Free Software Foundation, Inc.
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(require 'xsd-regexp)
+
+(ert-deftest xsdre-matches ()
+ (should (equal (string-match (xsdre-translate "\\p{Pd}") "a-b") 1))
+ ;; this fails:
+ (should (equal (string-match (xsdre-translate "\\p{P}") "a-b") 1)))
+
+(provide 'xsd-regexp-tests)
+
+;;; xsd-regexp-tests.el ends here
diff --git a/test/lisp/obsolete/cl-tests.el b/test/lisp/obsolete/cl-tests.el
index 91dedaee304..4a5f4f872b6 100644
--- a/test/lisp/obsolete/cl-tests.el
+++ b/test/lisp/obsolete/cl-tests.el
@@ -21,7 +21,8 @@
;;; Code:
-(require 'cl)
+(with-no-warnings
+ (require 'cl))
(require 'ert)
diff --git a/test/lisp/org/org-tests.el b/test/lisp/org/org-tests.el
index 5329a6cec6b..c1985a46a40 100644
--- a/test/lisp/org/org-tests.el
+++ b/test/lisp/org/org-tests.el
@@ -1,4 +1,4 @@
-;;; org-tests.el --- tests for org/org.el
+;;; org-tests.el --- tests for org/org.el -*- lexical-binding:t -*-
;; Copyright (C) 2018-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/password-cache-tests.el b/test/lisp/password-cache-tests.el
index fccff4a325b..11cb65cc163 100644
--- a/test/lisp/password-cache-tests.el
+++ b/test/lisp/password-cache-tests.el
@@ -28,31 +28,31 @@
(ert-deftest password-cache-tests-add-and-remove ()
(let ((password-data (copy-hash-table password-data)))
- (password-cache-add "foo" "bar")
+ (password-cache-add "foo" (copy-sequence "bar"))
(should (eq (password-in-cache-p "foo") t))
(password-cache-remove "foo")
(should (not (password-in-cache-p "foo")))))
(ert-deftest password-cache-tests-read-from-cache ()
(let ((password-data (copy-hash-table password-data)))
- (password-cache-add "foo" "bar")
+ (password-cache-add "foo" (copy-sequence "bar"))
(should (equal (password-read-from-cache "foo") "bar"))
(should (not (password-read-from-cache nil)))))
(ert-deftest password-cache-tests-in-cache-p ()
(let ((password-data (copy-hash-table password-data)))
- (password-cache-add "foo" "bar")
+ (password-cache-add "foo" (copy-sequence "bar"))
(should (password-in-cache-p "foo"))
(should (not (password-read-from-cache nil)))))
(ert-deftest password-cache-tests-read ()
(let ((password-data (copy-hash-table password-data)))
- (password-cache-add "foo" "bar")
+ (password-cache-add "foo" (copy-sequence "bar"))
(should (equal (password-read nil "foo") "bar"))))
(ert-deftest password-cache-tests-reset ()
(let ((password-data (copy-hash-table password-data)))
- (password-cache-add "foo" "bar")
+ (password-cache-add "foo" (copy-sequence "bar"))
(password-reset)
(should (not (password-in-cache-p "foo")))))
@@ -60,14 +60,14 @@
:tags '(:expensive-test)
(let ((password-data (copy-hash-table password-data))
(password-cache-expiry 0.01))
- (password-cache-add "foo" "bar")
+ (password-cache-add "foo" (copy-sequence "bar"))
(sit-for 0.1)
(should (not (password-in-cache-p "foo")))))
(ert-deftest password-cache-tests-no-password-cache ()
(let ((password-data (copy-hash-table password-data))
(password-cache nil))
- (password-cache-add "foo" "bar")
+ (password-cache-add "foo" (copy-sequence "bar"))
(should (not (password-in-cache-p "foo")))
(should (not (password-read-from-cache "foo")))))
diff --git a/test/lisp/pcmpl-linux-resources/fs/ext4/.keep b/test/lisp/pcmpl-linux-resources/fs/ext4/.keep
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/test/lisp/pcmpl-linux-resources/fs/ext4/.keep
diff --git a/test/lisp/pcmpl-linux-resources/mtab b/test/lisp/pcmpl-linux-resources/mtab
new file mode 100644
index 00000000000..ea33abd7b0a
--- /dev/null
+++ b/test/lisp/pcmpl-linux-resources/mtab
@@ -0,0 +1,11 @@
+/dev/sdb1 / ext3 rw,relatime,errors=remount-ro 0 0
+proc /proc proc rw,noexec,nosuid,nodev 0 0
+/sys /sys sysfs rw,noexec,nosuid,nodev 0 0
+varrun /var/run tmpfs rw,noexec,nosuid,nodev,mode=0755 0 0
+varlock /var/lock tmpfs rw,noexec,nosuid,nodev,mode=1777 0 0
+udev /dev tmpfs rw,mode=0755 0 0
+devshm /dev/shm tmpfs rw 0 0
+devpts /dev/pts devpts rw,gid=5,mode=620 0 0
+lrm /lib/modules/2.6.24-16-generic/volatile tmpfs rw 0 0
+securityfs /sys/kernel/security securityfs rw 0 0
+gvfs-fuse-daemon /home/alice/.gvfs fuse.gvfs-fuse-daemon rw,nosuid,nodev,user=alice 0 0
diff --git a/test/lisp/pcmpl-linux-tests.el b/test/lisp/pcmpl-linux-tests.el
new file mode 100644
index 00000000000..1b795ad706e
--- /dev/null
+++ b/test/lisp/pcmpl-linux-tests.el
@@ -0,0 +1,43 @@
+;;; pcmpl-linux-tests.el --- Tests for pcmpl-linux.el -*- lexical-binding: t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+(require 'ert-x)
+(require 'pcmpl-linux)
+
+(ert-deftest pcmpl-linux-test-fs-types ()
+ (let ((pcmpl-linux-fs-modules-path-format (ert-resource-file "fs")))
+ ;; FIXME: Shouldn't return "." and ".."
+ (should (equal (pcmpl-linux-fs-types)
+ '("." ".." "ext4")))))
+
+(ert-deftest pcmpl-linux-test-mounted-directories ()
+ (let ((pcmpl-linux-mtab-file (ert-resource-file "mtab")))
+ (should (equal (pcmpl-linux-mounted-directories)
+ '("/" "/dev" "/dev/pts" "/dev/shm" "/home/alice/.gvfs"
+ "/lib/modules/2.6.24-16-generic/volatile" "/proc" "/sys"
+ "/sys/kernel/security" "/var/lock" "/var/run")))))
+
+(provide 'pcmpl-linux-tests)
+
+;;; pcmpl-linux-tests.el ends here
diff --git a/test/lisp/play/animate-tests.el b/test/lisp/play/animate-tests.el
new file mode 100644
index 00000000000..62527244670
--- /dev/null
+++ b/test/lisp/play/animate-tests.el
@@ -0,0 +1,56 @@
+;;; animate-tests.el --- Tests for animate.el -*- lexical-binding:t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+(require 'animate)
+
+(ert-deftest animate-test-birthday-present ()
+ (unwind-protect
+ (save-window-excursion
+ (cl-letf (((symbol-function 'sit-for) (lambda (_) nil)))
+ (animate-birthday-present "foo")
+ (should (equal (buffer-string)
+ "
+
+
+
+
+
+ Happy Birthday,
+ Foo
+
+
+ You are my sunshine,
+ My only sunshine.
+ I'm awful sad that
+ You've moved away.
+
+ Let's talk together
+ And love more deeply.
+ Please bring back
+ my sunshine
+ to stay!"))))
+ (kill-buffer "*A-Present-for-Foo*")))
+
+(provide 'animate-tests)
+;;; animate-tests.el ends here
diff --git a/test/lisp/play/dissociate-tests.el b/test/lisp/play/dissociate-tests.el
new file mode 100644
index 00000000000..e2f1e03101a
--- /dev/null
+++ b/test/lisp/play/dissociate-tests.el
@@ -0,0 +1,38 @@
+;;; dissociate-tests.el --- Tests for dissociate.el -*- lexical-binding:t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+(require 'dissociate)
+
+(ert-deftest dissociate-tests-dissociated-press ()
+ (cl-letf (((symbol-function 'y-or-n-p) (lambda (_) nil))
+ ((symbol-function 'random) (lambda (_) 10)))
+ (save-window-excursion
+ (with-temp-buffer
+ (insert "Lorem ipsum dolor sit amet")
+ (dissociated-press)
+ (should (string-match-p "dolor sit ametdolor sit amdolor sit amdolor sit am"
+ (buffer-string)))))))
+
+(provide 'dissociate-tests)
+;;; dissociate-tests.el ends here
diff --git a/test/lisp/play/fortune-resources/fortunes b/test/lisp/play/fortune-resources/fortunes
new file mode 100644
index 00000000000..f1ddc512d00
--- /dev/null
+++ b/test/lisp/play/fortune-resources/fortunes
@@ -0,0 +1,11 @@
+Embarrassed
+Manual-Writer
+Accused of
+Communist
+Subversion
+%
+Embarrassingly
+Mundane
+Advertising
+Cuts
+Sales
diff --git a/test/lisp/play/fortune-tests.el b/test/lisp/play/fortune-tests.el
new file mode 100644
index 00000000000..3b85febaf00
--- /dev/null
+++ b/test/lisp/play/fortune-tests.el
@@ -0,0 +1,41 @@
+;;; fortune-tests.el --- Tests for fortune.el -*- lexical-binding: t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+(require 'ert-x)
+(require 'fortune)
+
+(defvar fortune-tests--regexp
+ (rx (| "Embarrassed" "Embarrassingly")))
+
+(ert-deftest test-fortune ()
+ (skip-unless (executable-find "fortune"))
+ (unwind-protect
+ (let ((fortune-file (ert-resource-file "fortunes")))
+ (fortune)
+ (goto-char (point-min))
+ (should (looking-at fortune-tests--regexp)))
+ (kill-buffer fortune-buffer-name)))
+
+(provide 'fortune-tests)
+;;; fortune-tests.el ends here
diff --git a/test/lisp/play/life-tests.el b/test/lisp/play/life-tests.el
new file mode 100644
index 00000000000..cdc507b5767
--- /dev/null
+++ b/test/lisp/play/life-tests.el
@@ -0,0 +1,80 @@
+;;; life-tests.el --- Tests for life.el -*- lexical-binding:t -*-
+
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+;; Author: Stefan Kangas <stefankangas@gmail.com>
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(require 'life)
+
+(ert-deftest test-life ()
+ (let ((life--max-width 5)
+ (life--max-height 3)
+ (life-patterns [(" @ "
+ " @"
+ "@@@")])
+ (generations '("
+
+ @
+ @
+ @@@
+" "
+
+
+ @ @
+ @@
+ @
+" "
+
+
+ @
+ @ @
+ @@
+" "
+
+
+ @
+ @@
+ @@
+" "
+
+
+ @
+ @
+ @@@
+"
+)))
+ (life-setup)
+ ;; Test initial state.
+ (goto-char (point-min))
+ (dolist (generation generations)
+ ;; Hack to test buffer contents without trailing whitespace,
+ ;; while also not modifying the "*Life*" buffer.
+ (let ((str (buffer-string))
+ (delete-trailing-lines t))
+ (with-temp-buffer
+ (insert str)
+ (delete-trailing-whitespace)
+ (should (equal (buffer-string) generation))))
+ (life--tick))))
+
+(provide 'life-tests)
+
+;;; life-tests.el ends here
diff --git a/test/lisp/progmodes/autoconf-tests.el b/test/lisp/progmodes/autoconf-tests.el
new file mode 100644
index 00000000000..3d347feaf65
--- /dev/null
+++ b/test/lisp/progmodes/autoconf-tests.el
@@ -0,0 +1,55 @@
+;;; autoconf-tests.el --- Tests for autoconf.el -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+;; Author: Simen Heggestøyl <simenheg@gmail.com>
+;; Keywords:
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'autoconf)
+(require 'ert)
+
+(ert-deftest autoconf-tests-current-defun-function-define ()
+ (with-temp-buffer
+ (insert "AC_DEFINE(HAVE_RSVG, 1, [Define to 1 if using librsvg.])")
+ (goto-char (point-min))
+ (should-not (autoconf-current-defun-function))
+ (forward-char 10)
+ (should (equal (autoconf-current-defun-function) "HAVE_RSVG"))))
+
+(ert-deftest autoconf-tests-current-defun-function-subst ()
+ (with-temp-buffer
+ (insert "AC_SUBST(srcdir)")
+ (goto-char (point-min))
+ (should-not (autoconf-current-defun-function))
+ (forward-char 9)
+ (should (equal (autoconf-current-defun-function) "srcdir"))))
+
+(ert-deftest autoconf-tests-autoconf-mode-comment-syntax ()
+ (with-temp-buffer
+ (autoconf-mode)
+ (insert "dnl Autoconf script for GNU Emacs")
+ (should (nth 4 (syntax-ppss)))))
+
+(provide 'autoconf-tests)
+;;; autoconf-tests.el ends here
diff --git a/test/lisp/progmodes/cc-mode-tests.el b/test/lisp/progmodes/cc-mode-tests.el
index 41d46913280..a3a8ff208ed 100644
--- a/test/lisp/progmodes/cc-mode-tests.el
+++ b/test/lisp/progmodes/cc-mode-tests.el
@@ -40,7 +40,7 @@
(insert content)
(setq mode nil)
(c-or-c++-mode)
- (unless(eq expected mode)
+ (unless (eq expected mode)
(ert-fail
(format "expected %s but got %s when testing '%s'"
expected mode content)))))
@@ -53,11 +53,18 @@
(funcall do-test (concat " * " content) 'c-mode))
'("using \t namespace \t std;"
"using \t std::string;"
+ "using Foo = Bar;"
"namespace \t {"
"namespace \t foo \t {"
- "class \t Blah_42 \t {"
+ "namespace \t foo::bar \t {"
+ "inline namespace \t foo \t {"
+ "inline namespace \t foo::bar \t {"
"class \t Blah_42 \t \n"
+ "class \t Blah_42;"
+ "class \t Blah_42 \t final {"
+ "struct \t Blah_42 \t final {"
"class \t _42_Blah:public Foo {"
+ "struct \t _42_Blah:public Foo {"
"template \t < class T >"
"template< class T >"
"#include <string>"
@@ -67,6 +74,7 @@
(mapc (lambda (content) (funcall do-test content 'c-mode))
'("struct \t Blah_42 \t {"
"struct template {"
+ "struct Blah;"
"#include <string.h>")))))
(ert-deftest c-mode-macro-comment ()
@@ -78,4 +86,25 @@
(insert macro-string)
(c-mode))))
+(ert-deftest c-lineup-ternary-bodies ()
+ "Test for c-lineup-ternary-bodies function"
+ (with-temp-buffer
+ (c-mode)
+ (let* ((common-prefix "int value = condition ")
+ (expected-column (length common-prefix)))
+ (dolist (test '(("? a : \n b" . nil)
+ ("? a \n ::b" . nil)
+ ("a \n : b" . nil)
+ ("? a \n : b" . t)
+ ("? ::a \n : b" . t)
+ ("? (p ? q : r) \n : b" . t)
+ ("? p ?: q \n : b" . t)
+ ("? p ? : q \n : b" . t)
+ ("? p ? q : r \n : b" . t)))
+ (delete-region (point-min) (point-max))
+ (insert common-prefix (car test))
+ (should (equal
+ (and (cdr test) (vector expected-column))
+ (c-lineup-ternary-bodies '(statement-cont . 1))))))))
+
;;; cc-mode-tests.el ends here
diff --git a/test/lisp/progmodes/compile-tests.el b/test/lisp/progmodes/compile-tests.el
index 807422598e2..da6a1e641c7 100644
--- a/test/lisp/progmodes/compile-tests.el
+++ b/test/lisp/progmodes/compile-tests.el
@@ -35,311 +35,360 @@
;; what's reported in the string. The end column numbers are for
;; the character after, so it matches what's reported in the string.
'(;; absoft
- ("Error on line 3 of t.f: Execution error unclassifiable statement"
+ (absoft
+ "Error on line 3 of t.f: Execution error unclassifiable statement"
1 nil 3 "t.f")
- ("Line 45 of \"foo.c\": bloofle undefined"
+ (absoft "Line 45 of \"foo.c\": bloofle undefined"
1 nil 45 "foo.c")
- ("error on line 19 of fplot.f: spelling error?"
+ (absoft "error on line 19 of fplot.f: spelling error?"
1 nil 19 "fplot.f")
- ("warning on line 17 of fplot.f: data type is undefined for variable d"
+ (absoft
+ "warning on line 17 of fplot.f: data type is undefined for variable d"
1 nil 17 "fplot.f")
;; Ada & Mpatrol
- ("foo.adb:61:11: [...] in call to size declared at foo.ads:11"
+ (gnu "foo.adb:61:11: [...] in call to size declared at foo.ads:11"
1 11 61 "foo.adb")
- ("foo.adb:61:11: [...] in call to size declared at foo.ads:11"
+ (ada "foo.adb:61:11: [...] in call to size declared at foo.ads:11"
52 nil 11 "foo.ads")
- (" 0x8008621 main+16 at error.c:17"
+ (ada " 0x8008621 main+16 at error.c:17"
23 nil 17 "error.c")
;; aix
- ("****** Error number 140 in line 8 of file errors.c ******"
+ (aix "****** Error number 140 in line 8 of file errors.c ******"
25 nil 8 "errors.c")
;; ant
- ("[javac] /src/DataBaseTestCase.java:27: unreported exception ..."
+ (ant "[javac] /src/DataBaseTestCase.java:27: unreported exception ..."
13 nil 27 "/src/DataBaseTestCase.java" 2)
- ("[javac] /src/DataBaseTestCase.java:49: warning: finally clause cannot complete normally"
+ (ant "[javac] /src/DataBaseTestCase.java:49: warning: finally clause cannot complete normally"
13 nil 49 "/src/DataBaseTestCase.java" 1)
- ("[jikes] foo.java:3:5:7:9: blah blah"
+ (ant "[jikes] foo.java:3:5:7:9: blah blah"
14 (5 . 10) (3 . 7) "foo.java" 2)
- ("[javac] c:/cygwin/Test.java:12: error: foo: bar"
+ (ant "[javac] c:/cygwin/Test.java:12: error: foo: bar"
9 nil 12 "c:/cygwin/Test.java" 2)
- ("[javac] c:\\cygwin\\Test.java:87: error: foo: bar"
+ (ant "[javac] c:\\cygwin\\Test.java:87: error: foo: bar"
9 nil 87 "c:\\cygwin\\Test.java" 2)
;; Checkstyle error, but ant reports a warning (note additional
;; severity level after task name)
- ("[checkstyle] [ERROR] /src/Test.java:38: warning: foo"
+ (ant "[checkstyle] [ERROR] /src/Test.java:38: warning: foo"
22 nil 38 "/src/Test.java" 1)
;; bash
- ("a.sh: line 1: ls-l: command not found"
+ (bash "a.sh: line 1: ls-l: command not found"
1 nil 1 "a.sh")
;; borland
- ("Error ping.c 15: Unable to open include file 'sys/types.h'"
+ (borland "Error ping.c 15: Unable to open include file 'sys/types.h'"
1 nil 15 "ping.c")
- ("Warning pong.c 68: Call to function 'func' with no prototype"
+ (borland "Warning pong.c 68: Call to function 'func' with no prototype"
1 nil 68 "pong.c")
- ("Error E2010 ping.c 15: Unable to open include file 'sys/types.h'"
+ (borland "Error E2010 ping.c 15: Unable to open include file 'sys/types.h'"
1 nil 15 "ping.c")
- ("Warning W1022 pong.c 68: Call to function 'func' with no prototype"
+ (borland
+ "Warning W1022 pong.c 68: Call to function 'func' with no prototype"
1 nil 68 "pong.c")
;; caml
- ("File \"foobar.ml\", lines 5-8, characters 20-155: blah blah"
+ (python-tracebacks-and-caml
+ "File \"foobar.ml\", lines 5-8, characters 20-155: blah blah"
1 (20 . 156) (5 . 8) "foobar.ml")
- ("File \"F:\\ocaml\\sorting.ml\", line 65, characters 2-145:\nWarning 26: unused variable equ."
+ (python-tracebacks-and-caml
+ "File \"F:\\ocaml\\sorting.ml\", line 65, characters 2-145:\nWarning 26: unused variable equ."
1 (2 . 146) 65 "F:\\ocaml\\sorting.ml")
- ("File \"/usr/share/gdesklets/display/TargetGauge.py\", line 41, in add_children"
+ (python-tracebacks-and-caml
+ "File \"/usr/share/gdesklets/display/TargetGauge.py\", line 41, in add_children"
1 nil 41 "/usr/share/gdesklets/display/TargetGauge.py")
- ("File \\lib\\python\\Products\\PythonScripts\\PythonScript.py, line 302, in _exec"
+ (python-tracebacks-and-caml
+ "File \\lib\\python\\Products\\PythonScripts\\PythonScript.py, line 302, in _exec"
1 nil 302 "\\lib\\python\\Products\\PythonScripts\\PythonScript.py")
- ("File \"/tmp/foo.py\", line 10"
+ (python-tracebacks-and-caml
+ "File \"/tmp/foo.py\", line 10"
1 nil 10 "/tmp/foo.py")
;; clang-include
- ("In file included from foo.cpp:2:"
+ (clang-include "In file included from foo.cpp:2:"
1 nil 2 "foo.cpp" 0)
;; cmake cmake-info
- ("CMake Error at CMakeLists.txt:23 (hurz):"
+ (cmake "CMake Error at CMakeLists.txt:23 (hurz):"
1 nil 23 "CMakeLists.txt")
- ("CMake Warning at cmake/modules/UseUG.cmake:73 (find_package):"
+ (cmake "CMake Warning at cmake/modules/UseUG.cmake:73 (find_package):"
1 nil 73 "cmake/modules/UseUG.cmake")
- (" cmake/modules/DuneGridMacros.cmake:19 (include)"
+ (cmake-info " cmake/modules/DuneGridMacros.cmake:19 (include)"
1 nil 19 "cmake/modules/DuneGridMacros.cmake")
;; comma
- ("\"foo.f\", line 3: Error: syntax error near end of statement"
+ (comma "\"foo.f\", line 3: Error: syntax error near end of statement"
1 nil 3 "foo.f")
- ("\"vvouch.c\", line 19.5: 1506-046 (S) Syntax error."
+ (comma "\"vvouch.c\", line 19.5: 1506-046 (S) Syntax error."
1 5 19 "vvouch.c")
- ("\"foo.c\", line 32 pos 1; (E) syntax error; unexpected symbol: \"lossage\""
+ (comma "\"foo.c\", line 32 pos 1; (E) syntax error; unexpected symbol: \"lossage\""
1 1 32 "foo.c")
- ("\"foo.adb\", line 2(11): warning: file name does not match ..."
+ (comma "\"foo.adb\", line 2(11): warning: file name does not match ..."
1 11 2 "foo.adb")
- ("\"src/swapping.c\", line 30.34: 1506-342 (W) \"/*\" detected in comment."
+ (comma
+ "\"src/swapping.c\", line 30.34: 1506-342 (W) \"/*\" detected in comment."
1 34 30 "src/swapping.c")
;; cucumber
- ("Scenario: undefined step # features/cucumber.feature:3"
+ (cucumber "Scenario: undefined step # features/cucumber.feature:3"
29 nil 3 "features/cucumber.feature")
- (" /home/gusev/.rvm/foo/bar.rb:500:in `_wrap_assertion'"
+ ;; This rule is actually handled by the `cucumber' pattern but when
+ ;; `omake' is included, then `gnu' matches it first.
+ (gnu " /home/gusev/.rvm/foo/bar.rb:500:in `_wrap_assertion'"
1 nil 500 "/home/gusev/.rvm/foo/bar.rb")
;; edg-1 edg-2
- ("build/intel/debug/../../../struct.cpp(42): error: identifier \"foo\" is undefined"
+ (edg-1 "build/intel/debug/../../../struct.cpp(42): error: identifier \"foo\" is undefined"
1 nil 42 "build/intel/debug/../../../struct.cpp")
- ("build/intel/debug/struct.cpp(44): warning #1011: missing return statement at end of"
+ (edg-1 "build/intel/debug/struct.cpp(44): warning #1011: missing return statement at end of"
1 nil 44 "build/intel/debug/struct.cpp")
- ("build/intel/debug/iptr.h(302): remark #981: operands are evaluated in unspecified order"
+ (edg-1 "build/intel/debug/iptr.h(302): remark #981: operands are evaluated in unspecified order"
1 nil 302 "build/intel/debug/iptr.h")
- (" detected during ... at line 62 of \"build/intel/debug/../../../trace.h\""
+ (edg-2 " detected during ... at line 62 of \"build/intel/debug/../../../trace.h\""
31 nil 62 "build/intel/debug/../../../trace.h")
;; epc
- ("Error 24 at (2:progran.f90) : syntax error"
+ (epc "Error 24 at (2:progran.f90) : syntax error"
1 nil 2 "progran.f90")
;; ftnchek
- (" Dummy arg W in module SUBA line 8 file arrayclash.f is array"
+ (ftnchek " Dummy arg W in module SUBA line 8 file arrayclash.f is array"
32 nil 8 "arrayclash.f")
- (" L4 used at line 55 file test/assign.f; never set"
+ (ftnchek " L4 used at line 55 file test/assign.f; never set"
16 nil 55 "test/assign.f")
- ("Warning near line 10 file arrayclash.f: Module contains no executable"
+ (ftnchek
+ "Warning near line 10 file arrayclash.f: Module contains no executable"
1 nil 10 "arrayclash.f")
- ("Nonportable usage near line 31 col 9 file assign.f: mixed default and explicit"
+ (ftnchek "Nonportable usage near line 31 col 9 file assign.f: mixed default and explicit"
24 9 31 "assign.f")
;; iar
- ("\"foo.c\",3 Error[32]: Error message"
+ (iar "\"foo.c\",3 Error[32]: Error message"
1 nil 3 "foo.c")
- ("\"foo.c\",3 Warning[32]: Error message"
+ (iar "\"foo.c\",3 Warning[32]: Error message"
1 nil 3 "foo.c")
;; ibm
- ("foo.c(2:0) : informational EDC0804: Function foo is not referenced."
+ (ibm "foo.c(2:0) : informational EDC0804: Function foo is not referenced."
1 0 2 "foo.c")
- ("foo.c(3:8) : warning EDC0833: Implicit return statement encountered."
+ (ibm "foo.c(3:8) : warning EDC0833: Implicit return statement encountered."
1 8 3 "foo.c")
- ("foo.c(5:5) : error EDC0350: Syntax error."
+ (ibm "foo.c(5:5) : error EDC0350: Syntax error."
1 5 5 "foo.c")
;; irix
- ("ccom: Error: foo.c, line 2: syntax error"
+ (irix "ccom: Error: foo.c, line 2: syntax error"
1 nil 2 "foo.c")
- ("cc: Severe: /src/Python-2.3.3/Modules/_curses_panel.c, line 17: Cannot find file <panel.h> ..."
+ (irix "cc: Severe: /src/Python-2.3.3/Modules/_curses_panel.c, line 17: Cannot find file <panel.h> ..."
1 nil 17 "/src/Python-2.3.3/Modules/_curses_panel.c")
- ("cc: Info: foo.c, line 27: ..."
+ (irix "cc: Info: foo.c, line 27: ..."
1 nil 27 "foo.c")
- ("cfe: Warning 712: foo.c, line 2: illegal combination of pointer and ..."
+ (irix
+ "cfe: Warning 712: foo.c, line 2: illegal combination of pointer and ..."
1 nil 2 "foo.c")
- ("cfe: Warning 600: xfe.c: 170: Not in a conditional directive while ..."
+ (irix
+ "cfe: Warning 600: xfe.c: 170: Not in a conditional directive while ..."
1 nil 170 "xfe.c")
- ("/usr/lib/cmplrs/cc/cfe: Error: foo.c: 1: blah blah"
+ (irix "/usr/lib/cmplrs/cc/cfe: Error: foo.c: 1: blah blah"
1 nil 1 "foo.c")
- ("/usr/lib/cmplrs/cc/cfe: warning: foo.c: 1: blah blah"
+ (irix "/usr/lib/cmplrs/cc/cfe: warning: foo.c: 1: blah blah"
1 nil 1 "foo.c")
- ("foo bar: baz.f, line 27: ..."
+ (irix "foo bar: baz.f, line 27: ..."
1 nil 27 "baz.f")
;; java
- ("\tat org.foo.ComponentGateway.doGet(ComponentGateway.java:172)"
+ (java "\tat org.foo.ComponentGateway.doGet(ComponentGateway.java:172)"
5 nil 172 "ComponentGateway.java")
- ("\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:740)"
+ (java "\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:740)"
5 nil 740 "HttpServlet.java")
- ("==1332== at 0x4040743C: System::getErrorString() (../src/Lib/System.cpp:217)"
+ (java "==1332== at 0x4040743C: System::getErrorString() (../src/Lib/System.cpp:217)"
13 nil 217 "../src/Lib/System.cpp")
- ("==1332== by 0x8008621: main (vtest.c:180)"
+ (java "==1332== by 0x8008621: main (vtest.c:180)"
13 nil 180 "vtest.c")
+ ;; javac
+ (javac
+ "/src/Test.java:5: ';' expected\n foo foo\n ^\n"
+ 1 16 5 "/src/Test.java" 2)
+ (javac
+ "e:\\src\\Test.java:7: warning: ';' expected\n foo foo\n ^\n"
+ 1 11 7 "e:\\src\\Test.java" 1)
;; jikes-file jikes-line
- ("Found 2 semantic errors compiling \"../javax/swing/BorderFactory.java\":"
+ (jikes-file
+ "Found 2 semantic errors compiling \"../javax/swing/BorderFactory.java\":"
1 nil nil "../javax/swing/BorderFactory.java")
- ("Issued 1 semantic warning compiling \"java/awt/Toolkit.java\":"
+ (jikes-file "Issued 1 semantic warning compiling \"java/awt/Toolkit.java\":"
1 nil nil "java/awt/Toolkit.java")
;; gcc-include
- ("In file included from /usr/include/c++/3.3/backward/warn.h:4,"
+ (gcc-include "In file included from /usr/include/c++/3.3/backward/warn.h:4,"
1 nil 4 "/usr/include/c++/3.3/backward/warn.h")
- (" from /usr/include/c++/3.3/backward/iostream.h:31:0,"
+ (gcc-include
+ " from /usr/include/c++/3.3/backward/iostream.h:31:0,"
1 0 31 "/usr/include/c++/3.3/backward/iostream.h")
- (" from test_clt.cc:1:"
+ (gcc-include " from test_clt.cc:1:"
1 nil 1 "test_clt.cc")
;; gmake
- ("make: *** [Makefile:20: all] Error 2" 12 nil 20 "Makefile" 0)
- ("make[4]: *** [sub/make.mk:19: all] Error 127" 15 nil 19 "sub/make.mk" 0)
- ("gmake[4]: *** [sub/make.mk:19: all] Error 2" 16 nil 19 "sub/make.mk" 0)
- ("gmake-4.3[4]: *** [make.mk:1119: all] Error 2" 20 nil 1119 "make.mk" 0)
- ("Make-4.3: *** [make.INC:1119: dir/all] Error 2" 16 nil 1119 "make.INC" 0)
+ (gmake "make: *** [Makefile:20: all] Error 2" 12 nil 20 "Makefile" 0)
+ (gmake "make[4]: *** [sub/make.mk:19: all] Error 127" 15 nil 19
+ "sub/make.mk" 0)
+ (gmake "gmake[4]: *** [sub/make.mk:19: all] Error 2" 16 nil 19
+ "sub/make.mk" 0)
+ (gmake "gmake-4.3[4]: *** [make.mk:1119: all] Error 2" 20 nil 1119
+ "make.mk" 0)
+ (gmake "Make-4.3: *** [make.INC:1119: dir/all] Error 2" 16 nil 1119
+ "make.INC" 0)
;; gnu
- ("foo.c:8: message" 1 nil 8 "foo.c")
- ("../foo.c:8: W: message" 1 nil 8 "../foo.c")
- ("/tmp/foo.c:8:warning message" 1 nil 8 "/tmp/foo.c")
- ("foo/bar.py:8: FutureWarning message" 1 nil 8 "foo/bar.py")
- ("foo.py:8: RuntimeWarning message" 1 nil 8 "foo.py")
- ("foo.c:8:I: message" 1 nil 8 "foo.c")
- ("foo.c:8.23: note: message" 1 23 8 "foo.c")
- ("foo.c:8.23: info: message" 1 23 8 "foo.c")
- ("foo.c:8:23:information: message" 1 23 8 "foo.c")
- ("foo.c:8.23-45: Informational: message" 1 (23 . 46) (8 . nil) "foo.c")
- ("foo.c:8-23: message" 1 nil (8 . 23) "foo.c")
+ (gnu "foo.c:8: message" 1 nil 8 "foo.c")
+ (gnu "../foo.c:8: W: message" 1 nil 8 "../foo.c")
+ (gnu "/tmp/foo.c:8:warning message" 1 nil 8 "/tmp/foo.c")
+ (gnu "foo/bar.py:8: FutureWarning message" 1 nil 8 "foo/bar.py")
+ (gnu "foo.py:8: RuntimeWarning message" 1 nil 8 "foo.py")
+ (gnu "foo.c:8:I: message" 1 nil 8 "foo.c")
+ (gnu "foo.c:8.23: note: message" 1 23 8 "foo.c")
+ (gnu "foo.c:8.23: info: message" 1 23 8 "foo.c")
+ (gnu "foo.c:8:23:information: message" 1 23 8 "foo.c")
+ (gnu "foo.c:8.23-45: Informational: message" 1 (23 . 46) (8 . nil) "foo.c")
+ (gnu "foo.c:8-23: message" 1 nil (8 . 23) "foo.c")
;; The next one is not in the GNU standards AFAICS.
;; Here we seem to interpret it as LINE1-LINE2.COL2.
- ("foo.c:8-45.3: message" 1 (nil . 4) (8 . 45) "foo.c")
- ("foo.c:8.23-9.1: message" 1 (23 . 2) (8 . 9) "foo.c")
- ("jade:dbcommon.dsl:133:17:E: missing argument for function call"
+ (gnu "foo.c:8-45.3: message" 1 (nil . 4) (8 . 45) "foo.c")
+ (gnu "foo.c:8.23-9.1: message" 1 (23 . 2) (8 . 9) "foo.c")
+ (gnu "jade:dbcommon.dsl:133:17:E: missing argument for function call"
1 17 133 "dbcommon.dsl")
- ("G:/cygwin/dev/build-myproj.xml:54: Compiler Adapter 'javac' can't be found."
+ (gnu "G:/cygwin/dev/build-myproj.xml:54: Compiler Adapter 'javac' can't be found."
1 nil 54 "G:/cygwin/dev/build-myproj.xml")
- ("file:G:/cygwin/dev/build-myproj.xml:54: Compiler Adapter 'javac' can't be found."
+ (gnu "file:G:/cygwin/dev/build-myproj.xml:54: Compiler Adapter 'javac' can't be found."
1 nil 54 "G:/cygwin/dev/build-myproj.xml")
- ("{standard input}:27041: Warning: end of file not at end of a line; newline inserted"
+ (gnu "{standard input}:27041: Warning: end of file not at end of a line; newline inserted"
1 nil 27041 "{standard input}")
- ("boost/container/detail/flat_tree.hpp:589:25: [ skipping 5 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]"
+ (gnu "boost/container/detail/flat_tree.hpp:589:25: [ skipping 5 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]"
1 25 589 "boost/container/detail/flat_tree.hpp" 0)
;; gradle-kotlin
- ("e: /src/Test.kt: (34, 15): foo: bar" 4 15 34 "/src/Test.kt" 2)
- ("w: /src/Test.kt: (11, 98): foo: bar" 4 98 11 "/src/Test.kt" 1)
- ("e: e:/cygwin/src/Test.kt: (34, 15): foo: bar" 4 15 34 "e:/cygwin/src/Test.kt" 2)
- ("w: e:/cygwin/src/Test.kt: (11, 98): foo: bar" 4 98 11 "e:/cygwin/src/Test.kt" 1)
- ("e: e:\\src\\Test.kt: (34, 15): foo: bar" 4 15 34 "e:\\src\\Test.kt" 2)
- ("w: e:\\src\\Test.kt: (11, 98): foo: bar" 4 98 11 "e:\\src\\Test.kt" 1)
+ (gradle-kotlin
+ "e: /src/Test.kt: (34, 15): foo: bar" 4 15 34 "/src/Test.kt" 2)
+ (gradle-kotlin
+ "w: /src/Test.kt: (11, 98): foo: bar" 4 98 11 "/src/Test.kt" 1)
+ (gradle-kotlin
+ "e: e:/cygwin/src/Test.kt: (34, 15): foo: bar"
+ 4 15 34 "e:/cygwin/src/Test.kt" 2)
+ (gradle-kotlin
+ "w: e:/cygwin/src/Test.kt: (11, 98): foo: bar"
+ 4 98 11 "e:/cygwin/src/Test.kt" 1)
+ (gradle-kotlin
+ "e: e:\\src\\Test.kt: (34, 15): foo: bar" 4 15 34 "e:\\src\\Test.kt" 2)
+ (gradle-kotlin
+ "w: e:\\src\\Test.kt: (11, 98): foo: bar" 4 98 11 "e:\\src\\Test.kt" 1)
;; Guile
- ("In foo.scm:\n" 1 nil nil "foo.scm")
- (" 63:4 [call-with-prompt prompt0 ...]" 1 4 63 nil)
- ("1038: 1 [main (\"gud-break.scm\")]" 1 1 1038 nil)
+ (guile-file "In foo.scm:\n" 1 nil nil "foo.scm")
+ (guile-line " 63:4 [call-with-prompt prompt0 ...]" 1 4 63 nil)
+ (guile-line "1038: 1 [main (\"gud-break.scm\")]" 1 1 1038 nil)
;; lcc
- ("E, file.cc(35,52) Illegal operation on pointers" 1 52 35 "file.cc")
- ("W, file.cc(36,52) blah blah" 1 52 36 "file.cc")
+ (lcc "E, file.cc(35,52) Illegal operation on pointers" 1 52 35 "file.cc")
+ (lcc "W, file.cc(36,52) blah blah" 1 52 36 "file.cc")
;; makepp
- ("makepp: Scanning `/foo/bar.c'" 19 nil nil "/foo/bar.c")
- ("makepp: warning: bla bla `/foo/bar.c' and `/foo/bar.h'" 27 nil nil "/foo/bar.c")
- ("makepp: bla bla `/foo/Makeppfile:12' bla" 18 nil 12 "/foo/Makeppfile")
- ("makepp: bla bla `/foo/bar.c' and `/foo/bar.h'" 35 nil nil "/foo/bar.h")
+ (makepp "makepp: Scanning `/foo/bar.c'" 19 nil nil "/foo/bar.c")
+ (makepp "makepp: warning: bla bla `/foo/bar.c' and `/foo/bar.h'"
+ 27 nil nil "/foo/bar.c")
+ (makepp "makepp: bla bla `/foo/Makeppfile:12' bla"
+ 18 nil 12 "/foo/Makeppfile")
+ (nil "makepp: bla bla `/foo/bar.c' and `/foo/bar.h'"
+ 35 nil nil "/foo/bar.h")
;; maven
- ("FooBar.java:[111,53] no interface expected here"
+ (maven "FooBar.java:[111,53] no interface expected here"
1 53 111 "FooBar.java" 2)
- ("[ERROR] /Users/cinsk/hello.java:[651,96] ';' expected"
+ (maven "[ERROR] /Users/cinsk/hello.java:[651,96] ';' expected"
15 96 651 "/Users/cinsk/hello.java" 2) ;Bug#11517.
- ("[WARNING] /foo/bar/Test.java:[27,43] unchecked conversion"
+ (maven "[WARNING] /foo/bar/Test.java:[27,43] unchecked conversion"
11 43 27 "/foo/bar/Test.java" 1) ;Bug#20556
;; mips-1 mips-2
- ("TrimMask (255) in solomon.c may be indistinguishable from TrimMasks (93) in solomo.c due to truncation"
+ (mips-1 "TrimMask (255) in solomon.c may be indistinguishable from TrimMasks (93) in solomo.c due to truncation"
11 nil 255 "solomon.c")
- ("TrimMask (255) in solomon.c may be indistinguishable from TrimMasks (93) in solomo.c due to truncation"
+ (mips-1 "TrimMask (255) in solomon.c may be indistinguishable from TrimMasks (93) in solomo.c due to truncation"
70 nil 93 "solomo.c")
- ("name defined but never used: LinInt in cmap_calc.c(199)"
+ (mips-2 "name defined but never used: LinInt in cmap_calc.c(199)"
40 nil 199 "cmap_calc.c")
;; msft
- ("keyboard handler.c(537) : warning C4005: 'min' : macro redefinition"
+ (msft "keyboard handler.c(537) : warning C4005: 'min' : macro redefinition"
1 nil 537 "keyboard handler.c")
- ("d:\\tmp\\test.c(23) : error C2143: syntax error : missing ';' before 'if'"
+ (msft
+ "d:\\tmp\\test.c(23) : error C2143: syntax error : missing ';' before 'if'"
1 nil 23 "d:\\tmp\\test.c")
- ("d:\\tmp\\test.c(1145) : see declaration of 'nsRefPtr'"
+ (msft "d:\\tmp\\test.c(1145) : see declaration of 'nsRefPtr'"
1 nil 1145 "d:\\tmp\\test.c")
- ("1>test_main.cpp(29): error C2144: syntax error : 'int' should be preceded by ';'"
+ (msft "1>test_main.cpp(29): error C2144: syntax error : 'int' should be preceded by ';'"
3 nil 29 "test_main.cpp")
- ("1>test_main.cpp(29): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int"
+ (msft "1>test_main.cpp(29): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int"
3 nil 29 "test_main.cpp")
+ (msft "C:\\tmp\\test.cpp(101,11): error C4101: 'bias0123': unreferenced local variable [C:\\tmp\\project.vcxproj]"
+ 1 11 101 "C:\\tmp\\test.cpp")
;; watcom
- ("..\\src\\ctrl\\lister.c(109): Error! E1009: Expecting ';' but found '{'"
+ (watcom
+ "..\\src\\ctrl\\lister.c(109): Error! E1009: Expecting ';' but found '{'"
1 nil 109 "..\\src\\ctrl\\lister.c")
- ("..\\src\\ctrl\\lister.c(120): Warning! W201: Unreachable code"
+ (watcom "..\\src\\ctrl\\lister.c(120): Warning! W201: Unreachable code"
1 nil 120 "..\\src\\ctrl\\lister.c")
;; omake
- (" alpha.c:5:15: error: expected ';' after expression"
+ ;; FIXME: This doesn't actually test the omake rule.
+ (gnu " alpha.c:5:15: error: expected ';' after expression"
1 15 5 "alpha.c")
;; oracle
- ("Semantic error at line 528, column 5, file erosacqdb.pc:"
+ (oracle "Semantic error at line 528, column 5, file erosacqdb.pc:"
1 5 528 "erosacqdb.pc")
- ("Error at line 41, column 10 in file /usr/src/sb/ODBI_BHP.hpp"
+ (oracle "Error at line 41, column 10 in file /usr/src/sb/ODBI_BHP.hpp"
1 10 41 "/usr/src/sb/ODBI_BHP.hpp")
- ("PCC-02150: error at line 49, column 27 in file /usr/src/sb/ODBI_dxfgh.pc"
+ (oracle
+ "PCC-02150: error at line 49, column 27 in file /usr/src/sb/ODBI_dxfgh.pc"
1 27 49 "/usr/src/sb/ODBI_dxfgh.pc")
- ("PCC-00003: invalid SQL Identifier at column name in line 12 of file /usr/src/sb/ODBI_BHP.hpp"
+ (oracle "PCC-00003: invalid SQL Identifier at column name in line 12 of file /usr/src/sb/ODBI_BHP.hpp"
1 nil 12 "/usr/src/sb/ODBI_BHP.hpp")
- ("PCC-00004: mismatched IF/ELSE/ENDIF block at line 27 in file /usr/src/sb/ODBI_BHP.hpp"
+ (oracle "PCC-00004: mismatched IF/ELSE/ENDIF block at line 27 in file /usr/src/sb/ODBI_BHP.hpp"
1 nil 27 "/usr/src/sb/ODBI_BHP.hpp")
- ("PCC-02151: line 21 column 40 file /usr/src/sb/ODBI_BHP.hpp:"
+ (oracle "PCC-02151: line 21 column 40 file /usr/src/sb/ODBI_BHP.hpp:"
1 40 21 "/usr/src/sb/ODBI_BHP.hpp")
;; perl
- ("syntax error at automake line 922, near \"':'\""
+ (perl "syntax error at automake line 922, near \"':'\""
14 nil 922 "automake")
- ("Died at test.pl line 27."
+ (perl "Died at test.pl line 27."
6 nil 27 "test.pl")
- ("store::odrecall('File_A', 'x2') called at store.pm line 90"
+ (perl "store::odrecall('File_A', 'x2') called at store.pm line 90"
40 nil 90 "store.pm")
- ("\t(in cleanup) something bad at foo.pl line 3 during global destruction."
+ (perl
+ "\t(in cleanup) something bad at foo.pl line 3 during global destruction."
29 nil 3 "foo.pl")
- ("GLib-GObject-WARNING **: /build/buildd/glib2.0-2.14.5/gobject/gsignal.c:1741: instance `0x8206790' has no handler with id `1234' at t-compilation-perl-gtk.pl line 3."
+ (perl "GLib-GObject-WARNING **: /build/buildd/glib2.0-2.14.5/gobject/gsignal.c:1741: instance `0x8206790' has no handler with id `1234' at t-compilation-perl-gtk.pl line 3."
130 nil 3 "t-compilation-perl-gtk.pl")
;; php
- ("Parse error: parse error, unexpected $ in main.php on line 59"
+ (php "Parse error: parse error, unexpected $ in main.php on line 59"
1 nil 59 "main.php")
- ("Fatal error: Call to undefined function: mysql_pconnect() in db.inc on line 66"
+ (php "Fatal error: Call to undefined function: mysql_pconnect() in db.inc on line 66"
1 nil 66 "db.inc")
- ;; ruby
- ("plain-exception.rb:7:in `fun': unhandled exception"
+ ;; ruby (uses gnu)
+ (gnu "plain-exception.rb:7:in `fun': unhandled exception"
1 nil 7 "plain-exception.rb")
- ("\tfrom plain-exception.rb:3:in `proxy'" 2 nil 3 "plain-exception.rb")
- ("\tfrom plain-exception.rb:12" 2 nil 12 "plain-exception.rb")
+ (gcc-include
+ "\tfrom plain-exception.rb:3:in `proxy'" 2 nil 3 "plain-exception.rb")
+ (gcc-include "\tfrom plain-exception.rb:12" 2 nil 12 "plain-exception.rb")
;; ruby-Test::Unit
;; FIXME
- (" [examples/test-unit.rb:28:in `here_is_a_deep_assert'"
+ (ruby-Test::Unit " [examples/test-unit.rb:28:in `here_is_a_deep_assert'"
5 nil 28 "examples/test-unit.rb")
- (" examples/test-unit.rb:19:in `test_a_deep_assert']:"
+ (ruby-Test::Unit " examples/test-unit.rb:19:in `test_a_deep_assert']:"
6 nil 19 "examples/test-unit.rb")
- ("examples/test-unit.rb:10:in `test_assert_raise'"
+ (gnu "examples/test-unit.rb:10:in `test_assert_raise'"
1 nil 10 "examples/test-unit.rb")
;; rxp
- ("Error: Mismatched end tag: expected </geroup>, got </group>\nin unnamed entity at line 71 char 8 of file:///home/reto/test/group.xml"
+ (rxp "Error: Mismatched end tag: expected </geroup>, got </group>\nin unnamed entity at line 71 char 8 of file:///home/reto/test/group.xml"
1 8 71 "/home/reto/test/group.xml")
- ("Warning: Start tag for undeclared element geroup\nin unnamed entity at line 4 char 8 of file:///home/reto/test/group.xml"
+ (rxp "Warning: Start tag for undeclared element geroup\nin unnamed entity at line 4 char 8 of file:///home/reto/test/group.xml"
1 8 4 "/home/reto/test/group.xml")
+ ;; shellcheck
+ (shellcheck "In autogen.sh line 48:"
+ 1 nil 48 "autogen.sh")
;; sparc-pascal-file sparc-pascal-line sparc-pascal-example
- ("Thu May 14 10:46:12 1992 mom3.p:"
+ (sparc-pascal-file "Thu May 14 10:46:12 1992 mom3.p:"
1 nil nil "mom3.p")
;; sun
- ("cc-1020 CC: REMARK File = CUI_App.h, Line = 735"
+ (sun "cc-1020 CC: REMARK File = CUI_App.h, Line = 735"
13 nil 735 "CUI_App.h")
- ("cc-1070 cc: WARNING File = linkl.c, Line = 38"
+ (sun "cc-1070 cc: WARNING File = linkl.c, Line = 38"
13 nil 38 "linkl.c")
- ("cf90-113 f90comp: ERROR NSE, File = Hoved.f90, Line = 16, Column = 3"
+ (sun "cf90-113 f90comp: ERROR NSE, File = Hoved.f90, Line = 16, Column = 3"
18 3 16 "Hoved.f90")
;; sun-ada
- ("/home3/xdhar/rcds_rc/main.a, line 361, char 6:syntax error: \",\" inserted"
+ (sun-ada "/home3/xdhar/rcds_rc/main.a, line 361, char 6:syntax error: \",\" inserted"
1 6 361 "/home3/xdhar/rcds_rc/main.a")
;; 4bsd
- ("/usr/src/foo/foo.c(8): warning: w may be used before set"
+ (edg-1 "/usr/src/foo/foo.c(8): warning: w may be used before set"
1 nil 8 "/usr/src/foo/foo.c")
- ("/usr/src/foo/foo.c(9): error: w is used before set"
+ (edg-1 "/usr/src/foo/foo.c(9): error: w is used before set"
1 nil 9 "/usr/src/foo/foo.c")
- ("strcmp: variable # of args. llib-lc(359) :: /usr/src/foo/foo.c(8)"
+ (4bsd "strcmp: variable # of args. llib-lc(359) :: /usr/src/foo/foo.c(8)"
44 nil 8 "/usr/src/foo/foo.c")
- ("bloofle defined( /users/wolfgang/foo.c(4) ), but never used"
+ (4bsd "bloofle defined( /users/wolfgang/foo.c(4) ), but never used"
18 nil 4 "/users/wolfgang/foo.c")
;; perl--Pod::Checker
;; FIXME
@@ -347,21 +396,21 @@
;; *** ERROR: =over on line 37 without closing =back at line EOF in file bar.pm
;; *** ERROR: =over on line 1 without closing =back (at head1) at line 3 in file x.pod
;; perl--Test
- ("# Failed test 1 in foo.t at line 6"
+ (perl--Test "# Failed test 1 in foo.t at line 6"
1 nil 6 "foo.t")
;; perl--Test::Harness
- ("NOK 1# Test 1 got: \"1234\" (t/foo.t at line 46)"
+ (perl--Test2 "NOK 1# Test 1 got: \"1234\" (t/foo.t at line 46)"
1 nil 46 "t/foo.t")
;; weblint
- ("index.html (13:1) Unknown element <fdjsk>"
+ (weblint "index.html (13:1) Unknown element <fdjsk>"
1 1 13 "index.html"))
"List of tests for `compilation-error-regexp-alist'.
-Each element has the form (STR POS COLUMN LINE FILENAME [TYPE]),
-where STR is an error string, POS is the position of the error in
-STR, COLUMN and LINE are the reported column and line numbers (or
-nil) for that error, FILENAME is the reported filename, and TYPE
-is 0 for an information message, 1 for a warning, and 2 for an
-error.
+Each element has the form (RULE STR POS COLUMN LINE FILENAME
+[TYPE]), where RULE is the rule (as a symbol), STR is an error
+string, POS is the position of the error in STR, COLUMN and LINE
+are the reported column and line numbers (or nil) for that error,
+FILENAME is the reported filename, and TYPE is 0 for an
+information message, 1 for a warning, and 2 for an error.
LINE can also be of the form (LINE . END-LINE) meaning a range of
lines. COLUMN can also be of the form (COLUMN . END-COLUMN)
@@ -371,11 +420,14 @@ any message type is accepted.")
(defconst compile-tests--grep-regexp-testcases
;; Bug#32051.
- '(("c:/Users/my.name/src/project\\src\\kbhit.hpp\0\ 29:#include <termios.h>"
+ '((nil
+ "c:/Users/my.name/src/project\\src\\kbhit.hpp\0\ 29:#include <termios.h>"
1 nil 29 "c:/Users/my.name/src/project\\src\\kbhit.hpp")
- ("d:/gnu/emacs/branch/src/callproc.c\0\ 214:#ifdef DOS_NT"
+ (nil
+ "d:/gnu/emacs/branch/src/callproc.c\0\ 214:#ifdef DOS_NT"
1 nil 214 "d:/gnu/emacs/branch/src/callproc.c")
- ("/gnu/emacs/branch/src/callproc.c\0\ 214:#ifdef DOS_NT"
+ (nil
+ "/gnu/emacs/branch/src/callproc.c\0\ 214:#ifdef DOS_NT"
1 nil 214 "/gnu/emacs/branch/src/callproc.c"))
"List of tests for `grep-regexp-list'.
The format is the same as `compile-tests--test-regexps-data', but
@@ -384,43 +436,51 @@ with colon.")
(defconst compile-tests--grep-regexp-tricky-testcases
;; Bug#7378.
- '(("./x11-libs---nx/3.4.0:0:C.30253.1289557929.792611.C/nx-3.4.0.exheres-0\0\ 42:some text"
+ '((nil
+ "./x11-libs---nx/3.4.0:0:C.30253.1289557929.792611.C/nx-3.4.0.exheres-0\0\ 42:some text"
1 nil 42 "./x11-libs---nx/3.4.0:0:C.30253.1289557929.792611.C/nx-3.4.0.exheres-0")
- ("2011-08-31_11:57:03_1\0\ 7:Date: Wed, 31 Aug 2011 11:57:03 +0000"
+ (nil
+ "2011-08-31_11:57:03_1\0\ 7:Date: Wed, 31 Aug 2011 11:57:03 +0000"
1 nil 7 "2011-08-31_11:57:03_1"))
"List of tricky tests for `grep-regexp-list'.
Same as `compile-tests--grep-regexp-testcases', but these cases
can only work with the NUL byte to disambiguate colons.")
(defun compile--test-error-line (test)
- (erase-buffer)
- (setq compilation-locs (make-hash-table))
- (insert (car test))
- (compilation-parse-errors (point-min) (point-max))
- (let ((msg (get-text-property (nth 1 test) 'compilation-message)))
- (should msg)
- (let ((loc (compilation--message->loc msg))
- (col (nth 2 test))
- (line (nth 3 test))
- (file (nth 4 test))
- (type (nth 5 test))
- end-col end-line)
- (if (consp col)
- (setq end-col (cdr col) col (car col)))
- (if (consp line)
- (setq end-line (cdr line) line (car line)))
- (should (equal (compilation--loc->col loc) col))
- (should (equal (compilation--loc->line loc) line))
- (when file
- (should (equal (caar (compilation--loc->file-struct loc)) file)))
- (when end-col
- (should (equal (car (cadr (nth 2 (compilation--loc->file-struct loc))))
- end-col)))
- (should (equal (car (nth 2 (compilation--loc->file-struct loc)))
- (or end-line line)))
- (when type
- (should (equal type (compilation--message->type msg)))))
- msg))
+ (ert-info ((format "%S" test) :prefix "testcase: ")
+ (erase-buffer)
+ (setq compilation-locs (make-hash-table))
+ (let ((rule (nth 0 test))
+ (str (nth 1 test))
+ (pos (nth 2 test))
+ (col (nth 3 test))
+ (line (nth 4 test))
+ (file (nth 5 test))
+ (type (nth 6 test)))
+ (insert str)
+ (compilation-parse-errors (point-min) (point-max))
+ (let ((msg (get-text-property pos 'compilation-message)))
+ (should msg)
+ (let ((loc (compilation--message->loc msg))
+ end-col end-line)
+ (if (consp col)
+ (setq end-col (cdr col) col (car col)))
+ (if (consp line)
+ (setq end-line (cdr line) line (car line)))
+ (should (equal (compilation--loc->col loc) col))
+ (should (equal (compilation--loc->line loc) line))
+ (when file
+ (should (equal (caar (compilation--loc->file-struct loc)) file)))
+ (when end-col
+ (should (equal
+ (car (cadr (nth 2 (compilation--loc->file-struct loc))))
+ end-col)))
+ (should (equal (car (nth 2 (compilation--loc->file-struct loc)))
+ (or end-line line)))
+ (when type
+ (should (equal type (compilation--message->type msg))))
+ (should (equal rule (compilation--message->rule msg))))
+ msg))))
(ert-deftest compile-test-error-regexps ()
"Test the `compilation-error-regexp-alist' regexps.
@@ -431,9 +491,9 @@ The test data is in `compile-tests--test-regexps-data'."
(compilation-num-warnings-found 0)
(compilation-num-infos-found 0))
(mapc #'compile--test-error-line compile-tests--test-regexps-data)
- (should (eq compilation-num-errors-found 93))
- (should (eq compilation-num-warnings-found 36))
- (should (eq compilation-num-infos-found 26)))))
+ (should (eq compilation-num-errors-found 96))
+ (should (eq compilation-num-warnings-found 35))
+ (should (eq compilation-num-infos-found 28)))))
(ert-deftest compile-test-grep-regexps ()
"Test the `grep-regexp-alist' regexps.
@@ -444,16 +504,15 @@ The test data is in `compile-tests--grep-regexp-testcases'."
(font-lock-mode -1)
(dolist (testcase compile-tests--grep-regexp-testcases)
(let (msg1 msg2)
- (setq msg1 (ert-info ((format "%S" testcase) :prefix "testcase: ")
- (compile--test-error-line testcase)))
+ (setq msg1 (compile--test-error-line testcase))
;; Make sure replacing the NUL character with a colon still matches.
- (setf (car testcase) (replace-regexp-in-string "\0" ":" (car testcase)))
- (setq msg2 (ert-info ((format "%S" testcase) :prefix "testcase: ")
- (compile--test-error-line testcase)))
+ (let ((testcase2 (copy-sequence testcase)))
+ (setf (nth 1 testcase2)
+ (string-replace "\0" ":" (nth 1 testcase2)))
+ (setq msg2 (compile--test-error-line testcase2)))
(should (equal msg1 msg2))))
(dolist (testcase compile-tests--grep-regexp-tricky-testcases)
- (ert-info ((format "%S" testcase) :prefix "testcase: ")
- (compile--test-error-line testcase)))
+ (compile--test-error-line testcase))
(should (eq compilation-num-errors-found 8))))
;;; compile-tests.el ends here
diff --git a/test/lisp/progmodes/cperl-mode-resources/cperl-bug-19709.pl b/test/lisp/progmodes/cperl-mode-resources/cperl-bug-19709.pl
new file mode 100644
index 00000000000..f7c51a2ce57
--- /dev/null
+++ b/test/lisp/progmodes/cperl-mode-resources/cperl-bug-19709.pl
@@ -0,0 +1,25 @@
+# -------- bug#19709: input --------
+my $a = func1(
+ Module::test()
+ );
+
+my $b = func2(
+ test()
+);
+
+my $c = func3(
+ Module::test(),
+);
+# -------- bug#19709: expected output --------
+my $a = func1(
+ Module::test()
+);
+
+my $b = func2(
+ test()
+);
+
+my $c = func3(
+ Module::test(),
+);
+# -------- bug#19709: end --------
diff --git a/test/lisp/progmodes/cperl-mode-resources/cperl-bug-26850.pl b/test/lisp/progmodes/cperl-mode-resources/cperl-bug-26850.pl
new file mode 100644
index 00000000000..a02ea29fe9d
--- /dev/null
+++ b/test/lisp/progmodes/cperl-mode-resources/cperl-bug-26850.pl
@@ -0,0 +1,16 @@
+sub interesting {
+ $_ = shift;
+ return
+ />Today is .+\'s birthday\.</
+ || / like[ds]? your post in </
+ || /like[ds] your new subscription\. </
+ || / likes? that you're interested in </
+ || /> likes? your comment: /
+ || /&amp;birthdays=.*birthdays?\.<\/a>/;
+}
+
+sub boring {
+ return
+ / likes? your post in </
+ || / likes? that you're interested in </
+}
diff --git a/test/lisp/progmodes/cperl-mode-resources/cperl-bug-30393.pl b/test/lisp/progmodes/cperl-mode-resources/cperl-bug-30393.pl
new file mode 100644
index 00000000000..01db7b5206c
--- /dev/null
+++ b/test/lisp/progmodes/cperl-mode-resources/cperl-bug-30393.pl
@@ -0,0 +1,19 @@
+# -------- bug#30393: input --------
+#
+ my $sql = "insert into jobs (id, priority) values (1, 2);";
+ my $sth = $dbh->prepare($sql) or die "bother";
+
+ my $sql = "insert into jobs
+(id, priority)
+values (1, 2);";
+ my $sth = $dbh->prepare($sql) or die "bother";
+# -------- bug#30393: expected output --------
+#
+my $sql = "insert into jobs (id, priority) values (1, 2);";
+my $sth = $dbh->prepare($sql) or die "bother";
+
+my $sql = "insert into jobs
+(id, priority)
+values (1, 2);";
+my $sth = $dbh->prepare($sql) or die "bother";
+# -------- bug#30393: end --------
diff --git a/test/lisp/progmodes/cperl-mode-resources/cperl-indent-exp.pl b/test/lisp/progmodes/cperl-mode-resources/cperl-indent-exp.pl
new file mode 100644
index 00000000000..8c1883a10f1
--- /dev/null
+++ b/test/lisp/progmodes/cperl-mode-resources/cperl-indent-exp.pl
@@ -0,0 +1,52 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+use 5.020;
+
+# This file contains test input and expected output for the tests in
+# cperl-mode-tests.el, cperl-mode-test-indent-exp. The code is
+# syntactically valid, but doesn't make much sense.
+
+# -------- for loop: input --------
+for my $foo (@ARGV)
+{
+...;
+}
+# -------- for loop: expected output --------
+for my $foo (@ARGV) {
+ ...;
+}
+# -------- for loop: end --------
+
+# -------- while loop: input --------
+{
+while (1)
+{
+say "boring loop";
+}
+continue
+{
+last;
+}
+}
+# -------- while loop: expected output --------
+{
+ while (1) {
+ say "boring loop";
+ } continue {
+ last;
+ }
+}
+# -------- while loop: end --------
+
+# -------- if-then-else: input --------
+if (my $foo) { bar() } elsif (quux()) { baz() } else { quuux }
+# -------- if-then-else: expected output --------
+if (my $foo) {
+ bar();
+} elsif (quux()) {
+ baz();
+} else {
+ quuux;
+}
+# -------- if-then-else: end --------
diff --git a/test/lisp/progmodes/cperl-mode-resources/cperl-indent-styles.pl b/test/lisp/progmodes/cperl-mode-resources/cperl-indent-styles.pl
new file mode 100644
index 00000000000..371b19b7309
--- /dev/null
+++ b/test/lisp/progmodes/cperl-mode-resources/cperl-indent-styles.pl
@@ -0,0 +1,54 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+use 5.020;
+
+# This file contains test input and expected output for the tests in
+# cperl-mode-tests.el, cperl-mode-test-indent-exp. The code is
+# syntactically valid, but doesn't make much sense.
+
+# -------- PBP indent: input --------
+for my $foo (@ARGV)
+{
+...;
+}
+# -------- PBP indent: expected output --------
+for my $foo (@ARGV) {
+ ...;
+}
+# -------- PBP indent: end --------
+
+# -------- PBP uncuddle else: input --------
+{
+if (1 < 2)
+{
+say "Seems ok";
+} elsif (1 == 2) {
+say "Strange things are happening";
+} else {
+die "This world is backwards";
+}
+}
+# -------- PBP uncuddle else: expected output --------
+{
+ if (1 < 2) {
+ say "Seems ok";
+ }
+ elsif (1 == 2) {
+ say "Strange things are happening";
+ }
+ else {
+ die "This world is backwards";
+ }
+}
+# -------- PBP uncuddle else: end --------
+
+# -------- PBP closing paren offset: input --------
+my $a = func1(
+ Module::test()
+ );
+# -------- PBP closing paren offset: expected output --------
+my $a = func1(
+ Module::test()
+);
+# -------- PBP closing paren offset: end --------
diff --git a/test/lisp/progmodes/cperl-mode-resources/fontify-punctuation-vars.pl b/test/lisp/progmodes/cperl-mode-resources/fontify-punctuation-vars.pl
new file mode 100644
index 00000000000..fa328438cb1
--- /dev/null
+++ b/test/lisp/progmodes/cperl-mode-resources/fontify-punctuation-vars.pl
@@ -0,0 +1,20 @@
+# The following Perl punctiation variables contain characters which
+# are classified as string delimiters in the syntax table. The mode
+# should not be confused by these.
+# The corresponding tests check that two consecutive '#' characters
+# are seen as comments, not as strings.
+my $pre = $`; ## $PREMATCH, use another ` # to balance out
+my $pos = $'; ## $POSTMATCH, use another ' # to balance out
+my $lsp = $"; ## $LIST_SEPARATOR use another " # to balance out
+
+# In the second level, we use the reference constructor \ on these
+# variables. The backslash is an escape character *only* in strings.
+my $ref = \$`; ## \$PREMATCH, use another ` # to balance out
+my $rif = \$'; ## \$POSTMATCH, use another ' # to balance out
+my $raf = \$"; ## \$LIST_SEPARATOR use another " # to balance out
+
+my $opt::s = 0; ## s is no substitution here
+my $opt_s = 0; ## s is no substitution here
+my %opt = (s => 0); ## s is no substitution here
+$opt{s} = 0; ## s is no substitution here
+$opt_s =~ /\s+.../ ## s is no substitution here
diff --git a/test/lisp/progmodes/cperl-mode-tests.el b/test/lisp/progmodes/cperl-mode-tests.el
new file mode 100644
index 00000000000..46e687f14d0
--- /dev/null
+++ b/test/lisp/progmodes/cperl-mode-tests.el
@@ -0,0 +1,323 @@
+;;; cperl-mode-tests --- Test for cperl-mode -*- lexical-binding: t -*-
+
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+;; Author: Harald Jörg <haj@posteo.de>
+;; Maintainer: Harald Jörg
+;; Keywords: internal
+;; Homepage: https://github.com/HaraldJoerg/cperl-mode
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This is a collection of tests for CPerl-mode.
+
+;;; Code:
+
+(defvar cperl-test-mode #'cperl-mode)
+
+(require 'cperl-mode)
+(require 'ert)
+(require 'ert-x)
+
+;;; Utilities
+
+(defun cperl-test-ppss (text regexp)
+ "Return the `syntax-ppss' of the first character matched by REGEXP in TEXT."
+ (interactive)
+ (with-temp-buffer
+ (insert text)
+ (funcall cperl-test-mode)
+ (goto-char (point-min))
+ (re-search-forward regexp)
+ (syntax-ppss)))
+
+(defmacro cperl--run-test-cases (file &rest body)
+ "Run all test cases in FILE with BODY.
+This macro helps with tests which reformat Perl code, e.g. when
+indenting or rearranging flow control. It extracts source code
+snippets and corresponding expected results from a resource file,
+runs BODY on the snippets, and compares the resulting buffer with
+the expected results.
+
+Test cases in FILE are formatted like this:
+
+# -------- NAME: input --------
+Your input to the test case comes here.
+Both input and expected output may span several lines.
+# -------- NAME: expected output --------
+The expected output from running BODY on the input goes here.
+# -------- NAME: end --------
+
+You can have many of these blocks in one test file. You can
+chose a NAME for each block, which is passed to the 'should'
+clause for easy identification of the first test case that
+failed (if any). Text outside these the blocks is ignored by the
+tests, so you can use it to document the test cases if you wish."
+ `(with-temp-buffer
+ (insert-file-contents ,file)
+ (goto-char (point-min))
+ (while (re-search-forward
+ (concat "^# ?-+ \\_<\\(?1:.+?\\)\\_>: input ?-+\n"
+ "\\(?2:\\(?:.*\n\\)+?\\)"
+ "# ?-+ \\1: expected output ?-+\n"
+ "\\(?3:\\(?:.*\n\\)+?\\)"
+ "# ?-+ \\1: end ?-+")
+ nil t)
+ (let ((name (match-string 1))
+ (code (match-string 2))
+ (expected (match-string 3))
+ got)
+ (with-temp-buffer
+ (insert code)
+ (goto-char (point-min))
+ (funcall cperl-test-mode)
+ ,@body
+ (setq expected (concat "test case " name ":\n" expected))
+ (setq got (concat "test case " name ":\n" (buffer-string)))
+ (should (equal got expected)))))))
+
+;;; Indentation tests
+
+(ert-deftest cperl-test-indent-exp ()
+ "Run various tests for `cperl-indent-exp' edge cases.
+These exercise some standard blocks and also the special
+treatment for Perl expressions where a closing paren isn't the
+end of the statement."
+ (skip-unless (eq cperl-test-mode #'cperl-mode))
+ (cperl--run-test-cases
+ (ert-resource-file "cperl-indent-exp.pl")
+ (cperl-indent-exp))) ; here we go!
+
+(ert-deftest cperl-test-indent-styles ()
+ (skip-unless (eq cperl-test-mode #'cperl-mode))
+ (cperl--run-test-cases
+ (ert-resource-file "cperl-indent-styles.pl")
+ (cperl-set-style "PBP")
+ (indent-region (point-min) (point-max)) ; here we go!
+ (cperl-set-style-back)))
+
+;;; Fontification tests
+
+(ert-deftest cperl-test-fontify-punct-vars ()
+ "Test fontification of Perl's punctiation variables.
+Perl has variable names containing unbalanced quotes for the list
+separator $\" and pre- and postmatch $` and $'. A reference to
+these variables, for example \\$\", should not cause the dollar
+to be escaped, which would then start a string beginning with the
+quote character. This used to be broken in cperl-mode at some
+point in the distant past, and is still broken in perl-mode. "
+ (skip-unless (eq cperl-test-mode #'cperl-mode))
+ (let ((file (ert-resource-file "fontify-punctuation-vars.pl")))
+ (with-temp-buffer
+ (insert-file-contents file)
+ (goto-char (point-min))
+ (funcall cperl-test-mode)
+ (while (search-forward "##" nil t)
+ ;; The third element of syntax-ppss is true if in a string,
+ ;; which would indicate bad interpretation of the quote. The
+ ;; fourth element is true if in a comment, which should be the
+ ;; case.
+ (should (equal (nth 3 (syntax-ppss)) nil))
+ (should (equal (nth 4 (syntax-ppss)) t))))))
+
+;;; Tests for issues reported in the Bug Tracker
+
+(defun cperl-test--run-bug-10483 ()
+ "Runs a short program, intended to be under timer scrutiny.
+This function is intended to be used by an Emacs subprocess in
+batch mode. The message buffer is used to report the result of
+running `cperl-indent-exp' for a very simple input. The result
+is expected to be different from the input, to verify that
+indentation actually takes place.."
+ (let ((code "poop ('foo', \n'bar')")) ; see the bug report
+ (message "Test Bug#10483 started")
+ (with-temp-buffer
+ (insert code)
+ (funcall cperl-test-mode)
+ (goto-char (point-min))
+ (search-forward "poop")
+ (cperl-indent-exp)
+ (message "%s" (buffer-string)))))
+
+(ert-deftest cperl-test-bug-10483 ()
+ "Check that indenting certain perl code does not loop forever.
+This verifies that indenting a piece of code that ends in a paren
+without a statement terminator on the same line does not loop
+forever. The test starts an asynchronous Emacs batch process
+under timeout control."
+ :tags '(:expensive-test)
+ (interactive)
+ (skip-unless (not (getenv "EMACS_HYDRA_CI"))) ; FIXME times out
+ (skip-unless (not (< emacs-major-version 28))) ; times out in older Emacsen
+ (let* ((emacs (concat invocation-directory invocation-name))
+ (test-function 'cperl-test--run-bug-10483)
+ (test-function-name (symbol-name test-function))
+ (test-file (symbol-file test-function 'defun))
+ (ran-out-of-time nil)
+ (process-connection-type nil)
+ runner)
+ (with-temp-buffer
+ (with-timeout (2
+ (delete-process runner)
+ (setq ran-out-of-time t))
+ (setq runner (start-process "speedy"
+ (current-buffer)
+ emacs
+ "-batch"
+ "--quick"
+ "--load" test-file
+ "--funcall" test-function-name))
+ (while (accept-process-output runner)))
+ (should (equal ran-out-of-time nil))
+ (goto-char (point-min))
+ ;; just a very simple test for indentation: This should
+ ;; be rather robust with regard to indentation defaults
+ (should (string-match
+ "poop ('foo', \n 'bar')" (buffer-string))))))
+
+(ert-deftest cperl-test-bug-16368 ()
+ "Verify that `cperl-forward-group-in-re' doesn't hide errors."
+ (skip-unless (eq cperl-test-mode #'cperl-mode))
+ (let ((code "/(\\d{4})(?{2}/;") ; the regex from the bug report
+ (result))
+ (with-temp-buffer
+ (insert code)
+ (goto-char 9)
+ (setq result (cperl-forward-group-in-re))
+ (should (equal (car result) 'scan-error))
+ (should (equal (nth 1 result) "Unbalanced parentheses"))
+ (should (= (point) 9)))) ; point remains unchanged on error
+ (let ((code "/(\\d{4})(?{2})/;") ; here all parens are balanced
+ (result))
+ (with-temp-buffer
+ (insert code)
+ (goto-char 9)
+ (setq result (cperl-forward-group-in-re))
+ (should (equal result nil))
+ (should (= (point) 15))))) ; point has skipped the group
+
+(ert-deftest cperl-test-bug-19709 ()
+ "Verify that indentation of closing paren works as intended.
+Note that Perl mode has no setting for close paren offset, per
+documentation it does the right thing anyway."
+ (cperl--run-test-cases
+ (ert-resource-file "cperl-bug-19709.pl")
+ ;; settings from the bug report
+ (setq-local cperl-indent-level 4)
+ (setq-local cperl-indent-parens-as-block t)
+ (setq-local cperl-close-paren-offset -4)
+ ;; same, adapted for per-mode
+ (setq-local perl-indent-level 4)
+ (setq-local perl-indent-parens-as-block t)
+ (while (null (eobp))
+ (cperl-indent-command)
+ (forward-line 1))))
+
+(ert-deftest cperl-test-bug-28650 ()
+ "Verify that regular expressions are recognized after 'return'.
+The test uses the syntax property \"inside a string\" for the
+text in regular expressions, which is non-nil for both cperl-mode
+and perl-mode."
+ (with-temp-buffer
+ (insert-file-contents (ert-resource-file "cperl-bug-26850.pl"))
+ (goto-char (point-min))
+ (re-search-forward "sub interesting {[^}]*}")
+ (should-not (equal (nth 3 (cperl-test-ppss (match-string 0) "Today"))
+ nil))
+ (re-search-forward "sub boring {[^}]*}")
+ (should-not (equal (nth 3 (cperl-test-ppss (match-string 0) "likes\\?"))
+ nil))))
+
+(ert-deftest cperl-test-bug-30393 ()
+ "Verify that indentation is not disturbed by an open paren in col 0.
+Perl is not Lisp: An open paren in column 0 does not start a function."
+ (cperl--run-test-cases
+ (ert-resource-file "cperl-bug-30393.pl")
+ (while (null (eobp))
+ (cperl-indent-command)
+ (forward-line 1))))
+
+(ert-deftest cperl-test-bug-37127 ()
+ "Verify that closing a paren in a regex goes without a message.
+Also check that the message is issued if the regex terminator is
+missing."
+ ;; The actual fix for this bug is in simple.el, which is not
+ ;; backported to older versions of Emacs. Therefore we skip this
+ ;; test if we're running Emacs 27 or older.
+ (skip-unless (< 27 emacs-major-version))
+ ;; Part one: Regex is ok, no messages
+ (ert-with-message-capture collected-messages
+ (with-temp-buffer
+ (insert "$_ =~ /(./;")
+ (funcall cperl-test-mode)
+ (goto-char (point-min))
+ (search-forward ".")
+ (let ((last-command-event ?\))
+ ;; Don't emit "Matches ..." even if not visible (e.g. in batch).
+ (blink-matching-paren 'jump-offscreen))
+ (self-insert-command 1)
+ ;; `self-insert-command' doesn't call `blink-matching-open' in
+ ;; batch mode, so we need to call it explicitly.
+ (blink-matching-open))
+ (syntax-propertize (point-max)))
+ (should (string-equal collected-messages "")))
+ ;; part two: Regex terminator missing -> message
+ (when (eq cperl-test-mode #'cperl-mode)
+ ;; This test is only run in `cperl-mode' because only cperl-mode
+ ;; emits a message to warn about such unclosed REs.
+ (ert-with-message-capture collected-messages
+ (with-temp-buffer
+ (insert "$_ =~ /(..;")
+ (goto-char (point-min))
+ (funcall cperl-test-mode)
+ (search-forward ".")
+ (let ((last-command-event ?\)))
+ (self-insert-command 1))
+ (syntax-propertize (point-max)))
+ (should (string-match "^End of .* string/RE"
+ collected-messages)))))
+
+(ert-deftest cperl-test-bug-42168 ()
+ "Verify that '/' is a division after ++ or --, not a regexp.
+Reported in https://github.com/jrockway/cperl-mode/issues/45.
+If seen as regular expression, then the slash is displayed using
+font-lock-constant-face. If seen as a division, then it doesn't
+have a face property."
+ :tags '(:fontification)
+ ;; The next two Perl expressions have divisions. Perl "punctuation"
+ ;; operators don't get a face.
+ (let ((code "{ $a++ / $b }"))
+ (should (equal (nth 8 (cperl-test-ppss code "/")) nil)))
+ (let ((code "{ $a-- / $b }"))
+ (should (equal (nth 8 (cperl-test-ppss code "/")) nil)))
+ ;; The next two Perl expressions have regular expressions. The
+ ;; delimiter of a RE is fontified with font-lock-constant-face.
+ (let ((code "{ $a+ / $b } # /"))
+ (should (equal (nth 8 (cperl-test-ppss code "/")) 7)))
+ (let ((code "{ $a- / $b } # /"))
+ (should (equal (nth 8 (cperl-test-ppss code "/")) 7))))
+
+(ert-deftest cperl-test-bug-45255 ()
+ "Verify that \"<<>>\" is recognized as not starting a HERE-doc."
+ (let ((code (concat "while (<<>>) {\n"
+ " ...;\n"
+ "}\n")))
+ ;; The yadda-yadda operator should not be in a string.
+ (should (equal (nth 8 (cperl-test-ppss code "\\.")) nil))))
+
+;;; cperl-mode-tests.el ends here
diff --git a/test/lisp/progmodes/elisp-mode-tests.el b/test/lisp/progmodes/elisp-mode-tests.el
index 5181b281bf1..a10d5dab906 100644
--- a/test/lisp/progmodes/elisp-mode-tests.el
+++ b/test/lisp/progmodes/elisp-mode-tests.el
@@ -194,7 +194,7 @@
(dotimes (i 3)
(should
(equal (elisp-mode-tests--face-propertized-string
- (elisp--highlight-function-argument 'foo "(A B C)" (1+ i) "foo: "))
+ (elisp--highlight-function-argument 'foo "(A B C)" (1+ i)))
(propertize (nth i '("A" "B" "C"))
'face 'eldoc-highlight-function-argument)))))
@@ -206,7 +206,7 @@
(cl-flet ((bold-arg (i)
(elisp-mode-tests--face-propertized-string
(elisp--highlight-function-argument
- 'foo "(PROMPT LST &key A B C)" i "foo: "))))
+ 'foo "(PROMPT LST &key A B C)" i))))
(should-not (bold-arg 0))
(progn (forward-sexp) (forward-char))
(should (equal (bold-arg 1) "PROMPT"))
@@ -226,7 +226,7 @@
(cl-flet ((bold-arg (i)
(elisp-mode-tests--face-propertized-string
(elisp--highlight-function-argument
- 'foo "(X &key A B C)" i "foo: "))))
+ 'foo "(X &key A B C)" i))))
(should-not (bold-arg 0))
;; The `:b' specifies positional arg `X'.
(progn (forward-sexp) (forward-char))
@@ -810,5 +810,17 @@ to (xref-elisp-test-descr-to-target xref)."
(insert "?\\N{HEAVY CHECK MARK}")
(should (equal (elisp--preceding-sexp) ?\N{HEAVY CHECK MARK}))))
+(ert-deftest elisp-indent-basic ()
+ (with-temp-buffer
+ (emacs-lisp-mode)
+ (let ((orig "(defun x ()
+ (print (quote ( thingy great
+ stuff)))
+ (print (quote (thingy great
+ stuff))))"))
+ (insert orig)
+ (indent-region (point-min) (point-max))
+ (should (equal (buffer-string) orig)))))
+
(provide 'elisp-mode-tests)
;;; elisp-mode-tests.el ends here
diff --git a/test/lisp/progmodes/etags-tests.el b/test/lisp/progmodes/etags-tests.el
index 4ffa4eb13a2..35a2592e76f 100644
--- a/test/lisp/progmodes/etags-tests.el
+++ b/test/lisp/progmodes/etags-tests.el
@@ -1,4 +1,4 @@
-;;; etags-tests.el --- Test suite for etags.el.
+;;; etags-tests.el --- Test suite for etags.el. -*- lexical-binding:t -*-
;; Copyright (C) 2016-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/progmodes/f90-tests.el b/test/lisp/progmodes/f90-tests.el
index 05d446f8a5b..b3d12229d8f 100644
--- a/test/lisp/progmodes/f90-tests.el
+++ b/test/lisp/progmodes/f90-tests.el
@@ -1,8 +1,9 @@
-;;; f90-tests.el --- tests for progmodes/f90.el
+;;; f90-tests.el --- tests for progmodes/f90.el -*- lexical-binding:t -*-
;; Copyright (C) 2011-2021 Free Software Foundation, Inc.
;; Author: Glenn Morris <rgm@gnu.org>
+;; Maintainer: emacs-devel@gnu.org
;; This file is part of GNU Emacs.
diff --git a/test/lisp/progmodes/gdb-mi-tests.el b/test/lisp/progmodes/gdb-mi-tests.el
new file mode 100644
index 00000000000..ab482214afb
--- /dev/null
+++ b/test/lisp/progmodes/gdb-mi-tests.el
@@ -0,0 +1,46 @@
+;;; gdb-mi-tests.el --- tests for gdb-mi.el -*- lexical-binding: t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+(require 'ert)
+(require 'gdb-mi)
+
+(ert-deftest gdb-mi-parse-value ()
+ ;; Test the GDB/MI result/value parser.
+ (should (equal
+ (gdb-mi--from-string
+ "alpha=\"ab\\ncd\",beta=[\"x\",{gamma=\"y\",delta=[]}]")
+ '((alpha . "ab\ncd")
+ (beta . ("x" ((gamma . "y") (delta . ())))))))
+ (should (equal
+ (gdb-mi--from-string
+ "alpha=\"ab\\ncd\",beta=[\"x\",{gamma=\"y\",delta=[]}]"
+ 'gamma)
+ '((alpha . "ab\ncd")
+ (beta . ("x" ("y" (delta . ())))))))
+
+ (let ((gdb-mi-decode-strings nil))
+ (let ((ref `((alpha . ,(string-to-multibyte "a\303\245b")))))
+ (should (equal (gdb-mi--from-string "alpha=\"a\\303\\245b\"")
+ ref))))
+ (let ((gdb-mi-decode-strings 'utf-8))
+ (should (equal (gdb-mi--from-string "alpha=\"a\\303\\245b\"")
+ '((alpha . "aåb")))))
+ )
+
+(provide 'gdb-mi-tests)
diff --git a/test/lisp/progmodes/glasses-tests.el b/test/lisp/progmodes/glasses-tests.el
new file mode 100644
index 00000000000..633c7bf2dbe
--- /dev/null
+++ b/test/lisp/progmodes/glasses-tests.el
@@ -0,0 +1,101 @@
+;;; glasses-tests.el --- Tests for glasses.el -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+;; Author: Simen Heggestøyl <simenheg@gmail.com>
+;; Keywords:
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'ert)
+(require 'glasses)
+(require 'seq)
+
+(ert-deftest glasses-tests-parenthesis-exception-p ()
+ (with-temp-buffer
+ (insert "public OnClickListener menuListener() {}")
+ (let ((glasses-separate-parentheses-exceptions '("^Listen")))
+ (should-not (glasses-parenthesis-exception-p 1 (point-max)))
+ (should (glasses-parenthesis-exception-p 15 (point-max)))
+ (should-not (glasses-parenthesis-exception-p 24 (point-max)))
+ (should (glasses-parenthesis-exception-p 28 (point-max))))))
+
+(ert-deftest glasses-tests-overlay-p ()
+ (should
+ (glasses-overlay-p (glasses-make-overlay (point-min) (point-max))))
+ (should-not
+ (glasses-overlay-p (make-overlay (point-min) (point-max)))))
+
+(ert-deftest glasses-tests-make-overlay-p ()
+ (let ((o (glasses-make-overlay (point-min) (point-max))))
+ (should (eq (overlay-get o 'category) 'glasses)))
+ (let ((o (glasses-make-overlay (point-min) (point-max) 'foo)))
+ (should (eq (overlay-get o 'category) 'foo))))
+
+(ert-deftest glasses-tests-make-readable ()
+ (with-temp-buffer
+ (insert "pp.setBackgroundResource(R.drawable.button_right);")
+ (glasses-make-readable (point-min) (point-max))
+ (pcase-let ((`(,o1 ,o2 ,o3)
+ (sort (overlays-in (point-min) (point-max))
+ (lambda (o1 o2)
+ (< (overlay-start o1) (overlay-start o2))))))
+ (should (= (overlay-start o1) 7))
+ (should (equal (overlay-get o1 'before-string)
+ glasses-separator))
+ (should (= (overlay-start o2) 17))
+ (should (equal (overlay-get o2 'before-string)
+ glasses-separator))
+ (should (= (overlay-start o3) 25))
+ (should (equal (overlay-get o3 'before-string) " ")))))
+
+(ert-deftest glasses-tests-make-readable-dont-separate-parentheses ()
+ (with-temp-buffer
+ (insert "pp.setBackgroundResource(R.drawable.button_right);")
+ (let ((glasses-separate-parentheses-p nil))
+ (glasses-make-readable (point-min) (point-max))
+ (should-not (overlays-at 25)))))
+
+(ert-deftest glasses-tests-make-unreadable ()
+ (with-temp-buffer
+ (insert "pp.setBackgroundResource(R.drawable.button_right);")
+ (glasses-make-readable (point-min) (point-max))
+ (should (seq-some #'glasses-overlay-p
+ (overlays-in (point-min) (point-max))))
+ (glasses-make-unreadable (point-min) (point-max))
+ (should-not (seq-some #'glasses-overlay-p
+ (overlays-in (point-min) (point-max))))))
+
+(ert-deftest glasses-tests-convert-to-unreadable ()
+ (with-temp-buffer
+ (insert "set_Background_Resource(R.button_right);")
+ (let ((glasses-convert-on-write-p nil))
+ (should-not (glasses-convert-to-unreadable))
+ (should (equal (buffer-string)
+ "set_Background_Resource(R.button_right);")))
+ (let ((glasses-convert-on-write-p t))
+ (should-not (glasses-convert-to-unreadable))
+ (should (equal (buffer-string)
+ "setBackgroundResource(R.button_right);")))))
+
+(provide 'glasses-tests)
+;;; glasses-tests.el ends here
diff --git a/test/manual/indent/js-chain.js b/test/lisp/progmodes/js-resources/js-chain.js
index 2a290294026..2a290294026 100644
--- a/test/manual/indent/js-chain.js
+++ b/test/lisp/progmodes/js-resources/js-chain.js
diff --git a/test/manual/indent/js-indent-align-list-continuation-nil.js b/test/lisp/progmodes/js-resources/js-indent-align-list-continuation-nil.js
index 383b2539a26..383b2539a26 100644
--- a/test/manual/indent/js-indent-align-list-continuation-nil.js
+++ b/test/lisp/progmodes/js-resources/js-indent-align-list-continuation-nil.js
diff --git a/test/manual/indent/js-indent-init-dynamic.js b/test/lisp/progmodes/js-resources/js-indent-init-dynamic.js
index 536a976e86e..536a976e86e 100644
--- a/test/manual/indent/js-indent-init-dynamic.js
+++ b/test/lisp/progmodes/js-resources/js-indent-init-dynamic.js
diff --git a/test/manual/indent/js-indent-init-t.js b/test/lisp/progmodes/js-resources/js-indent-init-t.js
index bb755420ba7..bb755420ba7 100644
--- a/test/manual/indent/js-indent-init-t.js
+++ b/test/lisp/progmodes/js-resources/js-indent-init-t.js
diff --git a/test/manual/indent/js.js b/test/lisp/progmodes/js-resources/js.js
index 9658c95701c..9658c95701c 100644
--- a/test/manual/indent/js.js
+++ b/test/lisp/progmodes/js-resources/js.js
diff --git a/test/manual/indent/jsx-align-gt-with-lt.jsx b/test/lisp/progmodes/js-resources/jsx-align-gt-with-lt.jsx
index 8eb1d6d718c..8eb1d6d718c 100644
--- a/test/manual/indent/jsx-align-gt-with-lt.jsx
+++ b/test/lisp/progmodes/js-resources/jsx-align-gt-with-lt.jsx
diff --git a/test/manual/indent/jsx-comment-string.jsx b/test/lisp/progmodes/js-resources/jsx-comment-string.jsx
index cae023e7288..cae023e7288 100644
--- a/test/manual/indent/jsx-comment-string.jsx
+++ b/test/lisp/progmodes/js-resources/jsx-comment-string.jsx
diff --git a/test/manual/indent/jsx-indent-level.jsx b/test/lisp/progmodes/js-resources/jsx-indent-level.jsx
index 0a84b9eb77a..0a84b9eb77a 100644
--- a/test/manual/indent/jsx-indent-level.jsx
+++ b/test/lisp/progmodes/js-resources/jsx-indent-level.jsx
diff --git a/test/manual/indent/jsx-quote.jsx b/test/lisp/progmodes/js-resources/jsx-quote.jsx
index 1b2c6528734..1b2c6528734 100644
--- a/test/manual/indent/jsx-quote.jsx
+++ b/test/lisp/progmodes/js-resources/jsx-quote.jsx
diff --git a/test/manual/indent/jsx-self-closing.jsx b/test/lisp/progmodes/js-resources/jsx-self-closing.jsx
index f8ea7a138ad..f8ea7a138ad 100644
--- a/test/manual/indent/jsx-self-closing.jsx
+++ b/test/lisp/progmodes/js-resources/jsx-self-closing.jsx
diff --git a/test/manual/indent/jsx-unclosed-1.jsx b/test/lisp/progmodes/js-resources/jsx-unclosed-1.jsx
index 1f5c3fba8da..1f5c3fba8da 100644
--- a/test/manual/indent/jsx-unclosed-1.jsx
+++ b/test/lisp/progmodes/js-resources/jsx-unclosed-1.jsx
diff --git a/test/manual/indent/jsx-unclosed-2.jsx b/test/lisp/progmodes/js-resources/jsx-unclosed-2.jsx
index fb665b96a43..fb665b96a43 100644
--- a/test/manual/indent/jsx-unclosed-2.jsx
+++ b/test/lisp/progmodes/js-resources/jsx-unclosed-2.jsx
diff --git a/test/manual/indent/jsx.jsx b/test/lisp/progmodes/js-resources/jsx.jsx
index c200979df8c..c200979df8c 100644
--- a/test/manual/indent/jsx.jsx
+++ b/test/lisp/progmodes/js-resources/jsx.jsx
diff --git a/test/lisp/progmodes/js-tests.el b/test/lisp/progmodes/js-tests.el
index 419bf9eab17..cb7011e9a77 100644
--- a/test/lisp/progmodes/js-tests.el
+++ b/test/lisp/progmodes/js-tests.el
@@ -1,4 +1,4 @@
-;;; js-tests.el --- Test suite for js-mode
+;;; js-tests.el --- Test suite for js-mode -*- lexical-binding:t -*-
;; Copyright (C) 2017-2021 Free Software Foundation, Inc.
@@ -22,6 +22,7 @@
;;; Code:
(require 'ert)
+(require 'ert-x)
(require 'js)
(require 'syntax)
@@ -196,6 +197,46 @@ if (!/[ (:,='\"]/.test(value)) {
;; The bug was a hang.
(should t)))
+;;;; Indentation tests.
+
+(defun js-tests--remove-indentation ()
+ "Remove all indentation in the current buffer."
+ (goto-char (point-min))
+ (while (re-search-forward (rx bol (+ (in " \t"))) nil t)
+ (let ((syntax (save-match-data (syntax-ppss))))
+ (unless (nth 3 syntax) ; Avoid multiline string literals.
+ (replace-match "")))))
+
+(defmacro js-deftest-indent (file)
+ `(ert-deftest ,(intern (format "js-indent-test/%s" file)) ()
+ :tags '(:expensive-test)
+ (let ((buf (find-file-noselect (ert-resource-file ,file))))
+ (unwind-protect
+ (with-current-buffer buf
+ (let ((orig (buffer-string)))
+ (js-tests--remove-indentation)
+ ;; Indent and check that we get the original text.
+ (indent-region (point-min) (point-max))
+ (should (equal (buffer-string) orig))
+ ;; Verify idempotency.
+ (indent-region (point-min) (point-max))
+ (should (equal (buffer-string) orig))))
+ (kill-buffer buf)))))
+
+(js-deftest-indent "js-chain.js")
+(js-deftest-indent "js-indent-align-list-continuation-nil.js")
+(js-deftest-indent "js-indent-init-dynamic.js")
+(js-deftest-indent "js-indent-init-t.js")
+(js-deftest-indent "js.js")
+(js-deftest-indent "jsx-align-gt-with-lt.jsx")
+(js-deftest-indent "jsx-comment-string.jsx")
+(js-deftest-indent "jsx-indent-level.jsx")
+(js-deftest-indent "jsx-quote.jsx")
+(js-deftest-indent "jsx-self-closing.jsx")
+(js-deftest-indent "jsx-unclosed-1.jsx")
+(js-deftest-indent "jsx-unclosed-2.jsx")
+(js-deftest-indent "jsx.jsx")
+
(provide 'js-tests)
;;; js-tests.el ends here
diff --git a/test/lisp/progmodes/opascal-tests.el b/test/lisp/progmodes/opascal-tests.el
new file mode 100644
index 00000000000..682f2c6cb6b
--- /dev/null
+++ b/test/lisp/progmodes/opascal-tests.el
@@ -0,0 +1,45 @@
+;;; opascal-tests.el --- tests for opascal.el -*- lexical-binding: t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+(require 'ert)
+(require 'opascal)
+
+(ert-deftest opascal-indent-bug-36348 ()
+ (with-temp-buffer
+ (opascal-mode)
+ (let ((orig "{ -*- opascal -*- }
+
+procedure Toto ();
+begin
+ for i := 0 to 1 do
+ Write (str.Chars[i]);
+
+ // bug#36348
+ for var i := 0 to 1 do
+ Write (str.Chars[i]);
+
+end;
+"))
+ (insert orig)
+ (indent-region (point-min) (point-max))
+ (should (equal (buffer-string) orig)))))
+
+(provide 'opascal-tests)
+
+;;; opascal-tests.el ends here
diff --git a/test/lisp/progmodes/pascal-tests.el b/test/lisp/progmodes/pascal-tests.el
new file mode 100644
index 00000000000..e9c705806b3
--- /dev/null
+++ b/test/lisp/progmodes/pascal-tests.el
@@ -0,0 +1,63 @@
+;;; pascal-tests.el --- tests for pascal.el -*- lexical-binding: t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+(require 'ert)
+(require 'pascal)
+
+(ert-deftest pascal-completion ()
+ ;; Bug#41740: completion functions must preserve point.
+ (let ((pascal-completion-cache nil))
+ (with-temp-buffer
+ (pascal-mode)
+ (insert "program test; var")
+ (let* ((point-before (point))
+ (completions (pascal-completion "var" nil 'metadata))
+ (point-after (point)))
+ (should (equal completions nil))
+ (should (equal point-before point-after)))))
+
+ (let ((pascal-completion-cache nil))
+ (with-temp-buffer
+ (pascal-mode)
+ (insert "program test; function f(x : i")
+ (let* ((point-before (point))
+ (completions (pascal-completion "i" nil 'metadata))
+ (point-after (point)))
+ (should (equal completions nil))
+ (should (equal point-before point-after)))))
+
+ (let ((pascal-completion-cache nil))
+ (with-temp-buffer
+ (pascal-mode)
+ (insert "program test; function f(x : integer) : real")
+ (let* ((point-before (point))
+ (completions (pascal-completion "real" nil 'metadata))
+ (point-after (point)))
+ (should (equal completions nil))
+ (should (equal point-before point-after))))))
+
+(ert-deftest pascal-beg-of-defun ()
+ (with-temp-buffer
+ (pascal-mode)
+ (insert "program test; procedure p(")
+ (forward-char -1)
+ (pascal-beg-of-defun)
+ (should (equal (point) 15))))
+
+(provide 'pascal-tests)
diff --git a/test/lisp/progmodes/perl-mode-tests.el b/test/lisp/progmodes/perl-mode-tests.el
new file mode 100644
index 00000000000..9f6800ccd63
--- /dev/null
+++ b/test/lisp/progmodes/perl-mode-tests.el
@@ -0,0 +1,33 @@
+;;; perl-mode-tests --- Test for perl-mode -*- lexical-binding: t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'perl-mode)
+
+;;;; Re-use cperl-mode tests
+
+(defvar cperl-test-mode)
+(setq cperl-test-mode #'perl-mode)
+(load-file (expand-file-name "cperl-mode-tests.el"
+ (file-truename
+ (file-name-directory (or load-file-name
+ buffer-file-name)))))
+
+;;; perl-mode-tests.el ends here
diff --git a/test/lisp/progmodes/ps-mode-tests.el b/test/lisp/progmodes/ps-mode-tests.el
index c2d756147e7..eccc862ee3d 100644
--- a/test/lisp/progmodes/ps-mode-tests.el
+++ b/test/lisp/progmodes/ps-mode-tests.el
@@ -1,4 +1,4 @@
-;;; ps-mode-tests.el --- Test suite for ps-mode
+;;; ps-mode-tests.el --- Test suite for ps-mode -*- lexical-binding:t -*-
;; Copyright (C) 2019-2021 Free Software Foundation, Inc.
@@ -43,6 +43,30 @@
(should (equal (buffer-string)
"foo\\220\\221\\222bar"))))
+(ert-deftest ps-mode-test-indent ()
+ ;; Converted from manual test.
+ (with-temp-buffer
+ (ps-mode)
+ ;; TODO: Should some of these be fontification tests as well?
+ (let ((orig "%!PS-2.0
+
+<< 23 45 >> %dictionary
+< 23 > %hex string
+<~a>a%a~> %base85 string
+(%)s
+(sf\\(g>a)sdg)
+
+/foo {
+ <<
+ hello 2
+ 3
+ >>
+} def
+"))
+ (insert orig)
+ (indent-region (point-min) (point-max))
+ (should (equal (buffer-string) orig)))))
+
(provide 'ps-mode-tests)
;;; ps-mode-tests.el ends here
diff --git a/test/lisp/progmodes/python-tests.el b/test/lisp/progmodes/python-tests.el
index b855b0b1fe0..3e653cb568a 100644
--- a/test/lisp/progmodes/python-tests.el
+++ b/test/lisp/progmodes/python-tests.el
@@ -1,4 +1,4 @@
-;;; python-tests.el --- Test suite for python.el
+;;; python-tests.el --- Test suite for python.el -*- lexical-binding:t -*-
;; Copyright (C) 2013-2021 Free Software Foundation, Inc.
@@ -118,7 +118,6 @@ Argument MIN and MAX delimit the region to be returned and
default to `point-min' and `point-max' respectively."
(let* ((min (or min (point-min)))
(max (or max (point-max)))
- (buffer (current-buffer))
(buffer-contents (buffer-substring-no-properties min max))
(overlays
(sort (overlays-in min max)
@@ -154,7 +153,7 @@ The name of this directory depends on `system-type'."
sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua."
(let ((expected (save-excursion
- (dotimes (i 3)
+ (dotimes (_ 3)
(re-search-forward "et" nil t))
(forward-char -2)
(point))))
@@ -163,7 +162,7 @@ aliqua."
;; one should be returned.
(should (= (python-tests-look-at "et" 6 t) expected))
;; If already looking at STRING, it should skip it.
- (dotimes (i 2) (re-search-forward "et"))
+ (dotimes (_ 2) (re-search-forward "et"))
(forward-char -2)
(should (= (python-tests-look-at "et") expected)))))
@@ -178,7 +177,7 @@ aliqua."
(re-search-forward "et" nil t)
(forward-char -2)
(point))))
- (dotimes (i 3)
+ (dotimes (_ 3)
(re-search-forward "et" nil t))
(should (= (python-tests-look-at "et" -3 t) expected))
(should (= (python-tests-look-at "et" -6 t) expected)))))
@@ -205,7 +204,7 @@ aliqua."
;;; Indentation
-;; See: http://www.python.org/dev/peps/pep-0008/#indentation
+;; See: https://www.python.org/dev/peps/pep-0008/#indentation
(ert-deftest python-indent-pep8-1 ()
"First pep8 case."
@@ -340,7 +339,7 @@ def func(arg):
# I don't do much
return arg
# This comment is badly indented because the user forced so.
- # At this line python.el wont dedent, user is always right.
+ # At this line python.el won't dedent, user is always right.
comment_wins_over_ender = True
@@ -359,7 +358,7 @@ comment_wins_over_ender = True
;; The return keyword do make indentation lose a level...
(should (= (python-indent-calculate-indentation) 0))
;; ...but the current indentation was forced by the user.
- (python-tests-look-at "# At this line python.el wont dedent")
+ (python-tests-look-at "# At this line python.el won't dedent")
(should (eq (car (python-indent-context)) :after-comment))
(should (= (python-indent-calculate-indentation) 4))
;; Should behave the same for blank lines: potentially a comment.
@@ -2642,7 +2641,7 @@ if x:
(ert-deftest python-shell-calculate-process-environment-2 ()
"Test `python-shell-extra-pythonpaths' modification."
(let* ((process-environment process-environment)
- (original-pythonpath (setenv "PYTHONPATH" "/path0"))
+ (_original-pythonpath (setenv "PYTHONPATH" "/path0"))
(python-shell-extra-pythonpaths '("/path1" "/path2"))
(process-environment (python-shell-calculate-process-environment)))
(should (equal (getenv "PYTHONPATH")
diff --git a/test/manual/indent/ruby.rb b/test/lisp/progmodes/ruby-mode-resources/ruby.rb
index b038512b114..434237cf638 100644
--- a/test/manual/indent/ruby.rb
+++ b/test/lisp/progmodes/ruby-mode-resources/ruby.rb
@@ -34,7 +34,7 @@ x = # "tot %q/to"; =
# Regexp after whitelisted method.
"abc".sub /b/, 'd'
-# Don't mis-match "sub" at the end of words.
+# Don't mismatch "sub" at the end of words.
a = asub / aslb + bsub / bslb;
# Highlight the regexp after "if".
@@ -343,7 +343,7 @@ abc(foo
tee
.qux)
-# http://stackoverflow.com/questions/17786563/emacs-ruby-mode-if-expressions-indentation
+# https://stackoverflow.com/questions/17786563/emacs-ruby-mode-if-expressions-indentation
tee = if foo
bar
else
@@ -475,3 +475,11 @@ top test(
foo bar, {
tee: qux
}
+
+# Bug#42846, bug#18644
+
+:foo=
+# indent here
+2 = 3
+:foo= if true
+{:abc=>4} # not indented, and '=' is not highlighted
diff --git a/test/lisp/progmodes/ruby-mode-tests.el b/test/lisp/progmodes/ruby-mode-tests.el
index 63cbd365e92..67b592e9070 100644
--- a/test/lisp/progmodes/ruby-mode-tests.el
+++ b/test/lisp/progmodes/ruby-mode-tests.el
@@ -1,4 +1,4 @@
-;;; ruby-mode-tests.el --- Test suite for ruby-mode
+;;; ruby-mode-tests.el --- Test suite for ruby-mode -*- lexical-binding:t -*-
;; Copyright (C) 2012-2021 Free Software Foundation, Inc.
@@ -22,6 +22,7 @@
;;; Code:
(require 'ert)
+(require 'ert-x)
(require 'ruby-mode)
(defmacro ruby-with-temp-buffer (contents &rest body)
@@ -711,7 +712,7 @@ VALUES-PLIST is a list with alternating index and value elements."
(ruby-with-temp-buffer ruby-sexp-test-example
(goto-char (point-min))
(forward-line 1)
- (ruby-forward-sexp)
+ (forward-sexp)
(should (= 8 (line-number-at-pos)))))
(ert-deftest ruby-backward-sexp-skips-method-calls-with-keyword-names ()
@@ -719,7 +720,7 @@ VALUES-PLIST is a list with alternating index and value elements."
(goto-char (point-min))
(forward-line 7)
(end-of-line)
- (ruby-backward-sexp)
+ (backward-sexp)
(should (= 2 (line-number-at-pos)))))
(ert-deftest ruby-forward-sexp-jumps-do-end-block-with-no-args ()
@@ -728,7 +729,7 @@ VALUES-PLIST is a list with alternating index and value elements."
"proc do
|end")
(search-backward "do\n")
- (ruby-forward-sexp)
+ (forward-sexp)
(should (eobp))))
(ert-deftest ruby-backward-sexp-jumps-do-end-block-with-no-args ()
@@ -737,7 +738,7 @@ VALUES-PLIST is a list with alternating index and value elements."
"proc do
|end")
(goto-char (point-max))
- (ruby-backward-sexp)
+ (backward-sexp)
(should (looking-at "do$"))))
(ert-deftest ruby-forward-sexp-jumps-do-end-block-with-empty-args ()
@@ -746,7 +747,7 @@ VALUES-PLIST is a list with alternating index and value elements."
"proc do ||
|end")
(search-backward "do ")
- (ruby-forward-sexp)
+ (forward-sexp)
(should (eobp))))
(ert-deftest ruby-backward-sexp-jumps-do-end-block-with-empty-args ()
@@ -755,7 +756,7 @@ VALUES-PLIST is a list with alternating index and value elements."
"proc do ||
|end")
(goto-char (point-max))
- (ruby-backward-sexp)
+ (backward-sexp)
(should (looking-at "do "))))
(ert-deftest ruby-forward-sexp-jumps-do-end-block-with-args ()
@@ -764,7 +765,7 @@ VALUES-PLIST is a list with alternating index and value elements."
"proc do |a,b|
|end")
(search-backward "do ")
- (ruby-forward-sexp)
+ (forward-sexp)
(should (eobp))))
(ert-deftest ruby-backward-sexp-jumps-do-end-block-with-args ()
@@ -773,7 +774,7 @@ VALUES-PLIST is a list with alternating index and value elements."
"proc do |a,b|
|end")
(goto-char (point-max))
- (ruby-backward-sexp)
+ (backward-sexp)
(should (looking-at "do "))))
(ert-deftest ruby-forward-sexp-jumps-do-end-block-with-any-args ()
@@ -782,7 +783,7 @@ VALUES-PLIST is a list with alternating index and value elements."
"proc do |*|
|end")
(search-backward "do ")
- (ruby-forward-sexp)
+ (forward-sexp)
(should (eobp))))
(ert-deftest ruby-forward-sexp-jumps-do-end-block-with-expanded-one-arg ()
@@ -791,7 +792,7 @@ VALUES-PLIST is a list with alternating index and value elements."
"proc do |a,|
|end")
(search-backward "do ")
- (ruby-forward-sexp)
+ (forward-sexp)
(should (eobp))))
(ert-deftest ruby-forward-sexp-jumps-do-end-block-with-one-and-any-args ()
@@ -800,7 +801,7 @@ VALUES-PLIST is a list with alternating index and value elements."
"proc do |a,*|
|end")
(search-backward "do ")
- (ruby-forward-sexp)
+ (forward-sexp)
(should (eobp))))
(ert-deftest ruby-backward-sexp-jumps-do-end-block-with-one-and-any-args ()
@@ -809,7 +810,7 @@ VALUES-PLIST is a list with alternating index and value elements."
"proc do |a,*|
|end")
(goto-char (point-max))
- (ruby-backward-sexp)
+ (backward-sexp)
(should (looking-at "do "))))
(ert-deftest ruby-toggle-string-quotes-quotes-correctly ()
@@ -842,6 +843,16 @@ VALUES-PLIST is a list with alternating index and value elements."
(ruby--insert-coding-comment "utf-8")
(should (string= "# encoding: utf-8\n\n" (buffer-string))))))
+(ert-deftest ruby--indent/converted-from-manual-test ()
+ :tags '(:expensive-test)
+ ;; Converted from manual test.
+ (let ((buf (find-file-noselect (ert-resource-file "ruby.rb"))))
+ (unwind-protect
+ (with-current-buffer buf
+ (let ((orig (buffer-string)))
+ (indent-region (point-min) (point-max))
+ (should (equal (buffer-string) orig))))
+ (kill-buffer buf))))
(provide 'ruby-mode-tests)
diff --git a/test/lisp/progmodes/scheme-tests.el b/test/lisp/progmodes/scheme-tests.el
new file mode 100644
index 00000000000..8f2f75f81c2
--- /dev/null
+++ b/test/lisp/progmodes/scheme-tests.el
@@ -0,0 +1,50 @@
+;;; scheme-tests.el --- Test suite for scheme.el -*- lexical-binding:t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+(require 'scheme)
+
+(ert-deftest scheme-test-indent ()
+ ;; FIXME: Look into what is the expected indent here and fix it.
+ :expected-result :failed
+ ;; Converted from manual test.
+ (with-temp-buffer
+ (scheme-mode)
+ ;; TODO: Should some of these be fontification tests as well?
+ (let ((orig "#!/usr/bin/scheme is this a comment?
+
+;; This one is a comment
+(a)
+#| and this one as #|well|# as this! |#
+(b)
+(cons #;(this is a
+ comment)
+ head tail)
+"))
+ (insert orig)
+ (indent-region (point-min) (point-max))
+ (should (equal (buffer-string) orig)))))
+
+(provide 'scheme-tests)
+
+;;; scheme-tests.el ends here
diff --git a/test/lisp/progmodes/subword-tests.el b/test/lisp/progmodes/subword-tests.el
index 29b08951b7d..28a9445e01f 100644
--- a/test/lisp/progmodes/subword-tests.el
+++ b/test/lisp/progmodes/subword-tests.el
@@ -1,22 +1,24 @@
-;;; subword-tests.el --- Testing the subword rules
+;;; subword-tests.el --- Testing the subword rules -*- lexical-binding:t -*-
;; Copyright (C) 2011-2021 Free Software Foundation, Inc.
;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
;; Keywords:
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
diff --git a/test/lisp/progmodes/tcl-tests.el b/test/lisp/progmodes/tcl-tests.el
index 39d6569825e..8ff85470ece 100644
--- a/test/lisp/progmodes/tcl-tests.el
+++ b/test/lisp/progmodes/tcl-tests.el
@@ -1,4 +1,4 @@
-;;; tcl-tests.el --- Test suite for tcl-mode
+;;; tcl-tests.el --- Test suite for tcl-mode -*- lexical-binding:t -*-
;; Copyright (C) 2018-2021 Free Software Foundation, Inc.
diff --git a/test/data/xref/file1.txt b/test/lisp/progmodes/xref-resources/file1.txt
index 5d7cc544443..5d7cc544443 100644
--- a/test/data/xref/file1.txt
+++ b/test/lisp/progmodes/xref-resources/file1.txt
diff --git a/test/data/xref/file2.txt b/test/lisp/progmodes/xref-resources/file2.txt
index 9f075f26004..9f075f26004 100644
--- a/test/data/xref/file2.txt
+++ b/test/lisp/progmodes/xref-resources/file2.txt
diff --git a/test/lisp/progmodes/xref-tests.el b/test/lisp/progmodes/xref-tests.el
index 766b4aa6c0d..eaafc5888c7 100644
--- a/test/lisp/progmodes/xref-tests.el
+++ b/test/lisp/progmodes/xref-tests.el
@@ -1,4 +1,4 @@
-;;; xref-tests.el --- tests for xref
+;;; xref-tests.el --- tests for xref -*- lexical-binding:t -*-
;; Copyright (C) 2016-2021 Free Software Foundation, Inc.
@@ -23,47 +23,54 @@
;;; Code:
+(require 'ert)
(require 'xref)
(require 'cl-lib)
-(defvar xref-tests-data-dir
- (expand-file-name "../../../data/xref/"
- (or load-file-name
- buffer-file-name)))
+(defvar xref-tests--data-dir
+ (expand-file-name "xref-resources/"
+ (file-name-directory
+ (or load-file-name buffer-file-name))))
+
+(defun xref-tests--matches-in-data-dir (regexp &optional files)
+ (xref-matches-in-directory regexp (or files "*") xref-tests--data-dir nil))
+
+(defun xref-tests--locations-in-data-dir (regexp &optional files)
+ (let ((matches (xref-tests--matches-in-data-dir regexp files)))
+ ;; Sort in order to guarantee an order independent from the
+ ;; filesystem traversal.
+ (cl-sort (mapcar #'xref-item-location matches)
+ #'string<
+ :key #'xref-location-group)))
(ert-deftest xref-matches-in-directory-finds-none-for-some-regexp ()
- (should (null (xref-matches-in-directory "zzz" "*" xref-tests-data-dir nil))))
+ (should (null (xref-tests--matches-in-data-dir "zzz"))))
(ert-deftest xref-matches-in-directory-finds-some-for-bar ()
- (let* ((matches (xref-matches-in-directory "bar" "*" xref-tests-data-dir nil))
- (locs (cl-sort (mapcar #'xref-item-location matches)
- #'string<
- :key #'xref-location-group)))
- (should (= 2 (length matches)))
+ (let ((locs (xref-tests--locations-in-data-dir "bar")))
+ (should (= 2 (length locs)))
(should (string-match-p "file1\\.txt\\'" (xref-location-group (nth 0 locs))))
(should (string-match-p "file2\\.txt\\'" (xref-location-group (nth 1 locs))))))
(ert-deftest xref-matches-in-directory-finds-two-matches-on-the-same-line ()
- (let* ((matches (xref-matches-in-directory "foo" "*" xref-tests-data-dir nil))
- (locs (mapcar #'xref-item-location matches)))
- (should (= 2 (length matches)))
+ (let ((locs (xref-tests--locations-in-data-dir "foo")))
+ (should (= 2 (length locs)))
(should (string-match-p "file1\\.txt\\'" (xref-location-group (nth 0 locs))))
(should (string-match-p "file1\\.txt\\'" (xref-location-group (nth 1 locs))))
(should (equal 1 (xref-location-line (nth 0 locs))))
(should (equal 1 (xref-location-line (nth 1 locs))))
- (should (equal 0 (xref-file-location-column (nth 0 locs))))
- (should (equal 4 (xref-file-location-column (nth 1 locs))))))
+ (should (equal 0 (xref-location-column (nth 0 locs))))
+ (should (equal 4 (xref-location-column (nth 1 locs))))))
(ert-deftest xref-matches-in-directory-finds-an-empty-line-regexp-match ()
- (let* ((matches (xref-matches-in-directory "^$" "*" xref-tests-data-dir nil))
- (locs (mapcar #'xref-item-location matches)))
- (should (= 1 (length matches)))
+ (let ((locs (xref-tests--locations-in-data-dir "^$")))
+ (should (= 1 (length locs)))
(should (string-match-p "file2\\.txt\\'" (xref-location-group (nth 0 locs))))
(should (equal 1 (xref-location-line (nth 0 locs))))
- (should (equal 0 (xref-file-location-column (nth 0 locs))))))
+ (should (equal 0 (xref-location-column (nth 0 locs))))))
(ert-deftest xref--buf-pairs-iterator-groups-markers-by-buffers-1 ()
- (let* ((xrefs (xref-matches-in-directory "foo" "*" xref-tests-data-dir nil))
+ (let* ((xrefs (xref-tests--matches-in-data-dir "foo"))
(iter (xref--buf-pairs-iterator xrefs))
(cons (funcall iter :next)))
(should (null (funcall iter :next)))
@@ -71,7 +78,7 @@
(should (= 2 (length (cdr cons))))))
(ert-deftest xref--buf-pairs-iterator-groups-markers-by-buffers-2 ()
- (let* ((xrefs (xref-matches-in-directory "bar" "*" xref-tests-data-dir nil))
+ (let* ((xrefs (xref-tests--matches-in-data-dir "bar"))
(iter (xref--buf-pairs-iterator xrefs))
(cons1 (funcall iter :next))
(cons2 (funcall iter :next)))
@@ -81,7 +88,7 @@
(should (= 1 (length (cdr cons2))))))
(ert-deftest xref--buf-pairs-iterator-cleans-up-markers ()
- (let* ((xrefs (xref-matches-in-directory "bar" "*" xref-tests-data-dir nil))
+ (let* ((xrefs (xref-tests--matches-in-data-dir "bar"))
(iter (xref--buf-pairs-iterator xrefs))
(cons1 (funcall iter :next))
(cons2 (funcall iter :next)))
@@ -90,3 +97,34 @@
(should (null (marker-position (cdr (nth 0 (cdr cons1))))))
(should (null (marker-position (car (nth 0 (cdr cons2))))))
(should (null (marker-position (cdr (nth 0 (cdr cons2))))))))
+
+(ert-deftest xref--xref-file-name-display-is-abs ()
+ (let ((xref-file-name-display 'abs))
+ (should (equal (delete-dups
+ (mapcar 'xref-location-group
+ (xref-tests--locations-in-data-dir "\\(bar\\|foo\\)")))
+ (list
+ (concat xref-tests--data-dir "file1.txt")
+ (concat xref-tests--data-dir "file2.txt"))))))
+
+(ert-deftest xref--xref-file-name-display-is-nondirectory ()
+ (let ((xref-file-name-display 'nondirectory))
+ (should (equal (delete-dups
+ (mapcar 'xref-location-group
+ (xref-tests--locations-in-data-dir "\\(bar\\|foo\\)")))
+ (list
+ "file1.txt"
+ "file2.txt")))))
+
+(ert-deftest xref--xref-file-name-display-is-relative-to-project-root ()
+ (let* ((data-parent-dir
+ (file-name-directory (directory-file-name xref-tests--data-dir)))
+ (project-find-functions
+ #'(lambda (_) (cons 'transient data-parent-dir)))
+ (xref-file-name-display 'project-relative))
+ (should (equal (delete-dups
+ (mapcar 'xref-location-group
+ (xref-tests--locations-in-data-dir "\\(bar\\|foo\\)")))
+ (list
+ "xref-resources/file1.txt"
+ "xref-resources/file2.txt")))))
diff --git a/test/lisp/replace-tests.el b/test/lisp/replace-tests.el
index 1ea1e8199c5..8c2682a1f13 100644
--- a/test/lisp/replace-tests.el
+++ b/test/lisp/replace-tests.el
@@ -1,4 +1,4 @@
-;;; replace-tests.el --- tests for replace.el.
+;;; replace-tests.el --- tests for replace.el. -*- lexical-binding:t -*-
;; Copyright (C) 2010-2021 Free Software Foundation, Inc.
@@ -546,4 +546,46 @@ Return the last evalled form in BODY."
?q
(string= expected (buffer-string))))))
+(defmacro replace-tests-with-highlighted-occurrence (highlight-locus &rest body)
+ "Helper macro to test the highlight of matches when navigating occur buffer.
+
+Eval BODY with `next-error-highlight' and `next-error-highlight-no-select'
+bound to HIGHLIGHT-LOCUS."
+ (declare (indent 1) (debug (form body)))
+ `(let ((regexp "foo")
+ (next-error-highlight ,highlight-locus)
+ (next-error-highlight-no-select ,highlight-locus)
+ (buffer (generate-new-buffer "test"))
+ (inhibit-message t))
+ (unwind-protect
+ ;; Local bind to disable the deletion of `occur-highlight-overlay'
+ (cl-letf (((symbol-function 'occur-goto-locus-delete-o) (lambda ())))
+ (with-current-buffer buffer (dotimes (_ 3) (insert regexp ?\n)))
+ (pop-to-buffer buffer)
+ (occur regexp)
+ (pop-to-buffer "*Occur*")
+ (occur-next)
+ ,@body)
+ (kill-buffer buffer)
+ (kill-buffer "*Occur*"))))
+
+(ert-deftest occur-highlight-occurrence ()
+ "Test for https://debbugs.gnu.org/39121 ."
+ (let ((alist '((nil . nil) (0.5 . t) (t . t) (fringe-arrow . nil)))
+ (check-overlays
+ (lambda (has-ov)
+ (eq has-ov (not (null (overlays-in (point-min) (point-max))))))))
+ (pcase-dolist (`(,highlight-locus . ,has-overlay) alist)
+ ;; Visiting occurrences
+ (replace-tests-with-highlighted-occurrence highlight-locus
+ (occur-mode-goto-occurrence)
+ (should (funcall check-overlays has-overlay)))
+ ;; Displaying occurrences
+ (replace-tests-with-highlighted-occurrence highlight-locus
+ (occur-mode-display-occurrence)
+ (with-current-buffer (marker-buffer
+ (get-text-property (point) 'occur-target))
+ (should (funcall check-overlays has-overlay)))))))
+
+
;;; replace-tests.el ends here
diff --git a/test/lisp/saveplace-resources/saveplace b/test/lisp/saveplace-resources/saveplace
new file mode 100644
index 00000000000..3f3f6d501d6
--- /dev/null
+++ b/test/lisp/saveplace-resources/saveplace
@@ -0,0 +1,4 @@
+;;; -*- coding: utf-8 -*-
+(("/home/skangas/.emacs.d/cache/recentf" . 1306)
+ ("/home/skangas/wip/emacs/"
+ (dired-filename . "/home/skangas/wip/emacs/COPYING")))
diff --git a/test/lisp/saveplace-tests.el b/test/lisp/saveplace-tests.el
new file mode 100644
index 00000000000..17199ed443a
--- /dev/null
+++ b/test/lisp/saveplace-tests.el
@@ -0,0 +1,99 @@
+;;; saveplace-tests.el --- Tests for saveplace.el -*- lexical-binding:t -*-
+
+;; Copyright (C) 2019-2021 Free Software Foundation, Inc.
+
+;; Author: Stefan Kangas <stefankangas@gmail.com>
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+(require 'ert)
+(require 'ert-x)
+(require 'saveplace)
+
+(ert-deftest saveplace-test-save-place-to-alist/dir ()
+ (save-place-mode)
+ (let* ((save-place-alist nil)
+ (save-place-loaded t)
+ (loc (ert-resource-directory)))
+ (save-window-excursion
+ (dired loc)
+ (save-place-to-alist)
+ (should (equal save-place-alist
+ `((,loc
+ (dired-filename . ,(concat loc "saveplace")))))))))
+
+(ert-deftest saveplace-test-save-place-to-alist/file ()
+ (save-place-mode)
+ (let* ((tmpfile (make-temp-file "emacs-test-saveplace-"))
+ (tmpfile (file-truename tmpfile))
+ (save-place-alist nil)
+ (save-place-loaded t)
+ (loc tmpfile)
+ (pos 4))
+ (unwind-protect
+ (save-window-excursion
+ (find-file loc)
+ (insert "abc") ; must insert something
+ (save-place-to-alist)
+ (should (equal save-place-alist (list (cons tmpfile pos)))))
+ (delete-file tmpfile))))
+
+(ert-deftest saveplace-test-forget-unreadable-files ()
+ (save-place-mode)
+ (let* ((save-place-loaded t)
+ (tmpfile (make-temp-file "emacs-test-saveplace-"))
+ (alist-orig (list (cons "/this/file/does/not/exist" 10)
+ (cons tmpfile 1917)))
+ (save-place-alist alist-orig))
+ (unwind-protect
+ (progn
+ (save-place-forget-unreadable-files)
+ (should (equal save-place-alist (cdr alist-orig))))
+ (delete-file tmpfile))))
+
+(ert-deftest saveplace-test-place-alist-to-file ()
+ (save-place-mode)
+ (let* ((tmpfile (make-temp-file "emacs-test-saveplace-"))
+ (tmpfile2 (make-temp-file "emacs-test-saveplace-"))
+ (save-place-file tmpfile)
+ (save-place-alist (list (cons tmpfile2 99))))
+ (unwind-protect
+ (progn (save-place-alist-to-file)
+ (setq save-place-alist nil)
+ (save-window-excursion
+ (find-file save-place-file)
+ (unwind-protect
+ (should (string-match tmpfile2 (buffer-string)))
+ (kill-buffer))))
+ (delete-file tmpfile)
+ (delete-file tmpfile2))))
+
+(ert-deftest saveplace-test-load-alist-from-file ()
+ (save-place-mode)
+ (let ((save-place-loaded nil)
+ (save-place-file
+ (ert-resource-file "saveplace"))
+ (save-place-alist nil))
+ (load-save-place-alist-from-file)
+ (should (equal save-place-alist
+ '(("/home/skangas/.emacs.d/cache/recentf" . 1306)
+ ("/home/skangas/wip/emacs/"
+ (dired-filename . "/home/skangas/wip/emacs/COPYING")))))))
+
+(provide 'saveplace-tests)
+;;; saveplace-tests.el ends here
diff --git a/test/lisp/shadowfile-tests.el b/test/lisp/shadowfile-tests.el
index e158ad8b0a8..0c2d7123dd7 100644
--- a/test/lisp/shadowfile-tests.el
+++ b/test/lisp/shadowfile-tests.el
@@ -1,21 +1,23 @@
-;;; shadowfile-tests.el --- Tests of shadowfile
+;;; shadowfile-tests.el --- Tests of shadowfile -*- lexical-binding:t -*-
;; Copyright (C) 2018-2021 Free Software Foundation, Inc.
;; Author: Michael Albinus <michael.albinus@gmx.de>
-;; This program is free software: you can redistribute it and/or
+;; 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.
;;
-;; This program is distributed in the hope that it will be useful, but
+;; 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 `https://www.gnu.org/licenses/'.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
@@ -70,7 +72,6 @@
(setq password-cache-expiry nil
shadow-debug (getenv "EMACS_HYDRA_CI")
tramp-verbose 0
- tramp-message-show-message nil
;; On macOS, `temporary-file-directory' is a symlinked directory.
temporary-file-directory (file-truename temporary-file-directory)
shadow-test-remote-temporary-file-directory
@@ -126,6 +127,7 @@
Per definition, all files are identical on the different hosts of
a cluster (or site). This is not tested here; it must be
guaranteed by the originator of a cluster definition."
+ :tags '(:expensive-test)
(skip-unless (not (memq system-type '(windows-nt ms-dos))))
(skip-unless (file-remote-p shadow-test-remote-temporary-file-directory))
@@ -139,9 +141,9 @@ guaranteed by the originator of a cluster definition."
;; We must mock `read-from-minibuffer' and `read-string', in
;; order to avoid interactive arguments.
(cl-letf* (((symbol-function #'read-from-minibuffer)
- (lambda (&rest args) (pop mocked-input)))
+ (lambda (&rest _args) (pop mocked-input)))
((symbol-function #'read-string)
- (lambda (&rest args) (pop mocked-input))))
+ (lambda (&rest _args) (pop mocked-input))))
;; Cleanup & initialize.
(shadow--tests-cleanup)
@@ -256,9 +258,9 @@ guaranteed by the originator of a cluster definition."
;; We must mock `read-from-minibuffer' and `read-string', in
;; order to avoid interactive arguments.
(cl-letf* (((symbol-function #'read-from-minibuffer)
- (lambda (&rest args) (pop mocked-input)))
+ (lambda (&rest _args) (pop mocked-input)))
((symbol-function #'read-string)
- (lambda (&rest args) (pop mocked-input))))
+ (lambda (&rest _args) (pop mocked-input))))
;; Cleanup & initialize.
(shadow--tests-cleanup)
@@ -609,9 +611,9 @@ guaranteed by the originator of a cluster definition."
;; We must mock `read-from-minibuffer' and `read-string', in
;; order to avoid interactive arguments.
(cl-letf* (((symbol-function #'read-from-minibuffer)
- (lambda (&rest args) (pop mocked-input)))
+ (lambda (&rest _args) (pop mocked-input)))
((symbol-function #'read-string)
- (lambda (&rest args) (pop mocked-input))))
+ (lambda (&rest _args) (pop mocked-input))))
;; Cleanup & initialize.
(shadow--tests-cleanup)
@@ -670,9 +672,9 @@ guaranteed by the originator of a cluster definition."
;; We must mock `read-from-minibuffer' and `read-string', in
;; order to avoid interactive arguments.
(cl-letf* (((symbol-function #'read-from-minibuffer)
- (lambda (&rest args) (pop mocked-input)))
+ (lambda (&rest _args) (pop mocked-input)))
((symbol-function #'read-string)
- (lambda (&rest args) (pop mocked-input))))
+ (lambda (&rest _args) (pop mocked-input))))
;; Cleanup & initialize.
(shadow--tests-cleanup)
@@ -866,6 +868,7 @@ guaranteed by the originator of a cluster definition."
(ert-deftest shadow-test09-shadow-copy-files ()
"Check that needed shadow files are copied."
+ :tags '(:expensive-test)
(skip-unless (not (memq system-type '(windows-nt ms-dos))))
(skip-unless (file-remote-p shadow-test-remote-temporary-file-directory))
(skip-unless (file-writable-p shadow-test-remote-temporary-file-directory))
@@ -924,7 +927,7 @@ guaranteed by the originator of a cluster definition."
;; action.
(add-function
:before (symbol-function #'write-region)
- (lambda (&rest args)
+ (lambda (&rest _args)
(when (and (buffer-file-name) mocked-input)
(should (equal (buffer-file-name) (pop mocked-input)))))
'((name . "write-region-mock")))
diff --git a/test/lisp/simple-tests.el b/test/lisp/simple-tests.el
index 0530ee04d9d..7b022811a5c 100644
--- a/test/lisp/simple-tests.el
+++ b/test/lisp/simple-tests.el
@@ -4,18 +4,20 @@
;; Author: Artur Malabarba <bruce.connor.am@gmail.com>
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Code:
@@ -39,6 +41,13 @@
(with-no-warnings (simple-test--buffer-substrings))))
+;;; `count-words'
+(ert-deftest simple-test-count-words-bug-41761 ()
+ (with-temp-buffer
+ (dotimes (_i 10) (insert (propertize "test " 'field (cons nil nil))))
+ (should (= (count-words (point-min) (point-max)) 10))))
+
+
;;; `transpose-sexps'
(defmacro simple-test--transpositions (&rest body)
(declare (indent 0)
@@ -392,6 +401,48 @@ See bug#35036."
(should (equal ?\s (char-syntax ?\n))))))
+;;; undo tests
+
+(defun simple-tests--exec (cmds)
+ (dolist (cmd cmds)
+ (setq last-command this-command)
+ (setq this-command cmd)
+ (run-hooks 'pre-command-hook)
+ (command-execute cmd)
+ (run-hooks 'post-command-hook)
+ (undo-boundary)))
+
+(ert-deftest simple-tests--undo ()
+ (with-temp-buffer
+ (buffer-enable-undo)
+ (dolist (x '("a" "b" "c" "d" "e"))
+ (insert x)
+ (undo-boundary))
+ (should (equal (buffer-string) "abcde"))
+ (simple-tests--exec '(undo undo))
+ (should (equal (buffer-string) "abc"))
+ (simple-tests--exec '(backward-char undo))
+ (should (equal (buffer-string) "abcd"))
+ (simple-tests--exec '(undo))
+ (should (equal (buffer-string) "abcde"))
+ (simple-tests--exec '(backward-char undo undo))
+ (should (equal (buffer-string) "abc"))
+ (simple-tests--exec '(backward-char undo-redo))
+ (should (equal (buffer-string) "abcd"))
+ (simple-tests--exec '(undo))
+ (should (equal (buffer-string) "abc"))
+ (simple-tests--exec '(backward-char undo-redo undo-redo))
+ (should (equal (buffer-string) "abcde"))
+ (simple-tests--exec '(undo undo))
+ (should (equal (buffer-string) "abc"))
+ (simple-tests--exec '(backward-char undo-only undo-only))
+ (should (equal (buffer-string) "a"))
+ (simple-tests--exec '(backward-char undo-redo undo-redo))
+ (should (equal (buffer-string) "abc"))
+ (simple-tests--exec '(backward-char undo-redo undo-redo))
+ (should (equal (buffer-string) "abcde"))
+ ))
+
;;; undo auto-boundary tests
(ert-deftest undo-auto-boundary-timer ()
(should
@@ -427,7 +478,7 @@ See bug#35036."
(with-temp-buffer
(switch-to-buffer (current-buffer))
(setq buffer-undo-list nil)
- (insert "a\nb\n\c\n")
+ (insert "a\nb\nc\n")
(goto-char (point-max))
;; We use a keyboard macro because it adds undo events in the same
;; way as if a user were involved.
diff --git a/test/lisp/so-long-tests/so-long-tests.el b/test/lisp/so-long-tests/so-long-tests.el
index fbbe14ff665..a6d8721ffc8 100644
--- a/test/lisp/so-long-tests/so-long-tests.el
+++ b/test/lisp/so-long-tests/so-long-tests.el
@@ -181,7 +181,7 @@
;; The various 'window change functions' are now invoked by the
;; redisplay, and redisplay does nothing at all in batch mode,
;; so we cannot test under this revised behavior. Refer to:
- ;; https://lists.gnu.org/archive/html/emacs-devel/2019-10/msg00971.html
+ ;; https://lists.gnu.org/r/emacs-devel/2019-10/msg00971.html
;; For interactive (non-batch) test runs, calling `redisplay'
;; does do the trick; so do that first.
(redisplay)
diff --git a/test/lisp/sort-tests.el b/test/lisp/sort-tests.el
index ef4b8cca05e..62b89c1825d 100644
--- a/test/lisp/sort-tests.el
+++ b/test/lisp/sort-tests.el
@@ -4,18 +4,20 @@
;; Author: Artur Malabarba <bruce.connor.am@gmail.com>
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Code:
diff --git a/test/lisp/subr-tests.el b/test/lisp/subr-tests.el
index 81cb24f5ba1..2f5b38d05d9 100644
--- a/test/lisp/subr-tests.el
+++ b/test/lisp/subr-tests.el
@@ -1,4 +1,4 @@
-;;; subr-tests.el --- Tests for subr.el
+;;; subr-tests.el --- Tests for subr.el -*- lexical-binding:t -*-
;; Copyright (C) 2015-2021 Free Software Foundation, Inc.
@@ -172,27 +172,28 @@
(should (equal (version-to-list "6.9.30Beta") '(6 9 30 -2)))
(should (equal (version-to-list "6.9.30_Beta") '(6 9 30 -2)))
- (should (equal
- (error-message-string (should-error (version-to-list "OTP-18.1.5")))
- "Invalid version syntax: `OTP-18.1.5' (must start with a number)"))
- (should (equal
- (error-message-string (should-error (version-to-list "")))
- "Invalid version syntax: `' (must start with a number)"))
- (should (equal
- (error-message-string (should-error (version-to-list "1.0..7.5")))
- "Invalid version syntax: `1.0..7.5'"))
- (should (equal
- (error-message-string (should-error (version-to-list "1.0prepre2")))
- "Invalid version syntax: `1.0prepre2'"))
- (should (equal
- (error-message-string (should-error (version-to-list "22.8X3")))
- "Invalid version syntax: `22.8X3'"))
- (should (equal
- (error-message-string (should-error (version-to-list "beta22.8alpha3")))
- "Invalid version syntax: `beta22.8alpha3' (must start with a number)"))
- (should (equal
- (error-message-string (should-error (version-to-list "honk")))
- "Invalid version syntax: `honk' (must start with a number)"))
+ (let ((text-quoting-style 'grave))
+ (should (equal
+ (error-message-string (should-error (version-to-list "OTP-18.1.5")))
+ "Invalid version syntax: `OTP-18.1.5' (must start with a number)"))
+ (should (equal
+ (error-message-string (should-error (version-to-list "")))
+ "Invalid version syntax: `' (must start with a number)"))
+ (should (equal
+ (error-message-string (should-error (version-to-list "1.0..7.5")))
+ "Invalid version syntax: `1.0..7.5'"))
+ (should (equal
+ (error-message-string (should-error (version-to-list "1.0prepre2")))
+ "Invalid version syntax: `1.0prepre2'"))
+ (should (equal
+ (error-message-string (should-error (version-to-list "22.8X3")))
+ "Invalid version syntax: `22.8X3'"))
+ (should (equal
+ (error-message-string (should-error (version-to-list "beta22.8alpha3")))
+ "Invalid version syntax: `beta22.8alpha3' (must start with a number)"))
+ (should (equal
+ (error-message-string (should-error (version-to-list "honk")))
+ "Invalid version syntax: `honk' (must start with a number)")))
(should (equal
(error-message-string (should-error (version-to-list 9)))
"Version must be a string"))
@@ -231,18 +232,40 @@
(should (equal (version-to-list "6_9_30.Beta") '(6 9 30 -2)))
(should (equal (version-to-list "6_9_30Beta") '(6 9 30 -2)))
- (should (equal
- (error-message-string (should-error (version-to-list "1_0__7_5")))
- "Invalid version syntax: `1_0__7_5'"))
- (should (equal
- (error-message-string (should-error (version-to-list "1_0prepre2")))
- "Invalid version syntax: `1_0prepre2'"))
- (should (equal
- (error-message-string (should-error (version-to-list "22.8X3")))
- "Invalid version syntax: `22.8X3'"))
- (should (equal
- (error-message-string (should-error (version-to-list "beta22_8alpha3")))
- "Invalid version syntax: `beta22_8alpha3' (must start with a number)"))))
+ (let ((text-quoting-style 'grave))
+ (should (equal
+ (error-message-string (should-error (version-to-list "1_0__7_5")))
+ "Invalid version syntax: `1_0__7_5'"))
+ (should (equal
+ (error-message-string (should-error (version-to-list "1_0prepre2")))
+ "Invalid version syntax: `1_0prepre2'"))
+ (should (equal
+ (error-message-string (should-error (version-to-list "22.8X3")))
+ "Invalid version syntax: `22.8X3'"))
+ (should (equal
+ (error-message-string (should-error (version-to-list "beta22_8alpha3")))
+ "Invalid version syntax: `beta22_8alpha3' (must start with a number)")))))
+
+(ert-deftest subr-test-version-list-< ()
+ (should (version-list-< '(0) '(1)))
+ (should (version-list-< '(0 9) '(1 0)))
+ (should (version-list-< '(1 -1) '(1 0)))
+ (should (version-list-< '(1 -2) '(1 -1)))
+ (should (not (version-list-< '(1) '(0))))
+ (should (not (version-list-< '(1 1) '(1 0))))
+ (should (not (version-list-< '(1) '(1 0))))
+ (should (not (version-list-< '(1 0) '(1 0 0)))))
+
+(ert-deftest subr-test-version-list-= ()
+ (should (version-list-= '(1) '(1)))
+ (should (version-list-= '(1 0) '(1)))
+ (should (not (version-list-= '(0) '(1)))))
+
+(ert-deftest subr-test-version-list-<= ()
+ (should (version-list-<= '(0) '(1)))
+ (should (version-list-<= '(1) '(1)))
+ (should (version-list-<= '(1 0) '(1)))
+ (should (not (version-list-<= '(1) '(0)))))
(defun subr-test--backtrace-frames-with-backtrace-frame (base)
"Reference implementation of `backtrace-frames'."
@@ -417,5 +440,195 @@ See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=19350."
(should-error (ignore-error foo
(read ""))))
+(ert-deftest string-replace ()
+ (should (equal (string-replace "foo" "bar" "zot")
+ "zot"))
+ (should (equal (string-replace "foo" "bar" "foozot")
+ "barzot"))
+ (should (equal (string-replace "foo" "bar" "barfoozot")
+ "barbarzot"))
+ (should (equal (string-replace "zot" "bar" "barfoozot")
+ "barfoobar"))
+ (should (equal (string-replace "z" "bar" "barfoozot")
+ "barfoobarot"))
+ (should (equal (string-replace "zot" "bar" "zat")
+ "zat"))
+ (should (equal (string-replace "azot" "bar" "zat")
+ "zat"))
+ (should (equal (string-replace "azot" "bar" "azot")
+ "bar"))
+
+ (should (equal (string-replace "azot" "bar" "foozotbar")
+ "foozotbar"))
+
+ (should (equal (string-replace "fo" "bar" "lafofofozot")
+ "labarbarbarzot"))
+
+ (should (equal (string-replace "\377" "x" "a\377b")
+ "axb"))
+ (should (equal (string-replace "\377" "x" "a\377ø")
+ "axø"))
+ (should (equal (string-replace (string-to-multibyte "\377") "x" "a\377b")
+ "axb"))
+ (should (equal (string-replace (string-to-multibyte "\377") "x" "a\377ø")
+ "axø"))
+
+ (should (equal (string-replace "ana" "ANA" "ananas") "ANAnas"))
+
+ (should (equal (string-replace "a" "" "") ""))
+ (should (equal (string-replace "a" "" "aaaaa") ""))
+ (should (equal (string-replace "ab" "" "ababab") ""))
+ (should (equal (string-replace "ab" "" "abcabcabc") "ccc"))
+ (should (equal (string-replace "a" "aa" "aaa") "aaaaaa"))
+ (should (equal (string-replace "abc" "defg" "abc") "defg"))
+
+ (should-error (string-replace "" "x" "abc")))
+
+(ert-deftest subr-replace-regexp-in-string ()
+ (should (equal (replace-regexp-in-string "a+" "xy" "abaabbabaaba")
+ "xybxybbxybxybxy"))
+ ;; FIXEDCASE
+ (let ((case-fold-search t))
+ (should (equal (replace-regexp-in-string "a+" "xy" "ABAABBABAABA")
+ "XYBXYBBXYBXYBXY"))
+ (should (equal (replace-regexp-in-string "a+" "xy" "ABAABBABAABA" t)
+ "xyBxyBBxyBxyBxy"))
+ (should (equal (replace-regexp-in-string
+ "a[bc]*" "xyz"
+ "a A ab AB Ab aB abc ABC Abc AbC aBc")
+ "xyz XYZ xyz XYZ Xyz xyz xyz XYZ Xyz Xyz xyz"))
+ (should (equal (replace-regexp-in-string
+ "a[bc]*" "xyz"
+ "a A ab AB Ab aB abc ABC Abc AbC aBc" t)
+ "xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz")))
+ (let ((case-fold-search nil))
+ (should (equal (replace-regexp-in-string "a+" "xy" "ABAABBABAABA")
+ "ABAABBABAABA")))
+ ;; group substitution
+ (should (equal (replace-regexp-in-string
+ "a\\(b*\\)" "<\\1,\\&>" "babbcaabacbab")
+ "b<bb,abb>c<,a><b,ab><,a>cb<b,ab>"))
+ (should (equal (replace-regexp-in-string
+ "x\\(?2:..\\)\\(?1:..\\)\\(..\\)\\(..\\)\\(..\\)"
+ "<\\3,\\5,\\4,\\1,\\2>" "yxabcdefghijkl")
+ "y<ef,ij,gh,cd,ab>kl"))
+ ;; LITERAL
+ (should (equal (replace-regexp-in-string
+ "a\\(b*\\)" "<\\1,\\&>" "babbcaabacbab" nil t)
+ "b<\\1,\\&>c<\\1,\\&><\\1,\\&><\\1,\\&>cb<\\1,\\&>"))
+ (should (equal (replace-regexp-in-string
+ "a" "\\\\,\\?" "aba")
+ "\\,\\?b\\,\\?"))
+ (should (equal (replace-regexp-in-string
+ "a" "\\\\,\\?" "aba" nil t)
+ "\\\\,\\?b\\\\,\\?"))
+ ;; SUBEXP
+ (should (equal (replace-regexp-in-string
+ "\\(a\\)\\(b*\\)c" "xy" "babbcdacd" nil nil 2)
+ "baxycdaxycd"))
+ ;; START
+ (should (equal (replace-regexp-in-string
+ "ab" "x" "abcabdabeabf" nil nil nil 4)
+ "bdxexf"))
+ ;; An empty pattern matches once before every character.
+ (should (equal (replace-regexp-in-string "" "x" "abc")
+ "xaxbxc"))
+ (should (equal (replace-regexp-in-string "y*" "x" "abc")
+ "xaxbxc"))
+ ;; replacement function
+ (should (equal (replace-regexp-in-string
+ "a\\(b*\\)c"
+ (lambda (s)
+ (format "<%s,%s,%s,%s,%s>"
+ s
+ (match-beginning 0) (match-end 0)
+ (match-beginning 1) (match-end 1)))
+ "babbcaacabc")
+ "b<abbc,0,4,1,3>a<ac,0,2,1,1><abc,0,3,1,2>"))
+ ;; anchors (bug#15107, bug#44861)
+ (should (equal (replace-regexp-in-string "a\\B" "b" "a aaaa")
+ "a bbba"))
+ (should (equal (replace-regexp-in-string "\\`\\|x" "z" "--xx--")
+ "z--zz--")))
+
+(ert-deftest subr-match-substitute-replacement ()
+ (with-temp-buffer
+ (insert "Alpha Beta Gamma Delta Epsilon")
+ (goto-char (point-min))
+ (re-search-forward "B\\(..\\)a")
+ (should (equal (match-substitute-replacement "carrot")
+ "Carrot"))
+ (should (equal (match-substitute-replacement "<\\&>")
+ "<Beta>"))
+ (should (equal (match-substitute-replacement "m\\1a")
+ "Meta"))
+ (should (equal (match-substitute-replacement "ernin" nil nil nil 1)
+ "Bernina")))
+ (let ((s "Tau Beta Gamma Delta Epsilon"))
+ (string-match "B\\(..\\)a" s)
+ (should (equal (match-substitute-replacement "carrot" nil nil s)
+ "Carrot"))
+ (should (equal (match-substitute-replacement "<\\&>" nil nil s)
+ "<Beta>"))
+ (should (equal (match-substitute-replacement "m\\1a" nil nil s)
+ "Meta"))
+ (should (equal (match-substitute-replacement "ernin" nil nil s 1)
+ "Bernina"))))
+
+(ert-deftest subr-tests--change-group-33341 ()
+ (with-temp-buffer
+ (buffer-enable-undo)
+ (insert "0\n")
+ (let ((g (prepare-change-group)))
+ (activate-change-group g)
+ (insert "b\n")
+ (insert "c\n")
+ (cancel-change-group g))
+ (should (equal (buffer-string) "0\n"))
+ (erase-buffer)
+ (setq buffer-undo-list nil)
+ (insert "0\n")
+ (let ((g (prepare-change-group)))
+ (activate-change-group g)
+ (insert "b\n")
+ (insert "c\n")
+ (accept-change-group g))
+ (should (equal (buffer-string) "0\nb\nc\n"))
+ (undo-boundary)
+ (undo)
+ (should (equal (buffer-string) ""))))
+
+(defvar subr--ordered nil)
+
+(ert-deftest subr--add-to-ordered-list-eq ()
+ (setq subr--ordered nil)
+ (add-to-ordered-list 'subr--ordered 'b 2)
+ (should (equal subr--ordered '(b)))
+ (add-to-ordered-list 'subr--ordered 'c 3)
+ (should (equal subr--ordered '(b c)))
+ (add-to-ordered-list 'subr--ordered 'a 1)
+ (should (equal subr--ordered '(a b c)))
+ (add-to-ordered-list 'subr--ordered 'e)
+ (should (equal subr--ordered '(a b c e)))
+ (add-to-ordered-list 'subr--ordered 'd 4)
+ (should (equal subr--ordered '(a b c d e)))
+ (add-to-ordered-list 'subr--ordered 'e)
+ (should (equal subr--ordered '(a b c d e)))
+ (add-to-ordered-list 'subr--ordered 'b 5)
+ (should (equal subr--ordered '(a c d b e))))
+
+
+;;; Apropos.
+
+(ert-deftest apropos-apropos-internal ()
+ (should (equal (apropos-internal "^next-line$") '(next-line)))
+ (should (>= (length (apropos-internal "^help")) 100))
+ (should-not (apropos-internal "^test-a-missing-symbol-foo-bar-zot$")))
+
+(ert-deftest apropos-apropos-internal/predicate ()
+ (should (equal (apropos-internal "^next-line$" #'commandp) '(next-line)))
+ (should (>= (length (apropos-internal "^help" #'commandp)) 15))
+ (should-not (apropos-internal "^next-line$" #'keymapp)))
+
(provide 'subr-tests)
;;; subr-tests.el ends here
diff --git a/test/lisp/tar-mode-tests.el b/test/lisp/tar-mode-tests.el
index a640bb05d11..48a127157dd 100644
--- a/test/lisp/tar-mode-tests.el
+++ b/test/lisp/tar-mode-tests.el
@@ -29,7 +29,8 @@
(cons 420 "rw-r--r--")
(cons 292 "r--r--r--")
(cons 512 "--------T")
- (cons 1024 "-----S---"))))
+ (cons 1024 "-----S---")
+ (cons 2048 "--S------"))))
(dolist (x alist)
(should (equal (cdr x) (tar-grind-file-mode (car x)))))))
diff --git a/test/lisp/tempo-tests.el b/test/lisp/tempo-tests.el
index 85d6a17e25f..7594c360ad4 100644
--- a/test/lisp/tempo-tests.el
+++ b/test/lisp/tempo-tests.el
@@ -216,6 +216,45 @@
(tempo-complete-tag)
(should (equal (buffer-string) "Hello, World!"))))
+(ert-deftest tempo-define-tag-globally-test ()
+ "Testing usage of a template tag defined from another buffer."
+ (tempo-define-template "test" '("Hello, World!") "hello")
+
+ (with-temp-buffer
+ ;; Use a tag in buffer 1
+ (insert "hello")
+ (tempo-complete-tag)
+ (should (equal (buffer-string) "Hello, World!"))
+ (erase-buffer)
+
+ ;; Collection should not be dirty
+ (should-not tempo-dirty-collection)
+
+ ;; Define a tag on buffer 2
+ (with-temp-buffer
+ (tempo-define-template "test2" '("Now expanded.") "mytag"))
+
+ ;; I should be able to use this template back in buffer 1
+ (insert "mytag")
+ (tempo-complete-tag)
+ (should (equal (buffer-string) "Now expanded."))))
+
+(ert-deftest tempo-overwrite-tag-test ()
+ "Testing ability to reassign templates to tags."
+ (with-temp-buffer
+ ;; Define a tag and use it
+ (tempo-define-template "test-tag-1" '("abc") "footag")
+ (insert "footag")
+ (tempo-complete-tag)
+ (should (equal (buffer-string) "abc"))
+ (erase-buffer)
+
+ ;; Define a new template with the same tag
+ (tempo-define-template "test-tag-2" '("xyz") "footag")
+ (insert "footag")
+ (tempo-complete-tag)
+ (should (equal (buffer-string) "xyz"))))
+
(ert-deftest tempo-expand-partial-tag-test ()
"Testing expansion of a template with a tag, with a partial match."
(with-temp-buffer
diff --git a/test/lisp/textmodes/bibtex-tests.el b/test/lisp/textmodes/bibtex-tests.el
new file mode 100644
index 00000000000..010808ce48f
--- /dev/null
+++ b/test/lisp/textmodes/bibtex-tests.el
@@ -0,0 +1,57 @@
+;;; bibtex-tests.el --- Test suite for bibtex. -*- lexical-binding:t -*-
+
+;; Copyright (C) 2013-2021 Free Software Foundation, Inc.
+
+;; Keywords: bibtex
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+(require 'bibtex)
+
+(ert-deftest bibtex-test-set-dialect ()
+ "Tests if `bibtex-set-dialect' is executed."
+ (with-temp-buffer
+ (insert "@article{someID,
+ author = {some author},
+ title = {some title},
+}")
+ (bibtex-mode)
+ (should-not (null bibtex-dialect))
+ (should-not (null bibtex-entry-type))
+ (should-not (null bibtex-entry-head))
+ (should-not (null bibtex-reference-key))
+ (should-not (null bibtex-entry-head))
+ (should-not (null bibtex-entry-maybe-empty-head))
+ (should-not (null bibtex-any-valid-entry-type))))
+
+(ert-deftest bibtex-test-parse-buffers-stealthily ()
+ "Tests if `bibtex-parse-buffers-stealthily' can be executed."
+ (with-temp-buffer
+ (insert "@article{someID,
+ author = {some author},
+ title = {some title},
+}")
+ (bibtex-mode)
+ (should (progn (bibtex-parse-buffers-stealthily) t))))
+
+(provide 'bibtex-tests)
+
+;;; bibtex-tests.el ends here
diff --git a/test/lisp/textmodes/conf-mode-tests.el b/test/lisp/textmodes/conf-mode-tests.el
index aefb9328751..9c4fd1afdfe 100644
--- a/test/lisp/textmodes/conf-mode-tests.el
+++ b/test/lisp/textmodes/conf-mode-tests.el
@@ -7,18 +7,18 @@
;; This file is part of GNU Emacs.
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
@@ -162,7 +162,7 @@ image/tiff tiff tif
(ert-deftest conf-test-toml-mode ()
;; From `conf-toml-mode' docstring.
(with-temp-buffer
- (insert "\[entry]
+ (insert "[entry]
value = \"some string\"")
(goto-char (point-min))
(conf-toml-mode)
diff --git a/test/manual/indent/css-mode.css b/test/lisp/textmodes/css-mode-resources/test-indent.css
index ecf6c3c0ca5..041aeec1b15 100644
--- a/test/manual/indent/css-mode.css
+++ b/test/lisp/textmodes/css-mode-resources/test-indent.css
@@ -92,5 +92,9 @@ div::before {
.foo-bar--baz {
--foo-variable: 5px;
+ --_variable_with_underscores: #fff;
+ --_variable-starting-with-underscore: none;
margin: var(--foo-variable);
+ color: var(--_variable_with_underscores);
+ display: var(--_variable-starting-with-underscore);
}
diff --git a/test/lisp/textmodes/css-mode-tests.el b/test/lisp/textmodes/css-mode-tests.el
index a51ad690ae1..97f5abf1156 100644
--- a/test/lisp/textmodes/css-mode-tests.el
+++ b/test/lisp/textmodes/css-mode-tests.el
@@ -7,18 +7,20 @@
;; This file is part of GNU Emacs.
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
@@ -26,6 +28,7 @@
(require 'css-mode)
(require 'ert)
+(require 'ert-x)
(require 'seq)
(ert-deftest css-test-property-values ()
@@ -409,5 +412,12 @@
(point))
"black")))))
+(ert-deftest css-mode-test-indent ()
+ (with-current-buffer
+ (find-file-noselect (ert-resource-file "test-indent.css"))
+ (let ((orig (buffer-string)))
+ (indent-region (point-min) (point-max))
+ (should (equal (buffer-string) orig)))))
+
(provide 'css-mode-tests)
;;; css-mode-tests.el ends here
diff --git a/test/lisp/textmodes/mhtml-mode-tests.el b/test/lisp/textmodes/mhtml-mode-tests.el
index a630d7c937c..ad386bf1bdb 100644
--- a/test/lisp/textmodes/mhtml-mode-tests.el
+++ b/test/lisp/textmodes/mhtml-mode-tests.el
@@ -1,4 +1,4 @@
-;;; mhtml-mode-tests.el --- Tests for mhtml-mode
+;;; mhtml-mode-tests.el --- Tests for mhtml-mode -*- lexical-binding:t -*-
;; Copyright (C) 2017-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/textmodes/paragraphs-tests.el b/test/lisp/textmodes/paragraphs-tests.el
index 655c62d815a..bf7f37090f5 100644
--- a/test/lisp/textmodes/paragraphs-tests.el
+++ b/test/lisp/textmodes/paragraphs-tests.el
@@ -50,8 +50,8 @@
(goto-char (point-min))
(mark-paragraph)
(should mark-active)
- (should (equal (mark) 7)))
- (should-error (mark-paragraph 0)))
+ (should (equal (mark) 7))))
+;;; (should-error (mark-paragraph 0)))
(ert-deftest paragraphs-tests-kill-paragraph ()
(with-temp-buffer
diff --git a/test/lisp/textmodes/po-tests.el b/test/lisp/textmodes/po-tests.el
new file mode 100644
index 00000000000..c75cb5eae74
--- /dev/null
+++ b/test/lisp/textmodes/po-tests.el
@@ -0,0 +1,68 @@
+;;; po-tests.el --- Tests for po.el -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+;; Author: Simen Heggestøyl <simenheg@gmail.com>
+;; Keywords:
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'po)
+(require 'ert)
+
+(defconst po-tests--buffer-string
+ "# Norwegian bokmål translation of the GIMP.
+# Copyright (C) 1999-2001 Free Software Foundation, Inc.
+#
+msgid \"\"
+msgstr \"\"
+\"Project-Id-Version: gimp 2.8.5\\n\"
+\"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gimp/issues\\n\"
+\"POT-Creation-Date: 2013-05-27 14:57+0200\\n\"
+\"PO-Revision-Date: 2013-05-27 15:21+0200\\n\"
+\"Language: nb\\n\"
+\"MIME-Version: 1.0\\n\"
+\"Content-Type: text/plain; charset=UTF-8\\n\"
+\"Content-Transfer-Encoding: 8bit\\n\"
+\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"
+
+#: ../desktop/gimp.desktop.in.in.h:1 ../app/about.h:26
+msgid \"GNU Image Manipulation Program\"
+msgstr \"GNU bildebehandlingsprogram\"
+")
+
+(ert-deftest po-tests-find-charset ()
+ (with-temp-buffer
+ (insert po-tests--buffer-string)
+ (should (equal (po-find-charset (cons nil (current-buffer)))
+ "UTF-8"))))
+
+(ert-deftest po-tests-find-file-coding-system-guts ()
+ (with-temp-buffer
+ (insert po-tests--buffer-string)
+ (should (equal (po-find-file-coding-system-guts
+ 'insert-file-contents
+ (cons "*tmp*" (current-buffer)))
+ '(utf-8 . nil)))))
+
+(provide 'po-tests)
+;;; po-tests.el ends here
diff --git a/test/lisp/textmodes/reftex-tests.el b/test/lisp/textmodes/reftex-tests.el
index 4e046667b8a..b824e05f6d5 100644
--- a/test/lisp/textmodes/reftex-tests.el
+++ b/test/lisp/textmodes/reftex-tests.el
@@ -153,24 +153,23 @@
edition = {17th},
note = {Updated for Emacs Version 24.2}
}")
- (check (function
- (lambda (parsed)
- (should (string= (reftex-get-bib-field "&key" parsed)
- "Stallman12"))
- (should (string= (reftex-get-bib-field "&type" parsed)
- "book"))
- (should (string= (reftex-get-bib-field "author" parsed)
- "Richard Stallman et al."))
- (should (string= (reftex-get-bib-field "title" parsed)
- "The Emacs Editor"))
- (should (string= (reftex-get-bib-field "publisher" parsed)
- "GNU Press"))
- (should (string= (reftex-get-bib-field "year" parsed)
- "2012"))
- (should (string= (reftex-get-bib-field "edition" parsed)
- "17th"))
- (should (string= (reftex-get-bib-field "note" parsed)
- "Updated for Emacs Version 24.2"))))))
+ (check (lambda (parsed)
+ (should (string= (reftex-get-bib-field "&key" parsed)
+ "Stallman12"))
+ (should (string= (reftex-get-bib-field "&type" parsed)
+ "book"))
+ (should (string= (reftex-get-bib-field "author" parsed)
+ "Richard Stallman et al."))
+ (should (string= (reftex-get-bib-field "title" parsed)
+ "The Emacs Editor"))
+ (should (string= (reftex-get-bib-field "publisher" parsed)
+ "GNU Press"))
+ (should (string= (reftex-get-bib-field "year" parsed)
+ "2012"))
+ (should (string= (reftex-get-bib-field "edition" parsed)
+ "17th"))
+ (should (string= (reftex-get-bib-field "note" parsed)
+ "Updated for Emacs Version 24.2")))))
(funcall check (reftex-parse-bibtex-entry entry))
(with-temp-buffer
(insert entry)
diff --git a/test/lisp/textmodes/sgml-mode-tests.el b/test/lisp/textmodes/sgml-mode-tests.el
index 16feee57884..697c96c78e5 100644
--- a/test/lisp/textmodes/sgml-mode-tests.el
+++ b/test/lisp/textmodes/sgml-mode-tests.el
@@ -1,4 +1,4 @@
-;;; sgml-mode-tests.el --- Tests for sgml-mode
+;;; sgml-mode-tests.el --- Tests for sgml-mode -*- lexical-binding:t -*-
;; Copyright (C) 2015-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/thingatpt-tests.el b/test/lisp/thingatpt-tests.el
index 409cc867265..c43c81af9fd 100644
--- a/test/lisp/thingatpt-tests.el
+++ b/test/lisp/thingatpt-tests.el
@@ -1,4 +1,4 @@
-;;; thingatpt.el --- tests for thing-at-point.
+;;; thingatpt.el --- tests for thing-at-point. -*- lexical-binding:t -*-
;; Copyright (C) 2013-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/time-resources/non-empty b/test/lisp/time-resources/non-empty
new file mode 100644
index 00000000000..86f5704d8ee
--- /dev/null
+++ b/test/lisp/time-resources/non-empty
@@ -0,0 +1 @@
+This file should be non-empty.
diff --git a/test/lisp/time-stamp-tests.el b/test/lisp/time-stamp-tests.el
index eba732ae0da..81488c3df19 100644
--- a/test/lisp/time-stamp-tests.el
+++ b/test/lisp/time-stamp-tests.el
@@ -38,9 +38,7 @@
(cl-letf (((symbol-function 'time-stamp-conv-warn)
(lambda (old-format _new)
(ert-fail
- (format "Unexpected format warning for '%s'" old-format))))
- ((symbol-function 'system-name)
- (lambda () "test-system-name.example.org")))
+ (format "Unexpected format warning for '%s'" old-format)))))
;; Not all reference times are used in all tests;
;; suppress the byte compiler's "unused" warning.
(list ref-time1 ref-time2 ref-time3)
@@ -56,6 +54,13 @@
(apply orig-time-stamp-string-fn ts-format ,reference-time nil))))
,@body))
+(defmacro with-time-stamp-system-name (name &rest body)
+ "Force (system-name) to return NAME while evaluating BODY."
+ (declare (indent defun))
+ `(cl-letf (((symbol-function 'system-name)
+ (lambda () ,name)))
+ ,@body))
+
(defmacro time-stamp-should-warn (form)
"Similar to `should' but verifies that a format warning is generated."
`(let ((warning-count 0))
@@ -170,6 +175,20 @@
;; triggering the tests above.
(time-stamp)))))))
+(ert-deftest time-stamp-custom-format-tabs-expand ()
+ "Test that Tab characters expand in the format but not elsewhere."
+ (with-time-stamp-test-env
+ (let ((time-stamp-start "Updated in: <\t")
+ ;; Tabs in the format should expand
+ (time-stamp-format "\t%Y\t")
+ (time-stamp-end "\t>"))
+ (with-time-stamp-test-time ref-time1
+ (with-temp-buffer
+ (insert "Updated in: <\t\t>")
+ (time-stamp)
+ (should (equal (buffer-string)
+ "Updated in: <\t 2006 \t>")))))))
+
(ert-deftest time-stamp-custom-inserts-lines ()
"Test that time-stamp inserts lines or not, as directed."
(with-time-stamp-test-env
@@ -194,19 +213,46 @@
(time-stamp)
(should (equal (buffer-string) buffer-expected-2line)))))))
+(ert-deftest time-stamp-custom-end ()
+ "Test that time-stamp finds the end pattern on the correct line."
+ (with-time-stamp-test-env
+ (let ((time-stamp-start "Updated on: <")
+ (time-stamp-format "%Y-%m-%d")
+ (time-stamp-end ">") ;changed later in the test
+ (buffer-original-contents "Updated on: <\n>\n")
+ (buffer-expected-time-stamped "Updated on: <2006-01-02\n>\n"))
+ (with-time-stamp-test-time ref-time1
+ (with-temp-buffer
+ (insert buffer-original-contents)
+ ;; time-stamp-end is not on same line, should not be seen
+ (time-stamp)
+ (should (equal (buffer-string) buffer-original-contents))
+
+ ;; add a newline to time-stamp-end, so it starts on same line
+ (setq time-stamp-end "\n>")
+ (time-stamp)
+ (should (equal (buffer-string) buffer-expected-time-stamped)))))))
+
(ert-deftest time-stamp-custom-count ()
"Test that time-stamp updates no more than time-stamp-count templates."
(with-time-stamp-test-env
(let ((time-stamp-start "TS: <")
(time-stamp-format "%Y-%m-%d")
- (time-stamp-count 1) ;changed later in the test
+ (time-stamp-count 0) ;changed later in the test
(buffer-expected-once "TS: <2006-01-02>\nTS: <>")
(buffer-expected-twice "TS: <2006-01-02>\nTS: <2006-01-02>"))
(with-time-stamp-test-time ref-time1
(with-temp-buffer
(insert "TS: <>\nTS: <>")
(time-stamp)
+ ;; even with count = 0, expect one time stamp
+ (should (equal (buffer-string) buffer-expected-once)))
+ (with-temp-buffer
+ (setq time-stamp-count 1)
+ (insert "TS: <>\nTS: <>")
+ (time-stamp)
(should (equal (buffer-string) buffer-expected-once))
+
(setq time-stamp-count 2)
(time-stamp)
(should (equal (buffer-string) buffer-expected-twice)))))))
@@ -488,26 +534,35 @@
(ert-deftest time-stamp-format-non-date-conversions ()
"Test time-stamp formats for non-date items."
(with-time-stamp-test-env
- ;; implemented and documented since 1995
- (should (equal (time-stamp-string "%%" ref-time1) "%")) ;% last char
- (should (equal (time-stamp-string "%%P" ref-time1) "%P")) ;% not last char
- (should (equal (time-stamp-string "%f" ref-time1) "time-stamped-file"))
- (should
- (equal (time-stamp-string "%F" ref-time1) "/emacs/test/time-stamped-file"))
- (should (equal (time-stamp-string "%h" ref-time1) "test-mail-host-name"))
- ;; documented 1995-2019
- (should (equal
- (time-stamp-string "%s" ref-time1) "test-system-name.example.org"))
- (should (equal (time-stamp-string "%U" ref-time1) "100%d Tester"))
- (should (equal (time-stamp-string "%u" ref-time1) "test-logname"))
- ;; implemented since 2001, documented since 2019
- (should (equal (time-stamp-string "%L" ref-time1) "100%d Tester"))
- (should (equal (time-stamp-string "%l" ref-time1) "test-logname"))
- ;; implemented since 2007, documented since 2019
- (should (equal
- (time-stamp-string "%Q" ref-time1) "test-system-name.example.org"))
- (should (equal
- (time-stamp-string "%q" ref-time1) "test-system-name"))))
+ (with-time-stamp-system-name "test-system-name.example.org"
+ ;; implemented and documented since 1995
+ (should (equal (time-stamp-string "%%" ref-time1) "%")) ;% last char
+ (should (equal (time-stamp-string "%%P" ref-time1) "%P")) ;% not last char
+ (should (equal (time-stamp-string "%f" ref-time1) "time-stamped-file"))
+ (should (equal (time-stamp-string "%F" ref-time1)
+ "/emacs/test/time-stamped-file"))
+ (with-temp-buffer
+ (should (equal (time-stamp-string "%f" ref-time1) "(no file)"))
+ (should (equal (time-stamp-string "%F" ref-time1) "(no file)")))
+ (should (equal (time-stamp-string "%h" ref-time1) "test-mail-host-name"))
+ (let ((mail-host-address nil))
+ (should (equal (time-stamp-string "%h" ref-time1)
+ "test-system-name.example.org")))
+ ;; documented 1995-2019
+ (should (equal (time-stamp-string "%s" ref-time1)
+ "test-system-name.example.org"))
+ (should (equal (time-stamp-string "%U" ref-time1) "100%d Tester"))
+ (should (equal (time-stamp-string "%u" ref-time1) "test-logname"))
+ ;; implemented since 2001, documented since 2019
+ (should (equal (time-stamp-string "%L" ref-time1) "100%d Tester"))
+ (should (equal (time-stamp-string "%l" ref-time1) "test-logname"))
+ ;; implemented since 2007, documented since 2019
+ (should (equal (time-stamp-string "%Q" ref-time1)
+ "test-system-name.example.org"))
+ (should (equal (time-stamp-string "%q" ref-time1) "test-system-name")))
+ (with-time-stamp-system-name "sysname-no-dots"
+ (should (equal (time-stamp-string "%Q" ref-time1) "sysname-no-dots"))
+ (should (equal (time-stamp-string "%q" ref-time1) "sysname-no-dots")))))
(ert-deftest time-stamp-format-ignored-modifiers ()
"Test additional args allowed (but ignored) to allow for future expansion."
@@ -538,6 +593,13 @@
;;; Tests of helper functions
+(ert-deftest time-stamp-helper-string-defaults ()
+ "Test that time-stamp-string defaults its format to time-stamp-format."
+ (with-time-stamp-test-env
+ (should (equal (time-stamp-string nil ref-time1)
+ (time-stamp-string time-stamp-format ref-time1)))
+ (should (equal (time-stamp-string 'not-a-string ref-time1) nil))))
+
(ert-deftest time-stamp-helper-zone-type-p ()
"Test time-stamp-zone-type-p."
(should (time-stamp-zone-type-p t))
diff --git a/test/lisp/time-tests.el b/test/lisp/time-tests.el
new file mode 100644
index 00000000000..3cf8b540cbc
--- /dev/null
+++ b/test/lisp/time-tests.el
@@ -0,0 +1,79 @@
+;;; time-tests.el --- Tests for time.el -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+;; Author: Stefan Kangas <stefankangas@gmail.com>
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+(require 'ert)
+(require 'ert-x)
+(require 'time)
+
+(ert-deftest time-tests-display-time-mail-check-directory ()
+ (let ((display-time-mail-directory (ert-resource-directory)))
+ (should (display-time-mail-check-directory))))
+
+(ert-deftest time-tests-display-time-update--load ()
+ (let ((display-time-load-average 1)
+ (display-time-load-average-threshold 0))
+ (display-time-next-load-average)
+ (should (string-match (rx string-start " "
+ (+ (| digit "."))
+ string-end)
+ (display-time-update--load))))
+ (let (display-time-load-average)
+ (should (equal (display-time-update--load) ""))))
+
+(ert-deftest time-tests-display-time-update ()
+ (let ((display-time-load-average 1)
+ (display-time-load-average-threshold 0)
+ display-time-string)
+ (display-time-update)
+ (should (string-match (rx string-start
+ (? digit) digit ":" digit digit
+ (? (| "AM" "PM"))
+ " " (+ (| digit "."))
+ (? " Mail")
+ string-end)
+ display-time-string))))
+
+(ert-deftest time-tests-display-time-file-nonempty-p ()
+ (should (display-time-file-nonempty-p (ert-resource-file "non-empty")))
+ (should-not (display-time-file-nonempty-p "/non/existent")))
+
+(ert-deftest time-tests-world-clock ()
+ (save-window-excursion
+ (world-clock)
+ (should (equal (buffer-name) world-clock-buffer-name))
+ (should (string-match "New York" (buffer-string)))))
+
+(ert-deftest time-tests-world-clock/revert-buffer-works ()
+ (save-window-excursion
+ (world-clock)
+ (revert-buffer)
+ (should (string-match "New York" (buffer-string)))))
+
+(ert-deftest time-tests-emacs-uptime ()
+ (should (string-match "^[0-9.]+ seconds?$" (emacs-uptime "%S"))))
+
+(ert-deftest time-tests-emacs-init-time ()
+ (should (string-match "^[0-9.]+ seconds?$" (emacs-init-time))))
+
+(provide 'time-tests)
+;;; time-tests.el ends here
diff --git a/test/lisp/url/url-auth-tests.el b/test/lisp/url/url-auth-tests.el
index 6bb65243dbe..ff30f100250 100644
--- a/test/lisp/url/url-auth-tests.el
+++ b/test/lisp/url/url-auth-tests.el
@@ -1,4 +1,4 @@
-;;; url-auth-tests.el --- Test suite for url-auth.
+;;; url-auth-tests.el --- Test suite for url-auth. -*- lexical-binding:t -*-
;; Copyright (C) 2015-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/url/url-domsuf-tests.el b/test/lisp/url/url-domsuf-tests.el
new file mode 100644
index 00000000000..d084c7a8bcb
--- /dev/null
+++ b/test/lisp/url/url-domsuf-tests.el
@@ -0,0 +1,51 @@
+;;; url-domsuf-tests.el --- Tests for url-domsuf.el -*- lexical-binding:t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'url-domsuf)
+(require 'ert)
+
+(defun url-domsuf-tests--run ()
+ (should-not (url-domsuf-cookie-allowed-p "com"))
+ (should (url-domsuf-cookie-allowed-p "foo.bar.bd"))
+ (should-not (url-domsuf-cookie-allowed-p "bar.bd"))
+ (should-not (url-domsuf-cookie-allowed-p "co.uk"))
+ (should (url-domsuf-cookie-allowed-p "foo.bar.hokkaido.jo"))
+ (should-not (url-domsuf-cookie-allowed-p "bar.yokohama.jp"))
+ (should (url-domsuf-cookie-allowed-p "city.yokohama.jp")))
+
+(ert-deftest url-domsuf-test-cookie-allowed-p ()
+ "Run the domsuf tests without need for parsing a file."
+ (let ((url-domsuf-domains '(("com")
+ ("bar.bd")
+ ("co.uk")
+ ("bar.yokohama.jp"))))
+ (url-domsuf-tests--run)))
+
+(ert-deftest url-domsuf-test-cookie-allowed-p/and-parse ()
+ "Run the domsuf tests, but also parse the file."
+ :tags '(:expensive-test)
+ (url-domsuf-tests--run))
+
+(provide 'url-domsuf-tests)
+
+;;; url-domsuf-tests.el ends here
diff --git a/test/lisp/url/url-expand-tests.el b/test/lisp/url/url-expand-tests.el
index 8c3cbe7bfa1..52124dfedd8 100644
--- a/test/lisp/url/url-expand-tests.el
+++ b/test/lisp/url/url-expand-tests.el
@@ -1,4 +1,4 @@
-;;; url-expand-tests.el --- Test suite for relative URI/URL resolution.
+;;; url-expand-tests.el --- Test suite for relative URI/URL resolution. -*- lexical-binding:t -*-
;; Copyright (C) 2012-2021 Free Software Foundation, Inc.
@@ -100,6 +100,13 @@
(should (equal (url-expand-file-name "foo#bar" "http://host/foobar") "http://host/foo#bar"))
(should (equal (url-expand-file-name "foo#bar" "http://host/foobar/") "http://host/foobar/foo#bar")))
+(ert-deftest url-expand-file-name/relative-resolution-file-url ()
+ "RFC 3986, Section 5.4 Reference Resolution Examples / Section 5.4.1. Normal Examples"
+ (should (equal (url-expand-file-name "bar.html" "file:///a/b/c/foo.html") "file:///a/b/c/bar.html"))
+ (should (equal (url-expand-file-name "bar.html" "file:///a/b/c/") "file:///a/b/c/bar.html"))
+ (should (equal (url-expand-file-name "../d/bar.html" "file:///a/b/c/") "file:///a/b/d/bar.html"))
+ (should (equal (url-expand-file-name "../d/bar.html" "file:///a/b/c/foo.html") "file:///a/b/d/bar.html")))
+
(provide 'url-expand-tests)
;;; url-expand-tests.el ends here
diff --git a/test/lisp/url/url-file-tests.el b/test/lisp/url/url-file-tests.el
index c3eef39d5ef..18365c79693 100644
--- a/test/lisp/url/url-file-tests.el
+++ b/test/lisp/url/url-file-tests.el
@@ -23,18 +23,11 @@
(require 'url-file)
(require 'ert)
-
-(defconst url-file-tests-data-directory
- (expand-file-name "lisp/url/url-file-resources"
- (or (getenv "EMACS_TEST_DIRECTORY")
- (expand-file-name "../../.."
- (or load-file-name
- buffer-file-name))))
- "Directory for url-file test files.")
+(require 'ert-x)
(ert-deftest url-file ()
"Test reading file via file:/// URL."
- (let* ((file (expand-file-name "file.txt" url-file-tests-data-directory))
+ (let* ((file (ert-resource-file "file.txt"))
(uri-prefix (if (eq (aref file 0) ?/) "file://" "file:///")))
(should (equal
(with-current-buffer
diff --git a/test/lisp/url/url-future-tests.el b/test/lisp/url/url-future-tests.el
index 3fda82e616e..8b0e20c4dde 100644
--- a/test/lisp/url/url-future-tests.el
+++ b/test/lisp/url/url-future-tests.el
@@ -1,4 +1,4 @@
-;;; url-future-tests.el --- Test suite for url-future.
+;;; url-future-tests.el --- Test suite for url-future. -*- lexical-binding:t -*-
;; Copyright (C) 2011-2021 Free Software Foundation, Inc.
@@ -25,31 +25,33 @@
(require 'ert)
(require 'url-future)
+(defvar url-future-tests--saver)
+
(ert-deftest url-future-tests ()
- (let* (saver
+ (let* (url-future-tests--saver
(text "running future")
(good (make-url-future :value (lambda () (format text))
- :callback (lambda (f) (set 'saver f))))
+ :callback (lambda (f) (setq url-future-tests--saver f))))
(bad (make-url-future :value (lambda () (/ 1 0))
- :errorback (lambda (&rest d) (set 'saver d))))
+ :errorback (lambda (&rest d) (setq url-future-tests--saver d))))
(tocancel (make-url-future :value (lambda () (/ 1 0))
- :callback (lambda (f) (set 'saver f))
+ :callback (lambda (f) (setq url-future-tests--saver f))
:errorback (lambda (&rest d)
- (set 'saver d)))))
+ (setq url-future-tests--saver d)))))
(should (equal good (url-future-call good)))
- (should (equal good saver))
+ (should (equal good url-future-tests--saver))
(should (equal text (url-future-value good)))
(should (url-future-completed-p good))
(should-error (url-future-call good))
- (setq saver nil)
+ (setq url-future-tests--saver nil)
(should (equal bad (url-future-call bad)))
(should-error (url-future-call bad))
- (should (equal saver (list bad '(arith-error))))
+ (should (equal url-future-tests--saver (list bad '(arith-error))))
(should (url-future-errored-p bad))
- (setq saver nil)
+ (setq url-future-tests--saver nil)
(should (equal (url-future-cancel tocancel) tocancel))
(should-error (url-future-call tocancel))
- (should (null saver))
+ (should (null url-future-tests--saver))
(should (url-future-cancelled-p tocancel))))
(provide 'url-future-tests)
diff --git a/test/lisp/url/url-handlers-test.el b/test/lisp/url/url-handlers-test.el
index 0816d490031..7e5a60363da 100644
--- a/test/lisp/url/url-handlers-test.el
+++ b/test/lisp/url/url-handlers-test.el
@@ -4,18 +4,20 @@
;; Author: Nicolas Petton <nicolas@petton.fr>
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
diff --git a/test/lisp/url/url-parse-tests.el b/test/lisp/url/url-parse-tests.el
index ddb86a42382..2418af40aca 100644
--- a/test/lisp/url/url-parse-tests.el
+++ b/test/lisp/url/url-parse-tests.el
@@ -1,4 +1,4 @@
-;;; url-parse-tests.el --- Test suite for URI/URL parsing.
+;;; url-parse-tests.el --- Test suite for URI/URL parsing. -*- lexical-binding:t -*-
;; Copyright (C) 2012-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/url/url-tramp-tests.el b/test/lisp/url/url-tramp-tests.el
index f657c13259e..63d752ac3a0 100644
--- a/test/lisp/url/url-tramp-tests.el
+++ b/test/lisp/url/url-tramp-tests.el
@@ -1,4 +1,4 @@
-;;; url-tramp-tests.el --- Test suite for Tramp / URL conversion.
+;;; url-tramp-tests.el --- Test suite for Tramp / URL conversion. -*- lexical-binding:t -*-
;; Copyright (C) 2017-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/url/url-util-tests.el b/test/lisp/url/url-util-tests.el
index 963e4a62178..57b67a04ccf 100644
--- a/test/lisp/url/url-util-tests.el
+++ b/test/lisp/url/url-util-tests.el
@@ -1,4 +1,4 @@
-;;; url-util-tests.el --- Test suite for url-util.
+;;; url-util-tests.el --- Test suite for url-util. -*- lexical-binding:t -*-
;; Copyright (C) 2012-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/vc/add-log-tests.el b/test/lisp/vc/add-log-tests.el
index 40d633c9fff..dc2b9961c6c 100644
--- a/test/lisp/vc/add-log-tests.el
+++ b/test/lisp/vc/add-log-tests.el
@@ -1,4 +1,4 @@
-;;; add-log-tests.el --- Test suite for add-log.
+;;; add-log-tests.el --- Test suite for add-log. -*- lexical-binding:t -*-
;; Copyright (C) 2013-2021 Free Software Foundation, Inc.
@@ -25,12 +25,12 @@
(require 'ert)
(require 'add-log)
-(defmacro add-log-current-defun-deftest (name doc major-mode
+(defmacro add-log-current-defun-deftest (name doc mode
content marker expected-defun)
"Generate an ert test for mode-own `add-log-current-defun-function'.
-Run `add-log-current-defun' at the point where MARKER specifies in a
-buffer which content is CONTENT under MAJOR-MODE. Then it compares the
-result with EXPECTED-DEFUN."
+Run `add-log-current-defun' at the point where MARKER specifies
+in a buffer which content is CONTENT under major mode MODE. Then
+it compares the result with EXPECTED-DEFUN."
(let ((xname (intern (concat "add-log-current-defun-test-"
(symbol-name name)
))))
@@ -39,7 +39,7 @@ result with EXPECTED-DEFUN."
(with-temp-buffer
(insert ,content)
(goto-char (point-min))
- (funcall ',major-mode)
+ (funcall ',mode)
(should (equal (when (search-forward ,marker nil t)
(replace-match "" nil t)
(add-log-current-defun))
diff --git a/test/data/vc/diff-mode/hello_emacs.c b/test/lisp/vc/diff-mode-resources/hello_emacs.c
index c7ed7538c3a..c7ed7538c3a 100644
--- a/test/data/vc/diff-mode/hello_emacs.c
+++ b/test/lisp/vc/diff-mode-resources/hello_emacs.c
diff --git a/test/data/vc/diff-mode/hello_emacs_1.c b/test/lisp/vc/diff-mode-resources/hello_emacs_1.c
index 62145a6b44a..62145a6b44a 100644
--- a/test/data/vc/diff-mode/hello_emacs_1.c
+++ b/test/lisp/vc/diff-mode-resources/hello_emacs_1.c
diff --git a/test/data/vc/diff-mode/hello_world.c b/test/lisp/vc/diff-mode-resources/hello_world.c
index dcbe06c6012..dcbe06c6012 100644
--- a/test/data/vc/diff-mode/hello_world.c
+++ b/test/lisp/vc/diff-mode-resources/hello_world.c
diff --git a/test/data/vc/diff-mode/hello_world_1.c b/test/lisp/vc/diff-mode-resources/hello_world_1.c
index 606afb371cb..606afb371cb 100644
--- a/test/data/vc/diff-mode/hello_world_1.c
+++ b/test/lisp/vc/diff-mode-resources/hello_world_1.c
diff --git a/test/lisp/vc/diff-mode-tests.el b/test/lisp/vc/diff-mode-tests.el
index 2e13fdbcf9d..f4e5c89afb4 100644
--- a/test/lisp/vc/diff-mode-tests.el
+++ b/test/lisp/vc/diff-mode-tests.el
@@ -1,3 +1,5 @@
+;;; diff-mode-tests.el --- Tests for diff-mode.el -*- lexical-binding:t -*-
+
;; Copyright (C) 2017-2021 Free Software Foundation, Inc.
;; Author: Dima Kogan <dima@secretsauce.net>
@@ -20,12 +22,11 @@
;;; Code:
+(require 'ert)
+(require 'ert-x)
(require 'diff-mode)
(require 'diff)
-(defconst diff-mode-tests--datadir
- (expand-file-name "test/data/vc/diff-mode" source-directory))
-
(ert-deftest diff-mode-test-ignore-trailing-dashes ()
"Check to make sure we successfully ignore trailing -- made by
'git format-patch'. This is bug #9597"
@@ -204,9 +205,14 @@ youthfulness
(ert-deftest diff-mode-test-font-lock ()
"Check font-locking of diff hunks."
+ ;; See comments in diff-hunk-file-names about nonascii.
+ ;; In such cases, the diff-font-lock-syntax portion of this fails.
+ :expected-result (if (string-match-p "[[:nonascii:]]"
+ (ert-resource-directory))
+ :failed :passed)
(skip-unless (executable-find shell-file-name))
(skip-unless (executable-find diff-command))
- (let ((default-directory diff-mode-tests--datadir)
+ (let ((default-directory (ert-resource-directory))
(old "hello_world.c")
(new "hello_emacs.c")
(diff-buffer (get-buffer-create "*Diff*"))
@@ -242,6 +248,7 @@ youthfulness
111 124 (face diff-context)
124 127 (face diff-context))))
+ ;; Test diff-font-lock-syntax.
(should (equal (mapcar (lambda (o)
(list (- (overlay-start o) diff-beg)
(- (overlay-end o) diff-beg)
@@ -265,9 +272,12 @@ youthfulness
(ert-deftest diff-mode-test-font-lock-syntax-one-line ()
"Check diff syntax highlighting for one line with no newline at end."
+ :expected-result (if (string-match-p "[[:nonascii:]]"
+ (ert-resource-directory))
+ :failed :passed)
(skip-unless (executable-find shell-file-name))
(skip-unless (executable-find diff-command))
- (let ((default-directory diff-mode-tests--datadir)
+ (let ((default-directory (ert-resource-directory))
(old "hello_world_1.c")
(new "hello_emacs_1.c")
(diff-buffer (get-buffer-create "*Diff*"))
diff --git a/test/lisp/vc/ediff-ptch-tests.el b/test/lisp/vc/ediff-ptch-tests.el
index 11dd235f8bf..a464db2349d 100644
--- a/test/lisp/vc/ediff-ptch-tests.el
+++ b/test/lisp/vc/ediff-ptch-tests.el
@@ -1,21 +1,23 @@
-;;; ediff-ptch-tests.el --- Tests for ediff-ptch.el
+;;; ediff-ptch-tests.el --- Tests for ediff-ptch.el -*- lexical-binding:t -*-
;; Copyright (C) 2016-2021 Free Software Foundation, Inc.
;; Author: Tino Calancha <tino.calancha@gmail.com>
-;; This program is free software: you can redistribute it and/or
+;; 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.
;;
-;; This program is distributed in the hope that it will be useful, but
+;; 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 `https://www.gnu.org/licenses/'.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Code:
diff --git a/test/lisp/vc/smerge-mode-tests.el b/test/lisp/vc/smerge-mode-tests.el
index bd1c0ad7f23..2c8f48618e5 100644
--- a/test/lisp/vc/smerge-mode-tests.el
+++ b/test/lisp/vc/smerge-mode-tests.el
@@ -1,3 +1,5 @@
+;;; smerge-mode-tests.el --- Tests for smerge-mode.el -*- lexical-binding:t -*-
+
;; Copyright (C) 2017-2021 Free Software Foundation, Inc.
;; Maintainer: emacs-devel@gnu.org
diff --git a/test/lisp/vc/vc-bzr-tests.el b/test/lisp/vc/vc-bzr-tests.el
index 7632717bd32..aeab51ec261 100644
--- a/test/lisp/vc/vc-bzr-tests.el
+++ b/test/lisp/vc/vc-bzr-tests.el
@@ -1,4 +1,4 @@
-;;; vc-bzr.el --- tests for vc/vc-bzr.el
+;;; vc-bzr.el --- tests for vc/vc-bzr.el -*- lexical-binding: t -*-
;; Copyright (C) 2011-2021 Free Software Foundation, Inc.
@@ -37,7 +37,7 @@
;; commands (eg `bzr status') want to access ~/.bazaar, and will
;; abort if they cannot. I could not figure out how to stop bzr
;; doing that, so just give it a temporary homedir for the duration.
- ;; http://bugs.launchpad.net/bzr/+bug/137407 ?
+ ;; https://bugs.launchpad.net/bzr/+bug/137407 ?
;;
;; Note that with bzr 2.x, this works:
;; mkdir /tmp/bzr
@@ -131,7 +131,6 @@
(make-directory bzrdir)
(expand-file-name "foo.el" bzrdir)))
(default-directory (file-name-as-directory bzrdir))
- (generated-autoload-file (expand-file-name "loaddefs.el" bzrdir))
(process-environment (cons (format "HOME=%s" homedir)
process-environment)))
(unwind-protect
@@ -148,7 +147,9 @@
;; causes bzr status to fail. This simulates a broken bzr
;; installation.
(delete-file ".bzr/checkout/dirstate")
- (should (progn (update-directory-autoloads default-directory)
+ (should (progn (make-directory-autoloads
+ default-directory
+ (expand-file-name "loaddefs.el" bzrdir))
t)))
(delete-directory homedir t))))
diff --git a/test/lisp/vc/vc-hg-tests.el b/test/lisp/vc/vc-hg-tests.el
index 457ac09b038..2edd4b6fd71 100644
--- a/test/lisp/vc/vc-hg-tests.el
+++ b/test/lisp/vc/vc-hg-tests.el
@@ -1,4 +1,4 @@
-;;; vc-hg-tests.el --- tests for vc/vc-hg.el
+;;; vc-hg-tests.el --- tests for vc/vc-hg.el -*- lexical-binding:t -*-
;; Copyright (C) 2016-2021 Free Software Foundation, Inc.
diff --git a/test/lisp/vc/vc-tests.el b/test/lisp/vc/vc-tests.el
index 1389ccd1432..5430535c5ed 100644
--- a/test/lisp/vc/vc-tests.el
+++ b/test/lisp/vc/vc-tests.el
@@ -1,21 +1,23 @@
-;;; vc-tests.el --- Tests of different backends of vc.el
+;;; vc-tests.el --- Tests of different backends of vc.el -*- lexical-binding:t -*-
;; Copyright (C) 2014-2021 Free Software Foundation, Inc.
;; Author: Michael Albinus <michael.albinus@gmx.de>
-;; This program is free software: you can redistribute it and/or
+;; 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.
;;
-;; This program is distributed in the hope that it will be useful, but
+;; 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 `https://www.gnu.org/licenses/'.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
@@ -224,11 +226,10 @@ For backends which don't support it, `vc-not-supported' is signaled."
(defmacro vc-test--run-maybe-unsupported-function (func &rest args)
"Run FUNC with ARGS as arguments.
Catch the `vc-not-supported' error."
- `(let (err)
- (condition-case err
- (funcall ,func ,@args)
- (vc-not-supported 'vc-not-supported)
- (t (signal (car err) (cdr err))))))
+ `(condition-case err
+ (funcall ,func ,@args)
+ (vc-not-supported 'vc-not-supported)
+ (t (signal (car err) (cdr err)))))
(defun vc-test--register (backend)
"Register and unregister a file.
@@ -438,8 +439,9 @@ This checks also `vc-backend' and `vc-responsible-backend'."
;; nil: Git Mtn
;; "0": Bzr CVS Hg SRC SVN
;; "1.1": RCS SCCS
+ ;; "-1": Hg versions before 5 (probably)
(message "vc-working-revision4 %s" (vc-working-revision tmp-name))
- (should (member (vc-working-revision tmp-name) '(nil "0" "1.1")))
+ (should (member (vc-working-revision tmp-name) '(nil "0" "1.1" "-1")))
;; TODO: Call `vc-checkin', and check the resulting
;; working revision. None of the return values should be
@@ -555,7 +557,8 @@ This checks also `vc-backend' and `vc-responsible-backend'."
(defvar vc-svn-program)
(defun vc-test--svn-enabled ()
- (executable-find vc-svn-program))
+ (and (executable-find "svnadmin")
+ (executable-find vc-svn-program)))
(defun vc-test--sccs-enabled ()
(executable-find "sccs"))
diff --git a/test/lisp/version-tests.el b/test/lisp/version-tests.el
new file mode 100644
index 00000000000..ef2e9453052
--- /dev/null
+++ b/test/lisp/version-tests.el
@@ -0,0 +1,31 @@
+;;; version-tests.el --- Tests for version.el -*- lexical-binding: t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+
+(ert-deftest test-emacs-version ()
+ (should (string-match emacs-version (emacs-version)))
+ (should (string-match system-configuration (emacs-version))))
+
+(provide 'version-tests)
+;;; version-tests.el ends here
diff --git a/test/lisp/wdired-tests.el b/test/lisp/wdired-tests.el
index ee22bf888a8..ba276e24d96 100644
--- a/test/lisp/wdired-tests.el
+++ b/test/lisp/wdired-tests.el
@@ -4,18 +4,18 @@
;; This file is part of GNU Emacs.
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Code:
@@ -106,7 +106,6 @@ only the name before the link arrow."
"Test editing a file name without saving the change.
Finding the new name should be possible while still in
wdired-mode."
- :expected-result (if (< emacs-major-version 27) :failed :passed)
(let* ((test-dir (make-temp-file "test-dir-" t))
(test-file (concat (file-name-as-directory test-dir) "foo.c"))
(replace "bar")
@@ -143,6 +142,7 @@ wdired-get-filename before and after editing."
(let* ((test-dir (make-temp-file "test-dir-" t))
(server-socket-dir test-dir)
(dired-listing-switches "-Fl")
+ (dired-ls-F-marks-symlinks (eq system-type 'darwin))
(buf (find-file-noselect test-dir)))
(unwind-protect
(progn
@@ -178,6 +178,22 @@ wdired-get-filename before and after editing."
(server-force-delete)
(delete-directory test-dir t))))
+(ert-deftest wdired-test-bug39280 ()
+ "Test for https://debbugs.gnu.org/39280."
+ (let* ((test-dir (make-temp-file "test-dir" 'dir))
+ (fname "foo")
+ (full-fname (expand-file-name fname test-dir)))
+ (make-empty-file full-fname)
+ (let ((buf (find-file-noselect test-dir)))
+ (unwind-protect
+ (with-current-buffer buf
+ (dired-toggle-read-only)
+ (dolist (old '(t nil))
+ (should (equal fname (wdired-get-filename 'nodir old)))
+ (should (equal full-fname (wdired-get-filename nil old))))
+ (wdired-finish-edit))
+ (if buf (kill-buffer buf))
+ (delete-directory test-dir t)))))
(provide 'wdired-tests)
;;; wdired-tests.el ends here
diff --git a/test/lisp/wid-edit-tests.el b/test/lisp/wid-edit-tests.el
index 2b0537bb006..35235c65665 100644
--- a/test/lisp/wid-edit-tests.el
+++ b/test/lisp/wid-edit-tests.el
@@ -113,4 +113,192 @@
(should (eq (current-column)
(widget-get grandchild :indent)))))))
+(ert-deftest widget-test-character-widget-value ()
+ "Check that we get the character widget's value correctly."
+ (with-temp-buffer
+ (let ((wid (widget-create '(character :value ?\n))))
+ (goto-char (widget-get wid :from))
+ (should (string= (widget-apply wid :value-get) "\n"))
+ (should (char-equal (widget-value wid) ?\n))
+ (should-not (widget-apply wid :validate)))))
+
+(ert-deftest widget-test-editable-field-widget-value ()
+ "Test that we get the editable field widget's value correctly."
+ (with-temp-buffer
+ (let ((wid (widget-create '(editable-field :value ""))))
+ (widget-insert "And some non-widget text.")
+ (should (string= (widget-apply wid :value-get) "")))))
+
+(ert-deftest widget-test-moving-editable-list-item ()
+ "Check that we can move an editable list item up or down, via delete+insert."
+ (with-temp-buffer
+ (widget-insert "Testing editable-list.\n\n")
+ (let ((lst (widget-create 'editable-list
+ :value '("beg" "end" "middle")
+ '(editable-field :value "unknown"))))
+ (use-local-map widget-keymap)
+ (widget-setup)
+ ;; Go to the DEL button for the 2nd element and action it.
+ (goto-char (widget-get (nth 2 (widget-get lst :buttons)) :from))
+ (widget-apply-action (widget-at))
+ ;; Go to the INS button and action it.
+ (goto-char (widget-get lst :to))
+ (widget-backward 1)
+ (widget-apply-action (widget-at))
+ ;; Check that we effectively moved the item to the last position.
+ (should (equal (widget-value lst) '("beg" "middle" "end"))))))
+
+(ert-deftest widget-test-choice-match-no-inline ()
+ "Test that a no-inline choice widget can match its values."
+ (let* ((choice '(choice (const nil) (const t) string function))
+ (widget (widget-convert choice)))
+ (should (widget-apply widget :match nil))
+ (should (widget-apply widget :match t))
+ (should (widget-apply widget :match ""))
+ (should (widget-apply widget :match 'ignore))))
+
+(ert-deftest widget-test-choice-match-all-inline ()
+ "Test that a choice widget with all inline members can match its values."
+ (let* ((lst '(list (choice (list :inline t symbol number)
+ (list :inline t symbol regexp))))
+ (widget (widget-convert lst)))
+ (should-not (widget-apply widget :match nil))
+ (should (widget-apply widget :match '(:test 2)))
+ (should (widget-apply widget :match '(:test ".*")))
+ (should-not (widget-apply widget :match '(:test ignore)))))
+
+(ert-deftest widget-test-choice-match-some-inline ()
+ "Test that a choice widget with some inline members can match its values."
+ (let* ((lst '(list string
+ (choice (const t)
+ (list :inline t symbol number)
+ (list :inline t symbol regexp))))
+ (widget (widget-convert lst)))
+ (should-not (widget-apply widget :match nil))
+ (should (widget-apply widget :match '("" t)))
+ (should (widget-apply widget :match '("" :test 2)))
+ (should (widget-apply widget :match '("" :test ".*")))
+ (should-not (widget-apply widget :match '(:test ignore)))))
+
+(ert-deftest widget-test-inline-p ()
+ "Test `widget-inline-p'.
+For widgets without an :inline t property, `widget-inline-p' has to return nil.
+But if the widget is a choice widget, it has to return nil if passed nil as
+the bubblep argument, or non-nil if one of the members of the choice widget has
+an :inline t property and we pass a non-nil bubblep argument. If no members of
+the choice widget have an :inline t property, then `widget-inline-p' has to
+return nil, even with a non-nil bubblep argument."
+ (with-temp-buffer
+ (widget-insert "Testing.\n\n")
+ (let* ((widget (widget-create 'repeat
+ :value '(nil)
+ '(choice (const nil) (const t)
+ (list :inline t symbol number))
+ '(choice (const nil) (const t)
+ (list function string))))
+ (children (widget-get widget :children))
+ (child-1 (car children))
+ (child-2 (cadr children)))
+ (should-not (widget-inline-p widget))
+ (should-not (widget-inline-p child-1))
+ (should (widget-inline-p child-1 'bubble))
+ (should-not (widget-inline-p child-2))
+ (should-not (widget-inline-p child-2 'bubble)))))
+
+(ert-deftest widget-test-repeat-can-handle-choice ()
+ "Test that we can create a repeat widget with a choice correctly."
+ (with-temp-buffer
+ (widget-insert "Testing.\n\n")
+ (let* ((widget (widget-create 'repeat
+ :entry-format "%i %d %v"
+ :value '((:test 2))
+ '(choice (const nil) (const t)
+ (list symbol number))))
+ (child (car (widget-get widget :children))))
+ (widget-insert "\n")
+ (use-local-map widget-keymap)
+ (widget-setup)
+ (should child)
+ (should (equal (widget-value widget) '((:test 2)))))))
+
+(ert-deftest widget-test-repeat-can-handle-inlinable-choice ()
+ "Test that we can create a repeat widget with an inlinable choice correctly."
+ (with-temp-buffer
+ (widget-insert "Testing.\n\n")
+ (let* ((widget (widget-create 'repeat
+ :entry-format "%i %d %v"
+ :value '(:test 2)
+ '(choice (const nil) (const t)
+ (list :inline t symbol number))))
+ (child (widget-get widget :children)))
+ (widget-insert "\n")
+ (use-local-map widget-keymap)
+ (widget-setup)
+ (should child)
+ (should (equal (widget-value widget) '(:test 2))))))
+
+(ert-deftest widget-test-list-can-handle-choice ()
+ "Test that we can create a list widget with a choice correctly."
+ (with-temp-buffer
+ (widget-insert "Testing.\n\n")
+ (let* ((widget (widget-create 'list
+ :value '((1 "One"))
+ '(choice string
+ (list number string))))
+ (child (car (widget-get widget :children))))
+ (widget-insert "\n")
+ (use-local-map widget-keymap)
+ (widget-setup)
+ (should child)
+ (should (equal (widget-value widget) '((1 "One")))))))
+
+(ert-deftest widget-test-list-can-handle-inlinable-choice ()
+ "Test that we can create a list widget with an inlinable choice correctly."
+ (with-temp-buffer
+ (widget-insert "Testing.\n\n")
+ (let* ((widget (widget-create 'list
+ :value '(1 "One")
+ '(choice string
+ (list :inline t number string))))
+ (child (car (widget-get widget :children))))
+ (widget-insert "\n")
+ (use-local-map widget-keymap)
+ (widget-setup)
+ (should child)
+ (should (equal (widget-value widget) '(1 "One"))))))
+
+(ert-deftest widget-test-option-can-handle-choice ()
+ "Test that we can create a option widget with a choice correctly."
+ (with-temp-buffer
+ (widget-insert "Testing.\n\n")
+ (let* ((widget (widget-create 'repeat
+ :value '(("foo"))
+ '(list (option
+ (choice string
+ (list :inline t
+ number string))))))
+ (child (car (widget-get widget :children))))
+ (widget-insert "\n")
+ (use-local-map widget-keymap)
+ (widget-setup)
+ (should child)
+ (should (equal (widget-value widget) '(("foo")))))))
+
+(ert-deftest widget-test-option-can-handle-inlinable-choice ()
+ "Test that we can create a option widget with an inlinable choice correctly."
+ (with-temp-buffer
+ (widget-insert "Testing.\n\n")
+ (let* ((widget (widget-create 'repeat
+ :value '((1 "One"))
+ '(list (option
+ (choice string
+ (list :inline t
+ number string))))))
+ (child (car (widget-get widget :children))))
+ (widget-insert "\n")
+ (use-local-map widget-keymap)
+ (widget-setup)
+ (should child)
+ (should (equal (widget-value widget) '((1 "One")))))))
+
;;; wid-edit-tests.el ends here
diff --git a/test/data/xdg/l10n.desktop b/test/lisp/xdg-resources/l10n.desktop
index 42da83910da..42da83910da 100644
--- a/test/data/xdg/l10n.desktop
+++ b/test/lisp/xdg-resources/l10n.desktop
diff --git a/test/data/xdg/malformed.desktop b/test/lisp/xdg-resources/malformed.desktop
index 144a3f719d5..144a3f719d5 100644
--- a/test/data/xdg/malformed.desktop
+++ b/test/lisp/xdg-resources/malformed.desktop
diff --git a/test/data/xdg/mimeapps.list b/test/lisp/xdg-resources/mimeapps.list
index 27fbd94b16b..27fbd94b16b 100644
--- a/test/data/xdg/mimeapps.list
+++ b/test/lisp/xdg-resources/mimeapps.list
diff --git a/test/data/xdg/mimeinfo.cache b/test/lisp/xdg-resources/mimeinfo.cache
index 6e54f604fa0..6e54f604fa0 100644
--- a/test/data/xdg/mimeinfo.cache
+++ b/test/lisp/xdg-resources/mimeinfo.cache
diff --git a/test/data/xdg/test.desktop b/test/lisp/xdg-resources/test.desktop
index b848cef5b0f..b848cef5b0f 100644
--- a/test/data/xdg/test.desktop
+++ b/test/lisp/xdg-resources/test.desktop
diff --git a/test/data/xdg/wrong.desktop b/test/lisp/xdg-resources/wrong.desktop
index e0b4c221cf9..e0b4c221cf9 100644
--- a/test/data/xdg/wrong.desktop
+++ b/test/lisp/xdg-resources/wrong.desktop
diff --git a/test/lisp/xdg-tests.el b/test/lisp/xdg-tests.el
index 3413a70ef8c..67cd9401937 100644
--- a/test/lisp/xdg-tests.el
+++ b/test/lisp/xdg-tests.el
@@ -25,26 +25,20 @@
;;; Code:
(require 'ert)
+(require 'ert-x)
(require 'xdg)
-(defconst xdg-tests-data-dir
- (expand-file-name "test/data/xdg" source-directory))
-
(ert-deftest xdg-desktop-parsing ()
"Test `xdg-desktop-read-file' parsing of .desktop files."
- (let ((tab1 (xdg-desktop-read-file
- (expand-file-name "test.desktop" xdg-tests-data-dir)))
- (tab2 (xdg-desktop-read-file
- (expand-file-name "test.desktop" xdg-tests-data-dir)
+ (let ((tab1 (xdg-desktop-read-file (ert-resource-file "test.desktop")))
+ (tab2 (xdg-desktop-read-file (ert-resource-file "test.desktop")
"Another Section")))
(should (equal (gethash "Name" tab1) "Test"))
(should (eq 'default (gethash "Exec" tab1 'default)))
(should (equal "frobnicate" (gethash "Exec" tab2))))
(should-error
- (xdg-desktop-read-file
- (expand-file-name "malformed.desktop" xdg-tests-data-dir)))
- (let ((tab (xdg-desktop-read-file
- (expand-file-name "l10n.desktop" xdg-tests-data-dir)))
+ (xdg-desktop-read-file (ert-resource-file "malformed.desktop")))
+ (let ((tab (xdg-desktop-read-file (ert-resource-file "l10n.desktop")))
(env (getenv "LC_MESSAGES")))
(unwind-protect
(progn
@@ -67,8 +61,8 @@
(ert-deftest xdg-mime-associations ()
"Test reading MIME associations from files."
- (let* ((apps (expand-file-name "mimeapps.list" xdg-tests-data-dir))
- (cache (expand-file-name "mimeinfo.cache" xdg-tests-data-dir))
+ (let* ((apps (ert-resource-file "mimeapps.list"))
+ (cache (ert-resource-file "mimeinfo.cache"))
(fs (list apps cache)))
(should (equal (xdg-mime-collect-associations "x-test/foo" fs)
'("a.desktop" "b.desktop")))
diff --git a/test/lisp/xml-tests.el b/test/lisp/xml-tests.el
index 463d2741c68..cd3e1138f4b 100644
--- a/test/lisp/xml-tests.el
+++ b/test/lisp/xml-tests.el
@@ -1,4 +1,4 @@
-;;; xml-parse-tests.el --- Test suite for XML parsing.
+;;; xml-parse-tests.el --- Test suite for XML parsing. -*- lexical-binding:t -*-
;; Copyright (C) 2012-2021 Free Software Foundation, Inc.
@@ -164,6 +164,37 @@ Parser is called with and without 'symbol-qnames argument.")
(should (equal (cdr xml-parse-test--namespace-attribute-qnames)
(xml-parse-region nil nil nil nil 'symbol-qnames)))))
+(ert-deftest xml-print-invalid-cdata ()
+ "Check that Bug#41094 is fixed."
+ (with-temp-buffer
+ (should (equal (should-error (xml-print '((foo () "\0")))
+ :type 'xml-invalid-character)
+ '(xml-invalid-character 0 1)))
+ (should (equal (should-error (xml-print '((foo () "\u00FF \xFF")))
+ :type 'xml-invalid-character)
+ '(xml-invalid-character #x3FFFFF 3)))))
+
+(defvar xml-tests--data-with-comments
+ `(;; simple case
+ ("<?xml version=\"1.0\"?><foo baz=\"true\">bar</foo>"
+ . ((foo ((baz . "true")) "bar")))
+ ;; toplevel comments -- first document child must not get lost
+ (,(concat "<?xml version=\"1.0\"?><foo>bar</foo><!--comment-1-->"
+ "<!--comment-2-->")
+ . ((foo nil "bar")))
+ (,(concat "<?xml version=\"1.0\"?><!--comment-a--><foo a=\"b\">"
+ "<bar>blub</bar></foo><!--comment-b--><!--comment-c-->")
+ . ((foo ((a . "b")) (bar nil "blub")))))
+ "Alist of XML strings and their expected parse trees for discarded comments.")
+
+(ert-deftest xml-remove-comments ()
+ (dolist (test xml-tests--data-with-comments)
+ (erase-buffer)
+ (insert (car test))
+ (xml-remove-comments (point-min) (point-max))
+ (should (equal (cdr test)
+ (xml-parse-region (point-min) (point-max))))))
+
;; Local Variables:
;; no-byte-compile: t
;; End:
diff --git a/test/lisp/xt-mouse-tests.el b/test/lisp/xt-mouse-tests.el
index c2991343311..72659ddf99b 100644
--- a/test/lisp/xt-mouse-tests.el
+++ b/test/lisp/xt-mouse-tests.el
@@ -53,9 +53,9 @@
(ert-deftest xt-mouse-tracking-basic ()
(should (equal (xterm-mouse-tracking-enable-sequence)
- "\e[?1000h\e[?1002h\e[?1006h"))
+ "\e[?1000h\e[?1003h\e[?1006h"))
(should (equal (xterm-mouse-tracking-disable-sequence)
- "\e[?1006l\e[?1002l\e[?1000l"))
+ "\e[?1006l\e[?1003l\e[?1000l"))
(with-xterm-mouse-mode
(should xterm-mouse-mode)
(should (terminal-parameter nil 'xterm-mouse-mode))
@@ -73,9 +73,9 @@
(ert-deftest xt-mouse-tracking-utf-8 ()
(let ((xterm-mouse-utf-8 t))
(should (equal (xterm-mouse-tracking-enable-sequence)
- "\e[?1000h\e[?1002h\e[?1005h\e[?1006h"))
+ "\e[?1000h\e[?1003h\e[?1005h\e[?1006h"))
(should (equal (xterm-mouse-tracking-disable-sequence)
- "\e[?1006l\e[?1005l\e[?1002l\e[?1000l"))
+ "\e[?1006l\e[?1005l\e[?1003l\e[?1000l"))
(with-xterm-mouse-mode
(should xterm-mouse-mode)
(should (terminal-parameter nil 'xterm-mouse-mode))
diff --git a/test/manual/biditest.el b/test/manual/biditest.el
index 798bb182b88..dc78ef55b03 100644
--- a/test/manual/biditest.el
+++ b/test/manual/biditest.el
@@ -6,12 +6,14 @@
;; Maintainer: emacs-devel@gnu.org
;; Package: emacs
-;; This program is free software: you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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.
diff --git a/test/manual/cedet/cedet-utests.el b/test/manual/cedet/cedet-utests.el
index 01839761f46..7805fce2d12 100644
--- a/test/manual/cedet/cedet-utests.el
+++ b/test/manual/cedet/cedet-utests.el
@@ -150,7 +150,7 @@ of just logging the error."
;; Cleanup stray input and events that are in the way.
;; Not doing this causes sit-for to not refresh the screen.
;; Doing this causes the user to need to press keys more frequently.
- (when (and (interactive-p) (input-pending-p))
+ (when (and (called-interactively-p 'interactive) (input-pending-p))
(if (fboundp 'read-event)
(read-event)
(read-char)))
@@ -497,11 +497,11 @@ When optional NO-ERROR don't throw an error if we can't run tests."
(error (concat "Pulse test only works on versions of Emacs"
" that support pulsing")))
;; Run the tests
- (when (interactive-p)
+ (when (called-interactively-p 'interactive)
(message "<Press a key> Pulse one line.")
(read-char))
(pulse-momentary-highlight-one-line (point))
- (when (interactive-p)
+ (when (called-interactively-p 'interactive)
(message "<Press a key> Pulse a region.")
(read-char))
(pulse-momentary-highlight-region (point)
@@ -510,11 +510,11 @@ When optional NO-ERROR don't throw an error if we can't run tests."
(forward-char 30)
(error nil))
(point)))
- (when (interactive-p)
+ (when (called-interactively-p 'interactive)
(message "<Press a key> Pulse line a specific color.")
(read-char))
(pulse-momentary-highlight-one-line (point) 'mode-line)
- (when (interactive-p)
+ (when (called-interactively-p 'interactive)
(message "<Press a key> Pulse a pre-existing overlay.")
(read-char))
(let* ((start (point-at-bol))
@@ -530,7 +530,7 @@ When optional NO-ERROR don't throw an error if we can't run tests."
(delete-overlay o)
(error "Non-temporary overlay was deleted!"))
)
- (when (interactive-p)
+ (when (called-interactively-p 'interactive)
(message "Done!"))))
(provide 'cedet-utests)
diff --git a/test/manual/cedet/semantic-tests.el b/test/manual/cedet/semantic-tests.el
index 9d08a25b8ab..716bcc7abed 100644
--- a/test/manual/cedet/semantic-tests.el
+++ b/test/manual/cedet/semantic-tests.el
@@ -235,7 +235,7 @@ Analyze the area between BEG and END."
(set-buffer buff)
(semantic-lex-spp-write-test)
(kill-buffer buff)
- (when (not (interactive-p))
+ (when (not (called-interactively-p 'interactive))
(kill-buffer "*SPP Write Test*"))
)))
@@ -276,7 +276,7 @@ tag that contains point, and return that."
target (lambda (start end prefix) (setq Lcount (1+ Lcount)))
(semantic-tag-start tag)
(semantic-tag-end tag))
- (when (interactive-p)
+ (when (called-interactively-p 'interactive)
(message "Found %d occurrences of %s in %.2f seconds"
Lcount (semantic-tag-name target)
(semantic-elapsed-time start nil)))
diff --git a/test/manual/cedet/tests/testnsp.cpp b/test/manual/cedet/tests/testnsp.cpp
index 8a7b2899f9a..db1603cead2 100644
--- a/test/manual/cedet/tests/testnsp.cpp
+++ b/test/manual/cedet/tests/testnsp.cpp
@@ -93,7 +93,7 @@ void foo(void) {
; // #4# ( "Mumble" "get" )
}
-// What happens if a type your looking for is scoped withing a type,
+// What happens if a type your looking for is scoped within a type,
// but you are one level into the completion so the originating scope
// excludes the type of the variable you are completing through?
// Thanks Martin Stein for this nice example.
diff --git a/test/manual/etags/CTAGS.good b/test/manual/etags/CTAGS.good
index 519315c6fdd..5e582434a62 100644
--- a/test/manual/etags/CTAGS.good
+++ b/test/manual/etags/CTAGS.good
@@ -1835,7 +1835,7 @@ Z c-src/h.h 100
\Ealphaenumerate tex-src/texinfo.tex /^\\def\\Ealphaenumerate{\\Eenumerate}$/
\Ecapsenumerate tex-src/texinfo.tex /^\\def\\Ecapsenumerate{\\Eenumerate}$/
\Ecartouche tex-src/texinfo.tex /^\\def\\Ecartouche{%$/
-\Edescription tex-src/texinfo.tex /^\\def\\Edescription{\\Etable}% Neccessary kludge.$/
+\Edescription tex-src/texinfo.tex /^\\def\\Edescription{\\Etable}% Necessary kludge.$/
\Edisplay tex-src/texinfo.tex /^\\def\\Edisplay{\\endgroup\\afterenvbreak}%$/
\Eexample tex-src/texinfo.tex /^\\def\\Eexample{\\Elisp}$/
\Eflushleft tex-src/texinfo.tex /^\\def\\Eflushleft{\\endgroup\\afterenvbreak}%$/
diff --git a/test/manual/etags/c-src/abbrev.c b/test/manual/etags/c-src/abbrev.c
index 4853824e434..039addc5a30 100644
--- a/test/manual/etags/c-src/abbrev.c
+++ b/test/manual/etags/c-src/abbrev.c
@@ -78,9 +78,6 @@ Lisp_Object Vlast_abbrev_text;
int last_abbrev_point;
-/* Hook to run before expanding any abbrev. */
-
-Lisp_Object Vpre_abbrev_expand_hook, Qpre_abbrev_expand_hook;
DEFUN ("make-abbrev-table", Fmake_abbrev_table, Smake_abbrev_table, 0, 0, 0,
"Create a new, empty abbrev table object.")
@@ -232,9 +229,6 @@ Returns the abbrev symbol, if expansion took place.")
value = Qnil;
- if (!NILP (Vrun_hooks))
- call1 (Vrun_hooks, Qpre_abbrev_expand_hook);
-
wordstart = 0;
if (!(BUFFERP (Vabbrev_start_location_buffer)
&& XBUFFER (Vabbrev_start_location_buffer) == current_buffer))
@@ -595,14 +589,6 @@ This causes `save-some-buffers' to offer to save the abbrevs.");
"*Set non-nil means expand multi-word abbrevs all caps if abbrev was so.");
abbrev_all_caps = 0;
- DEFVAR_LISP ("pre-abbrev-expand-hook", &Vpre_abbrev_expand_hook,
- "Function or functions to be called before abbrev expansion is done.\n\
-This is the first thing that `expand-abbrev' does, and so this may change\n\
-the current abbrev table before abbrev lookup happens.");
- Vpre_abbrev_expand_hook = Qnil;
- Qpre_abbrev_expand_hook = intern ("pre-abbrev-expand-hook");
- staticpro (&Qpre_abbrev_expand_hook);
-
defsubr (&Smake_abbrev_table);
defsubr (&Sclear_abbrev_table);
defsubr (&Sdefine_abbrev);
diff --git a/test/manual/etags/c-src/emacs/src/keyboard.c b/test/manual/etags/c-src/emacs/src/keyboard.c
index b1e9a755506..db86515ef09 100644
--- a/test/manual/etags/c-src/emacs/src/keyboard.c
+++ b/test/manual/etags/c-src/emacs/src/keyboard.c
@@ -5754,7 +5754,7 @@ make_lispy_event (struct input_event *event)
ignore_mouse_drag_p = 0;
}
- /* Now we're releasing a button - check the co-ordinates to
+ /* Now we're releasing a button - check the coordinates to
see if this was a click or a drag. */
else if (event->modifiers & up_modifier)
{
diff --git a/test/manual/etags/cp-src/functions.cpp b/test/manual/etags/cp-src/functions.cpp
index 7c353d161a1..ddd78f14d9b 100644
--- a/test/manual/etags/cp-src/functions.cpp
+++ b/test/manual/etags/cp-src/functions.cpp
@@ -223,7 +223,7 @@ int WorkingDays(Date a, Date b){
return(wdays);
}
-Date StartDay(Date a,int days){//Function to calculate the apropriate start day to finish in days working days
+Date StartDay(Date a,int days){//Function to calculate the appropriate start day to finish in days working days
Date tmp;
int wdays=0;
if ( ! a.set() )
diff --git a/test/manual/etags/prol-src/ordsets.prolog b/test/manual/etags/prol-src/ordsets.prolog
index 7192129fdce..0fa70f903f0 100644
--- a/test/manual/etags/prol-src/ordsets.prolog
+++ b/test/manual/etags/prol-src/ordsets.prolog
@@ -120,7 +120,7 @@ ord_intersect(>, Head1, Tail1, _, [Head2|Tail2]) :-
% ord_intersection(+Set1, +Set2, ?Intersection)
-% is true when Intersection is the intersecton of Set1
+% is true when Intersection is the intersection of Set1
% and Set2, provided that Set1 and Set2 are ordered sets.
ord_intersection([], _, []).
@@ -144,7 +144,7 @@ ord_intersection3([Head2|Tail2], Head1, Tail1, Intersection) :-
% ord_intersection(+Set1, +Set2, ?Intersection, ?Difference)
% is true when Intersection is the intersection of Set1 and Set2,
-% and Differens is Set2 \ Set1 (like in ord_union/4),
+% and Difference is Set2 \ Set1 (like in ord_union/4),
% provided that Set1 and Set2 are ordered sets.
ord_intersection([], Set2, [], Set2).
diff --git a/test/manual/etags/tex-src/texinfo.tex b/test/manual/etags/tex-src/texinfo.tex
index 9c80a2592d1..a04371d1c90 100644
--- a/test/manual/etags/tex-src/texinfo.tex
+++ b/test/manual/etags/tex-src/texinfo.tex
@@ -1074,7 +1074,7 @@ July\or August\or September\or October\or November\or December\fi
\def\tablez #1#2#3#4#5#6{%
\aboveenvbreak %
\begingroup %
-\def\Edescription{\Etable}% Neccessary kludge.
+\def\Edescription{\Etable}% Necessary kludge.
\let\itemindex=#1%
\ifnum 0#3>0 \advance \leftskip by #3\mil \fi %
\ifnum 0#4>0 \tableindent=#4\mil \fi %
@@ -2937,7 +2937,7 @@ July\or August\or September\or October\or November\or December\fi
\setbox0=\hbox{\printednodename}%
\ifdim \wd0=0pt%
\def\printednodename{\ignorespaces #1}%
-%%% Uncommment the following line to make the actual chapter or section title
+%%% Uncomment the following line to make the actual chapter or section title
%%% appear inside the square brackets.
%\def\printednodename{#1-title}%
\fi%
diff --git a/test/manual/etags/y-src/parse.c b/test/manual/etags/y-src/parse.c
index 4ea147fc026..f90d31505f0 100644
--- a/test/manual/etags/y-src/parse.c
+++ b/test/manual/etags/y-src/parse.c
@@ -1917,7 +1917,7 @@ yylex FUN0()
}
#ifdef TEST
if(nn==n_usr_funs) {
- io_error_msg("Couln't turn fp into a ##");
+ io_error_msg("Couldn't turn fp into a ##");
parse_error=BAD_FUNC;
return ERROR;
}
diff --git a/test/manual/etags/y-src/parse.y b/test/manual/etags/y-src/parse.y
index 75764bdc442..7985da525be 100644
--- a/test/manual/etags/y-src/parse.y
+++ b/test/manual/etags/y-src/parse.y
@@ -556,7 +556,7 @@ yylex FUN0()
}
#ifdef TEST
if(nn==n_usr_funs) {
- io_error_msg("Couln't turn fp into a ##");
+ io_error_msg("Couldn't turn fp into a ##");
parse_error=BAD_FUNC;
return ERROR;
}
diff --git a/test/manual/image-circular-tests.el b/test/manual/image-circular-tests.el
new file mode 100644
index 00000000000..28b5f892e53
--- /dev/null
+++ b/test/manual/image-circular-tests.el
@@ -0,0 +1,144 @@
+;;; image-tests.el --- Test suite for image-related functions.
+
+;; Copyright (C) 2019, 2021 Free Software Foundation, Inc.
+
+;; Author: Pip Cet <pipcet@gmail.com>
+;; Keywords: internal
+;; Human-Keywords: internal
+
+;; 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+
+(ert-deftest image-test-duplicate-keywords ()
+ "Test that duplicate keywords in an image spec lead to rejection."
+ (should-error (image-size `(image :type xbm :type xbm :width 1 :height 1
+ :data ,(bool-vector t))
+ t)))
+
+(ert-deftest image-test-circular-plist ()
+ "Test that a circular image spec is rejected."
+ (should-error
+ (let ((l `(image :type xbm :width 1 :height 1 :data ,(bool-vector t))))
+ (setcdr (last l) '#1=(:invalid . #1#))
+ (image-size l t))))
+
+(ert-deftest image-test-:type-property-value ()
+ "Test that :type is allowed as a property value in an image spec."
+ (should (equal (image-size `(image :dummy :type :type xbm :width 1 :height 1
+ :data ,(bool-vector t))
+ t)
+ (cons 1 1))))
+
+(ert-deftest image-test-circular-specs ()
+ "Test that circular image spec property values do not cause infinite recursion."
+ (should
+ (let* ((circ1 (cons :dummy nil))
+ (circ2 (cons :dummy nil))
+ (spec1 `(image :type xbm :width 1 :height 1
+ :data ,(bool-vector 1) :ignored ,circ1))
+ (spec2 `(image :type xbm :width 1 :height 1
+ :data ,(bool-vector 1) :ignored ,circ2)))
+ (setcdr circ1 circ1)
+ (setcdr circ2 circ2)
+ (and (equal (image-size spec1 t) (cons 1 1))
+ (equal (image-size spec2 t) (cons 1 1))))))
+
+(provide 'image-tests)
+;;; image-tests.el ends here.
+;;; image-tests.el --- tests for image.el -*- lexical-binding: t -*-
+
+;; Copyright (C) 2019-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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+(require 'image)
+(eval-when-compile
+ (require 'cl-lib))
+
+(defconst image-tests--emacs-images-directory
+ (expand-file-name "../etc/images" (getenv "EMACS_TEST_DIRECTORY"))
+ "Directory containing Emacs images.")
+
+(ert-deftest image--set-property ()
+ "Test `image--set-property' behavior."
+ (let ((image (list 'image)))
+ ;; Add properties.
+ (setf (image-property image :scale) 1)
+ (should (equal image '(image :scale 1)))
+ (setf (image-property image :width) 8)
+ (should (equal image '(image :scale 1 :width 8)))
+ (setf (image-property image :height) 16)
+ (should (equal image '(image :scale 1 :width 8 :height 16)))
+ ;; Delete properties.
+ (setf (image-property image :type) nil)
+ (should (equal image '(image :scale 1 :width 8 :height 16)))
+ (setf (image-property image :scale) nil)
+ (should (equal image '(image :width 8 :height 16)))
+ (setf (image-property image :height) nil)
+ (should (equal image '(image :width 8)))
+ (setf (image-property image :width) nil)
+ (should (equal image '(image)))))
+
+(ert-deftest image-type-from-file-header-test ()
+ "Test image-type-from-file-header."
+ (should (eq (if (image-type-available-p 'svg) 'svg)
+ (image-type-from-file-header
+ (expand-file-name "splash.svg"
+ image-tests--emacs-images-directory)))))
+
+(ert-deftest image-rotate ()
+ "Test `image-rotate'."
+ (cl-letf* ((image (list 'image))
+ ((symbol-function 'image--get-imagemagick-and-warn)
+ (lambda () image)))
+ (let ((current-prefix-arg '(4)))
+ (call-interactively #'image-rotate))
+ (should (equal image '(image :rotation 270.0)))
+ (call-interactively #'image-rotate)
+ (should (equal image '(image :rotation 0.0)))
+ (image-rotate)
+ (should (equal image '(image :rotation 90.0)))
+ (image-rotate 0)
+ (should (equal image '(image :rotation 90.0)))
+ (image-rotate 1)
+ (should (equal image '(image :rotation 91.0)))
+ (image-rotate 1234.5)
+ (should (equal image '(image :rotation 245.5)))
+ (image-rotate -154.5)
+ (should (equal image '(image :rotation 91.0)))))
+
+;;; image-tests.el ends here
diff --git a/test/manual/image-size-tests.el b/test/manual/image-size-tests.el
index 42aab9d8c33..489b3972932 100644
--- a/test/manual/image-size-tests.el
+++ b/test/manual/image-size-tests.el
@@ -4,18 +4,18 @@
;; This file is part of GNU Emacs.
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;; To test: Load the file and eval (image-size-tests).
;; A non-erroring result is a success.
diff --git a/test/manual/image-transforms-tests.el b/test/manual/image-transforms-tests.el
index 6be2913cac9..5342b5edcae 100644
--- a/test/manual/image-transforms-tests.el
+++ b/test/manual/image-transforms-tests.el
@@ -1,4 +1,4 @@
-;;; image-transform-tests.el --- Test suite for image transforms.
+;;; image-transform-tests.el --- Test suite for image transforms. -*- lexical-binding: t -*-
;; Copyright (C) 2019-2021 Free Software Foundation, Inc.
@@ -48,24 +48,24 @@
(let ((image "<svg height='30' width='30'>
<rect x='0' y='0' width='10' height='10'/>
<rect x='10' y='10' width='10' height='10'
- style='fill:none;stroke-width:1;stroke:#000'/>
- <line x1='10' y1='10' x2='20' y2='20' style='stroke:#000'/>
- <line x1='20' y1='10' x2='10' y2='20' style='stroke:#000'/>
+ style='fill:none;stroke-width:1;stroke:currentColor'/>
+ <line x1='10' y1='10' x2='20' y2='20' style='stroke:currentColor'/>
+ <line x1='20' y1='10' x2='10' y2='20' style='stroke:currentColor'/>
<rect x='20' y='20' width='10' height='10'
- style='fill:none;stroke-width:1;stroke:#000'/>
+ style='fill:none;stroke-width:1;stroke:currentColor'/>
</svg>")
(top-left "<svg height='10' width='10'>
<rect x='0' y='0' width='10' height='10'/>
</svg>")
(middle "<svg height='10' width='10'>
<rect x='0' y='0' width='10' height='10'
- style='fill:none;stroke-width:1;stroke:#000'/>
- <line x1='0' y1='0' x2='10' y2='10' style='stroke:#000'/>
- <line x1='10' y1='0' x2='0' y2='10' style='stroke:#000'/>
+ style='fill:none;stroke-width:1;stroke:currentColor'/>
+ <line x1='0' y1='0' x2='10' y2='10' style='stroke:currentColor'/>
+ <line x1='10' y1='0' x2='0' y2='10' style='stroke:currentColor'/>
</svg>")
(bottom-right "<svg height='10' width='10'>
<rect x='0' y='0' width='10' height='10'
- style='fill:none;stroke-width:1;stroke:#000'/>
+ style='fill:none;stroke-width:1;stroke:currentColor'/>
</svg>"))
(insert-header "Test Crop: cropping an image (only works with ImageMagick)")
(insert-test "all params" top-left image '(:crop (10 10 0 0)))
@@ -77,23 +77,23 @@
(defun test-scaling ()
(let ((image "<svg height='10' width='10'>
<rect x='0' y='0' width='10' height='10'
- style='fill:none;stroke-width:1;stroke:#000'/>
- <line x1='0' y1='0' x2='10' y2='10' style='stroke:#000'/>
- <line x1='10' y1='0' x2='0' y2='10' style='stroke:#000'/>
+ style='fill:none;stroke-width:1;stroke:currentColor'/>
+ <line x1='0' y1='0' x2='10' y2='10' style='stroke:currentColor'/>
+ <line x1='10' y1='0' x2='0' y2='10' style='stroke:currentColor'/>
</svg>")
(large "<svg height='20' width='20'>
<rect x='0' y='0' width='20' height='20'
- style='fill:none;stroke-width:2;stroke:#000'/>
+ style='fill:none;stroke-width:2;stroke:currentColor'/>
<line x1='0' y1='0' x2='20' y2='20'
- style='stroke-width:2;stroke:#000'/>
+ style='stroke-width:2;stroke:currentColor'/>
<line x1='20' y1='0' x2='0' y2='20'
- style='stroke-width:2;stroke:#000'/>
+ style='stroke-width:2;stroke:currentColor'/>
</svg>")
(small "<svg height='5' width='5'>
<rect x='0' y='0' width='4' height='4'
- style='fill:none;stroke-width:1;stroke:#000'/>
- <line x1='0' y1='0' x2='4' y2='4' style='stroke:#000'/>
- <line x1='4' y1='0' x2='0' y2='4' style='stroke:#000'/>
+ style='fill:none;stroke-width:1;stroke:currentColor'/>
+ <line x1='0' y1='0' x2='4' y2='4' style='stroke:currentColor'/>
+ <line x1='4' y1='0' x2='0' y2='4' style='stroke:currentColor'/>
</svg>"))
(insert-header "Test Scaling: resize an image (pixelization may occur)")
(insert-test "1x" image image '(:scale 1))
@@ -107,27 +107,27 @@
(defun test-scaling-rotation ()
(let ((image "<svg height='20' width='20'>
<rect x='0' y='0' width='20' height='20'
- style='fill:none;stroke-width:1;stroke:#000'/>
+ style='fill:none;stroke-width:1;stroke:currentColor'/>
<rect x='0' y='0' width='10' height='10'
- style='fill:#000'/>
+ style='fill:currentColor'/>
</svg>")
(x2-90 "<svg height='40' width='40'>
<rect x='0' y='0' width='40' height='40'
- style='fill:none;stroke-width:1;stroke:#000'/>
+ style='fill:none;stroke-width:1;stroke:currentColor'/>
<rect x='20' y='0' width='20' height='20'
- style='fill:#000'/>
+ style='fill:currentColor'/>
</svg>")
(x2--90 "<svg height='40' width='40'>
<rect x='0' y='0' width='40' height='40'
- style='fill:none;stroke-width:1;stroke:#000'/>
+ style='fill:none;stroke-width:1;stroke:currentColor'/>
<rect x='0' y='20' width='20' height='20'
- style='fill:#000'/>
+ style='fill:currentColor'/>
</svg>")
(x0.5-180 "<svg height='10' width='10'>
<rect x='0' y='0' width='10' height='10'
- style='fill:none;stroke-width:1;stroke:#000'/>
+ style='fill:none;stroke-width:1;stroke:currentColor'/>
<rect x='5' y='5' width='5' height='5'
- style='fill:#000'/>
+ style='fill:currentColor'/>
</svg>"))
(insert-header "Test Scaling and Rotation: resize and rotate an image (pixelization may occur)")
(insert-test "1x, 0 degrees" image image '(:scale 1 :rotation 0))
diff --git a/test/manual/indent/less-css-mode.less b/test/manual/indent/less-css-mode.less
index 36c037450cc..b40a2362e28 100644
--- a/test/manual/indent/less-css-mode.less
+++ b/test/manual/indent/less-css-mode.less
@@ -1,3 +1,13 @@
+@var-with-dashes: #428bca;
+@var_with_underscores: 10px;
+@_var-starting-with-underscore: none;
+
+body {
+ background: @var-with-dashes;
+ padding: @var_with_underscores;
+ display: @_var-starting-with-underscore;
+}
+
.desktop-and-old-ie(@rules) {
@media screen and (min-width: 1200) { @rules(); }
html.lt-ie9 & { @rules(); }
diff --git a/test/manual/indent/nxml.xml b/test/manual/indent/nxml.xml
deleted file mode 100644
index 61b84f270b0..00000000000
--- a/test/manual/indent/nxml.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<spocosy version="1.0" responsetime="2011-03-15 13:53:12" exec="0.171">
- <!--
- <query-response requestid="" service="objectquery">
- <sport name="Soccer" enetSportCode="s" del="no" n="1" ut="2009-12-29
- 15:36:24" id="1">
- </sport>
- </query-response>
- -->
-</spocosy>
diff --git a/test/manual/indent/opascal.pas b/test/manual/indent/opascal.pas
deleted file mode 100644
index ac4beb3f840..00000000000
--- a/test/manual/indent/opascal.pas
+++ /dev/null
@@ -1,12 +0,0 @@
-{ -*- opascal -*- }
-
-procedure Toto ();
-begin
- for i := 0 to 1 do
- Write (str.Chars[i]);
-
- // bug#36348
- for var i := 0 to 1 do
- Write (str.Chars[i]);
-
-end;
diff --git a/test/manual/indent/perl.perl b/test/manual/indent/perl.perl
index 853aec49245..6ec04303b4f 100755
--- a/test/manual/indent/perl.perl
+++ b/test/manual/indent/perl.perl
@@ -81,3 +81,17 @@ return 'W' if #/^Not Available on Mobile/m; #W=Web only
# A "y|abc|def|" shouldn't interfere when inside a string!
$toto = " x \" string\"";
$toto = " y \" string\""; # This is not the `y' operator!
+
+
+# Tricky cases from Harald Jörg <haj@posteo.de>
+$_ = "abcabc\n";
+s:abc:def:g; # FIXME: the initial s is fontified like a label, and indented
+
+s'def'ghi'g; # The middle ' should not end the quoting.
+s"ghi"ijk"g; # The middle ' should not end the quoting.
+
+s#ijk#lmn#g; # This is a regular expression sustitution.
+
+s #lmn#opq#g; # FIXME: this should be a comment starting with "#lmn"
+ /lmn/rst/g; # and this is the actual regular expression
+print; # prints "rstrst\n"
diff --git a/test/manual/indent/ps-mode.ps b/test/manual/indent/ps-mode.ps
deleted file mode 100644
index 4b4ee0f10cb..00000000000
--- a/test/manual/indent/ps-mode.ps
+++ /dev/null
@@ -1,14 +0,0 @@
-%!PS-2.0
-
-<< 23 45 >> %dictionary
-< 23 > %hex string
-<~a>a%a~> %base85 string
-(%)s
-(sf\(g>a)sdg)
-
-/foo {
- <<
- hello 2
- 3
- >>
-} def
diff --git a/test/manual/indent/scheme.scm b/test/manual/indent/scheme.scm
deleted file mode 100644
index 84d0f6d8786..00000000000
--- a/test/manual/indent/scheme.scm
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/scheme is this a comment?
-
-;; This one is a comment
-(a)
-#| and this one as #|well|# as this! |#
-(b)
-(cons #;(this is a
- comment)
- head tail)
diff --git a/test/manual/indent/scss-mode.scss b/test/manual/indent/scss-mode.scss
index a3dd41eeb47..189ec4e22ac 100644
--- a/test/manual/indent/scss-mode.scss
+++ b/test/manual/indent/scss-mode.scss
@@ -41,9 +41,13 @@ p.#{$name} var
article[role="main"] {
$toto: 500 !global;
$var-with-default: 300 !default;
+ $var_with_underscores: #fff;
+ $_var-starting-with-underscore: none;
float: left !important;
width: 600px / 888px * 100%;
height: 100px / 888px * 100%;
+ color: $var_with_underscores;
+ display: $_var-starting-with-underscore;
}
%placeholder {
diff --git a/test/manual/indent/tcl.tcl b/test/manual/indent/tcl.tcl
new file mode 100644
index 00000000000..f055be19663
--- /dev/null
+++ b/test/manual/indent/tcl.tcl
@@ -0,0 +1,26 @@
+# Some sample code that tries to exercise the font-lock
+# of various forms of writing strings.
+
+puts "hello}"; # Top-level strings can contain unescaped closing braces!
+
+puts a"b; # Non-delimited strings can contain quotes!
+puts a""b; # Even several of them!
+
+proc foo1 {} {
+ puts "hello"; # Normal case!
+ puts "hello\}; # This will signal an error when `foo1` is called!
+}
+
+proc foo2 {} {
+ puts "hello; # This will also signal an error when `foo2` is called!
+}
+
+proc foo3 {} {
+ puts a"b; # This will not signal an error!
+ puts a""b"; # And that won't either!
+ puts "a""b"; # But this will!
+}
+
+# FIXME: The [..] interpolation within "..." strings is not properly
+# handled by the current `syntax-propertize-function`!
+set a "Testing: [split "192.168.1.1/24" "/"] address";
diff --git a/test/manual/scroll-tests.el b/test/manual/scroll-tests.el
index 0fa5818d7af..2f40b2bb696 100644
--- a/test/manual/scroll-tests.el
+++ b/test/manual/scroll-tests.el
@@ -4,18 +4,18 @@
;; This file is part of GNU Emacs.
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
diff --git a/test/src/alloc-tests.el b/test/src/alloc-tests.el
index e3e2ea184e6..1324c2d3b4d 100644
--- a/test/src/alloc-tests.el
+++ b/test/src/alloc-tests.el
@@ -51,3 +51,10 @@
(should-not (eq x y))
(dotimes (i 4)
(should (eql (aref x i) (aref y i))))))
+
+;; Bug#39207
+(ert-deftest aset-nbytes-change ()
+ (let ((s (make-string 1 ?a)))
+ (dolist (c (list 10003 ?b 128 ?c ?d (max-char) ?e))
+ (aset s 0 c)
+ (should (equal s (make-string 1 c))))))
diff --git a/test/src/buffer-tests.el b/test/src/buffer-tests.el
index 445a3414cdf..123f2e8eabb 100644
--- a/test/src/buffer-tests.el
+++ b/test/src/buffer-tests.el
@@ -19,9 +19,7 @@
;;; Code:
-(require 'ert)
-(require 'seq)
-(eval-when-compile (require 'cl-lib))
+(require 'cl-lib)
(ert-deftest overlay-modification-hooks-message-other-buf ()
"Test for bug#21824.
@@ -1314,4 +1312,53 @@ with parameters from the *Messages* buffer modification."
(ovshould nonempty-eob-end 4 5)
(ovshould empty-eob 5 5)))))
+(ert-deftest buffer-multibyte-overlong-sequences ()
+ (dolist (uni '("\xE0\x80\x80"
+ "\xF0\x80\x80\x80"
+ "\xF8\x8F\xBF\xBF\x80"))
+ (let ((multi (string-to-multibyte uni)))
+ (should
+ (string-equal
+ multi
+ (with-temp-buffer
+ (set-buffer-multibyte nil)
+ (insert uni)
+ (set-buffer-multibyte t)
+ (buffer-string)))))))
+
+;; https://debbugs.gnu.org/33492
+(ert-deftest buffer-tests-buffer-local-variables-undo ()
+ "Test that `buffer-undo-list' appears in `buffer-local-variables'."
+ (with-temp-buffer
+ (should (assq 'buffer-undo-list (buffer-local-variables)))))
+
+(ert-deftest buffer-tests-inhibit-buffer-hooks ()
+ "Test `get-buffer-create' argument INHIBIT-BUFFER-HOOKS."
+ (let* (run-bluh (bluh (lambda () (setq run-bluh t))))
+ (unwind-protect
+ (let* ( run-kbh (kbh (lambda () (setq run-kbh t)))
+ run-kbqf (kbqf (lambda () (setq run-kbqf t))) )
+
+ ;; Inhibited.
+ (add-hook 'buffer-list-update-hook bluh)
+ (with-current-buffer (generate-new-buffer " foo" t)
+ (add-hook 'kill-buffer-hook kbh nil t)
+ (add-hook 'kill-buffer-query-functions kbqf nil t)
+ (kill-buffer))
+ (with-temp-buffer)
+ (with-output-to-string)
+ (should-not run-bluh)
+ (should-not run-kbh)
+ (should-not run-kbqf)
+
+ ;; Not inhibited.
+ (with-current-buffer (generate-new-buffer " foo")
+ (should run-bluh)
+ (add-hook 'kill-buffer-hook kbh nil t)
+ (add-hook 'kill-buffer-query-functions kbqf nil t)
+ (kill-buffer))
+ (should run-kbh)
+ (should run-kbqf))
+ (remove-hook 'buffer-list-update-hook bluh))))
+
;;; buffer-tests.el ends here
diff --git a/test/src/callint-tests.el b/test/src/callint-tests.el
index a2abac458d1..0df58877102 100644
--- a/test/src/callint-tests.el
+++ b/test/src/callint-tests.el
@@ -29,7 +29,8 @@
(ert-deftest call-interactively/incomplete-multibyte-sequence ()
"Check that Bug#30004 is fixed."
- (let ((data (should-error (call-interactively (lambda () (interactive "\xFF"))))))
+ (let* ((text-quoting-style 'grave)
+ (data (should-error (call-interactively (lambda () (interactive "\xFF"))))))
(should
(equal
(cdr data)
diff --git a/test/src/callproc-tests.el b/test/src/callproc-tests.el
index 71a4127dadb..7262abbe0d0 100644
--- a/test/src/callproc-tests.el
+++ b/test/src/callproc-tests.el
@@ -17,6 +17,11 @@
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; Unit tests for src/callproc.c.
+
;;; Code:
(require 'ert)
@@ -60,3 +65,15 @@
(call-process "c:/nul.exe")
(error :got-error))))
(should have-called-debugger)))
+
+(ert-deftest call-process-region-entire-buffer-with-delete ()
+ "Check that Bug#40576 is fixed."
+ (let ((emacs (expand-file-name invocation-name invocation-directory)))
+ (skip-unless (file-executable-p emacs))
+ (with-temp-buffer
+ (insert "Buffer contents\n")
+ (should
+ (eq (call-process-region nil nil emacs :delete nil nil "--version") 0))
+ (should (eq (buffer-size) 0)))))
+
+;;; callproc-tests.el ends here
diff --git a/test/src/casefiddle-tests.el b/test/src/casefiddle-tests.el
index 714dd8f35d8..9fa54dcaf43 100644
--- a/test/src/casefiddle-tests.el
+++ b/test/src/casefiddle-tests.el
@@ -247,7 +247,8 @@
;; input upcase downcase [titlecase]
(dolist (test '((?a ?A ?a) (?A ?A ?a)
(?ł ?Ł ?ł) (?Ł ?Ł ?ł)
- (?ß ?ß ?ß) (?ẞ ?ẞ ?ß)
+ ;; We char-upcase ß to ẞ; see bug #11309.
+ (?ß ?ẞ ?ß) (?ẞ ?ẞ ?ß)
(?ⅷ ?Ⅷ ?ⅷ) (?Ⅷ ?Ⅷ ?ⅷ)
(?DŽ ?DŽ ?dž ?Dž) (?Dž ?DŽ ?dž ?Dž) (?dž ?DŽ ?dž ?Dž)))
(let ((ch (car test))
diff --git a/test/src/charset-tests.el b/test/src/charset-tests.el
index a97c8b6f1c8..5c46627c163 100644
--- a/test/src/charset-tests.el
+++ b/test/src/charset-tests.el
@@ -1,19 +1,21 @@
-;;; charset-tests.el --- Tests for charset.c
+;;; charset-tests.el --- Tests for charset.c -*- lexical-binding: t -*-
;; Copyright 2017-2021 Free Software Foundation, Inc.
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Code:
diff --git a/test/src/chartab-tests.el b/test/src/chartab-tests.el
index d96ba0a0615..bf37fb51cf5 100644
--- a/test/src/chartab-tests.el
+++ b/test/src/chartab-tests.el
@@ -1,21 +1,23 @@
-;;; chartab-tests.el --- Tests for char-tab.c
+;;; chartab-tests.el --- Tests for char-tab.c -*- lexical-binding: t -*-
;; Copyright (C) 2016-2021 Free Software Foundation, Inc.
;; Author: Eli Zaretskii <eliz@gnu.org>
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Code:
@@ -47,5 +49,25 @@
(#xe0e00 . #xe0ef6)
)))
+(ert-deftest chartab-test-char-table-p ()
+ (should (char-table-p (make-char-table 'foo)))
+ (should (not (char-table-p (make-hash-table)))))
+
+(ert-deftest chartab-test-char-table-subtype ()
+ (should (eq (char-table-subtype (make-char-table 'foo)) 'foo)))
+
+(ert-deftest chartab-test-char-table-parent ()
+ (should (eq (char-table-parent (make-char-table 'foo)) nil))
+ (let ((parent (make-char-table 'foo))
+ (child (make-char-table 'bar)))
+ (set-char-table-parent child parent)
+ (should (eq (char-table-parent child) parent))))
+
+(ert-deftest chartab-test-char-table-extra-slot ()
+ ;; Use any type with extra slots, e.g. 'case-table.
+ (let ((tbl (make-char-table 'case-table)))
+ (set-char-table-extra-slot tbl 1 'bar)
+ (should (eq (char-table-extra-slot tbl 1) 'bar))))
+
(provide 'chartab-tests)
;;; chartab-tests.el ends here
diff --git a/test/src/cmds-tests.el b/test/src/cmds-tests.el
index e07289d2264..681bfb30164 100644
--- a/test/src/cmds-tests.el
+++ b/test/src/cmds-tests.el
@@ -1,22 +1,24 @@
-;;; cmds-tests.el --- Testing some Emacs commands
+;;; cmds-tests.el --- Testing some Emacs commands -*- lexical-binding: t -*-
;; Copyright (C) 2013-2021 Free Software Foundation, Inc.
;; Author: Nicolas Richard <youngfrog@members.fsf.org>
;; Keywords:
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
diff --git a/test/src/coding-tests.el b/test/src/coding-tests.el
index 4008b510223..0bdcff22ce5 100644
--- a/test/src/coding-tests.el
+++ b/test/src/coding-tests.el
@@ -1,4 +1,4 @@
-;;; coding-tests.el --- tests for text encoding and decoding
+;;; coding-tests.el --- tests for text encoding and decoding -*- lexical-binding: t -*-
;; Copyright (C) 2013-2021 Free Software Foundation, Inc.
@@ -296,7 +296,7 @@
;;; decoder, not for regression testing.
(defun generate-ascii-file ()
- (dotimes (i 100000)
+ (dotimes (_i 100000)
(insert-char ?a 80)
(insert "\n")))
@@ -309,13 +309,13 @@
(insert "\n")))
(defun generate-mostly-nonascii-file ()
- (dotimes (i 30000)
+ (dotimes (_i 30000)
(insert-char ?a 80)
(insert "\n"))
- (dotimes (i 20000)
+ (dotimes (_i 20000)
(insert-char ?À 80)
(insert "\n"))
- (dotimes (i 10000)
+ (dotimes (_i 10000)
(insert-char ?あ 80)
(insert "\n")))
@@ -375,6 +375,60 @@
(with-temp-buffer (insert-file-contents (car file))))))
(insert (format "%s: %s\n" (car file) result)))))))
+(ert-deftest coding-nocopy-trivial ()
+ "Check that the NOCOPY parameter works for the trivial coding system."
+ (let ((s "abc"))
+ (should-not (eq (decode-coding-string s nil nil) s))
+ (should (eq (decode-coding-string s nil t) s))
+ (should-not (eq (encode-coding-string s nil nil) s))
+ (should (eq (encode-coding-string s nil t) s))))
+
+(ert-deftest coding-nocopy-ascii ()
+ "Check that the NOCOPY parameter works for ASCII-only strings."
+ (let* ((uni (apply #'string (number-sequence 0 127)))
+ (multi (string-to-multibyte uni)))
+ (dolist (s (list uni multi))
+ ;; Encodings without EOL conversion.
+ (dolist (coding '(us-ascii-unix iso-latin-1-unix utf-8-unix))
+ (should-not (eq (decode-coding-string s coding nil) s))
+ (should-not (eq (encode-coding-string s coding nil) s))
+ (should (eq (decode-coding-string s coding t) s))
+ (should (eq (encode-coding-string s coding t) s))
+ (should (eq last-coding-system-used coding)))
+
+ ;; With EOL conversion inhibited.
+ (let ((inhibit-eol-conversion t))
+ (dolist (coding '(us-ascii iso-latin-1 utf-8))
+ (should-not (eq (decode-coding-string s coding nil) s))
+ (should-not (eq (encode-coding-string s coding nil) s))
+ (should (eq (decode-coding-string s coding t) s))
+ (should (eq (encode-coding-string s coding t) s))))))
+
+ ;; Check identity decoding with EOL conversion for ASCII except CR.
+ (let* ((uni (apply #'string (delq ?\r (number-sequence 0 127))))
+ (multi (string-to-multibyte uni)))
+ (dolist (s (list uni multi))
+ (dolist (coding '(us-ascii-dos iso-latin-1-dos utf-8-dos mac-roman-mac))
+ (should-not (eq (decode-coding-string s coding nil) s))
+ (should (eq (decode-coding-string s coding t) s)))))
+
+ ;; Check identity encoding with EOL conversion for ASCII except LF.
+ (let* ((uni (apply #'string (delq ?\n (number-sequence 0 127))))
+ (multi (string-to-multibyte uni)))
+ (dolist (s (list uni multi))
+ (dolist (coding '(us-ascii-dos iso-latin-1-dos utf-8-dos mac-roman-mac))
+ (should-not (eq (encode-coding-string s coding nil) s))
+ (should (eq (encode-coding-string s coding t) s))))))
+
+
+(ert-deftest coding-check-coding-systems-region ()
+ (should (equal (check-coding-systems-region "aå" nil '(utf-8))
+ nil))
+ (should (equal (check-coding-systems-region "aåbγc" nil
+ '(utf-8 iso-latin-1 us-ascii))
+ '((iso-latin-1 3) (us-ascii 1 3))))
+ (should-error (check-coding-systems-region "å" nil '(bad-coding-system))))
+
;; Local Variables:
;; byte-compile-warnings: (not obsolete)
;; End:
diff --git a/test/src/data-tests.el b/test/src/data-tests.el
index 33b206d8cf3..03d867f18a8 100644
--- a/test/src/data-tests.el
+++ b/test/src/data-tests.el
@@ -324,7 +324,7 @@ comparing the subr with a much slower lisp implementation."
(defvar binding-test-some-local 'some)
(with-current-buffer binding-test-buffer-A
- (set (make-local-variable 'binding-test-some-local) 'local))
+ (setq-local binding-test-some-local 'local))
(ert-deftest binding-test-manual ()
"A test case from the elisp manual."
@@ -345,6 +345,25 @@ comparing the subr with a much slower lisp implementation."
(setq-default binding-test-some-local 'new-default))
(should (eq binding-test-some-local 'some))))
+(ert-deftest data-tests--let-buffer-local ()
+ (let ((blvar (make-symbol "blvar")))
+ (set-default blvar nil)
+ (make-variable-buffer-local blvar)
+
+ (dolist (var (list blvar 'left-margin))
+ (let ((def (default-value var)))
+ (with-temp-buffer
+ (should (equal def (symbol-value var)))
+ (cl-progv (list var) (list 42)
+ (should (equal (symbol-value var) 42))
+ (should (equal (default-value var) (symbol-value var)))
+ (set var 123)
+ (should (equal (symbol-value var) 123))
+ (should (equal (default-value var) (symbol-value var)))) ;bug#44733
+ (should (equal (symbol-value var) def))
+ (should (equal (default-value var) (symbol-value var))))
+ (should (equal (default-value var) def))))))
+
(ert-deftest binding-test-makunbound ()
"Tests of makunbound, from the manual."
(with-current-buffer binding-test-buffer-B
@@ -381,6 +400,37 @@ comparing the subr with a much slower lisp implementation."
"Test setting a keyword to itself"
(with-no-warnings (should (setq :keyword :keyword))))
+(ert-deftest data-tests--set-default-per-buffer ()
+ :expected-result t ;; Not fixed yet!
+ ;; FIXME: Performance tests are inherently unreliable.
+ ;; Using wall-clock time makes it even worse, so don't bother unless
+ ;; we have the primitive to measure cpu-time.
+ (skip-unless (fboundp 'current-cpu-time))
+ ;; Test performance of set-default on DEFVAR_PER_BUFFER variables.
+ ;; More specifically, test the problem seen in bug#41029 where setting
+ ;; the default value of a variable takes time proportional to the
+ ;; number of buffers.
+ (let* ((fun #'error)
+ (test (lambda ()
+ (with-temp-buffer
+ (let ((st (car (current-cpu-time))))
+ (dotimes (_ 1000)
+ (let ((case-fold-search 'data-test))
+ ;; Use an indirection through a mutable var
+ ;; to try and make sure the byte-compiler
+ ;; doesn't optimize away the let bindings.
+ (funcall fun)))
+ ;; FIXME: Handle the wraparound, if any.
+ (- (car (current-cpu-time)) st)))))
+ (_ (setq fun #'ignore))
+ (time1 (funcall test))
+ (bufs (mapcar (lambda (_) (generate-new-buffer " data-test"))
+ (make-list 1000 nil)))
+ (time2 (funcall test)))
+ (mapc #'kill-buffer bufs)
+ ;; Don't divide one time by the other since they may be 0.
+ (should (< time2 (* time1 5)))))
+
;; More tests to write -
;; kill-local-variable
;; defconst; can modify
diff --git a/test/src/decompress-tests.el b/test/src/decompress-tests.el
index 3ada74be5c4..67a7fefb05e 100644
--- a/test/src/decompress-tests.el
+++ b/test/src/decompress-tests.el
@@ -1,4 +1,4 @@
-;;; decompress-tests.el --- Test suite for decompress.
+;;; decompress-tests.el --- Test suite for decompress. -*- lexical-binding: t -*-
;; Copyright (C) 2013-2021 Free Software Foundation, Inc.
diff --git a/test/src/doc-tests.el b/test/src/doc-tests.el
deleted file mode 100644
index 107785945de..00000000000
--- a/test/src/doc-tests.el
+++ /dev/null
@@ -1,96 +0,0 @@
-;;; doc-tests.el --- Tests for doc.c
-
-;; Copyright (C) 2016-2021 Free Software Foundation, Inc.
-
-;; Author: Eli Zaretskii <eliz@gnu.org>
-
-;; This program 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.
-
-;; This program 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 <https://www.gnu.org/licenses/>.
-
-;;; Code:
-
-(require 'ert)
-
-(ert-deftest doc-test-substitute-command-keys ()
- ;; Bindings.
- (should (string= (substitute-command-keys "foo \\[goto-char]") "foo M-g c"))
- ;; Cannot use string= here, as that compares unibyte and multibyte
- ;; strings not equal.
- (should (compare-strings
- (substitute-command-keys "\200 \\[goto-char]") nil nil
- "\200 M-g c" nil nil))
- ;; Literals.
- (should (string= (substitute-command-keys "foo \\=\\[goto-char]")
- "foo \\[goto-char]"))
- (should (string= (substitute-command-keys "foo \\=\\=")
- "foo \\="))
- ;; Keymaps.
- ;; I don't see that this is testing anything useful.
- ;; AFAICS all it does it fail whenever someone modifies the
- ;; minibuffer map.
-;;; (should (string= (substitute-command-keys
-;;; "\\{minibuffer-local-must-match-map}")
-;;; "\
-;;; key binding
-;;; --- -------
-;;;
-;;; C-g abort-recursive-edit
-;;; TAB minibuffer-complete
-;;; C-j minibuffer-complete-and-exit
-;;; RET minibuffer-complete-and-exit
-;;; ESC Prefix Command
-;;; SPC minibuffer-complete-word
-;;; ? minibuffer-completion-help
-;;; <C-tab> file-cache-minibuffer-complete
-;;; <XF86Back> previous-history-element
-;;; <XF86Forward> next-history-element
-;;; <down> next-line-or-history-element
-;;; <next> next-history-element
-;;; <prior> switch-to-completions
-;;; <up> previous-line-or-history-element
-;;;
-;;; M-v switch-to-completions
-;;;
-;;; M-< minibuffer-beginning-of-buffer
-;;; M-n next-history-element
-;;; M-p previous-history-element
-;;; M-r previous-matching-history-element
-;;; M-s next-matching-history-element
-;;;
-;;; "))
- (should (string=
- (substitute-command-keys
- "\\<minibuffer-local-must-match-map>\\[abort-recursive-edit]")
- "C-g"))
- ;; Allow any style of quotes, since the terminal might not support
- ;; UTF-8.
- (should (string-match
- "\nUses keymap [`‘']foobar-map['’], which is not currently defined.\n"
- (substitute-command-keys "\\{foobar-map}")))
- ;; Quotes.
- (should (let ((text-quoting-style 'grave))
- (string= (substitute-command-keys "quotes `like this'")
- "quotes `like this'")))
- (should (let ((text-quoting-style 'grave))
- (string= (substitute-command-keys "quotes ‘like this’")
- "quotes ‘like this’")))
- (should (let ((text-quoting-style 'straight))
- (string= (substitute-command-keys "quotes `like this'")
- "quotes 'like this'")))
- ;; Bugs.
- (should (string= (substitute-command-keys "\\[foobar") "\\[foobar"))
- (should (string= (substitute-command-keys "\\=") "\\="))
- )
-
-(provide 'doc-tests)
-;;; doc-tests.el ends here
diff --git a/test/src/editfns-tests.el b/test/src/editfns-tests.el
index fa5d04ee962..64f9137865b 100644
--- a/test/src/editfns-tests.el
+++ b/test/src/editfns-tests.el
@@ -1,21 +1,21 @@
-;;; editfns-tests.el -- tests for editfns.c
+;;; editfns-tests.el -- tests for editfns.c -*- lexical-binding:t -*-
;; Copyright (C) 2016-2021 Free Software Foundation, Inc.
;; This file is part of GNU Emacs.
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Code:
@@ -124,8 +124,8 @@
"Validate character position to byte position translation."
(let ((bytes '()))
(dotimes (pos len)
- (setq bytes (add-to-list 'bytes (position-bytes (1+ pos)) t)))
- bytes))
+ (push (position-bytes (1+ pos)) bytes))
+ (nreverse bytes)))
(ert-deftest transpose-ascii-regions-test ()
(with-temp-buffer
diff --git a/test/data/emacs-module/mod-test.c b/test/src/emacs-module-resources/mod-test.c
index d1ffeea01d6..ad59cfc18cd 100644
--- a/test/data/emacs-module/mod-test.c
+++ b/test/src/emacs-module-resources/mod-test.c
@@ -24,17 +24,27 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <errno.h>
#include <limits.h>
+#include <stdbool.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
-#ifdef HAVE_GMP
-#include <gmp.h>
-#else
-#include "mini-gmp.h"
+#ifdef WINDOWSNT
+/* Cannot include <process.h> because of the local header by the same
+ name, sigh. */
+uintptr_t _beginthread (void (__cdecl *)(void *), unsigned, void *);
+# if !defined __x86_64__
+# define ALIGN_STACK __attribute__((force_align_arg_pointer))
+# endif
+# include <windows.h> /* for Sleep */
+#else /* !WINDOWSNT */
+# include <pthread.h>
+# include <unistd.h>
#endif
+#include <gmp.h>
#include <emacs-module.h>
#include "timespec.h"
@@ -86,6 +96,7 @@ static emacs_value
Fmod_test_sum (emacs_env *env, ptrdiff_t nargs, emacs_value args[], void *data)
{
assert (nargs == 2);
+ assert ((uintptr_t) data == 0x1234);
intmax_t a = env->extract_integer (env, args[0]);
intmax_t b = env->extract_integer (env, args[1]);
@@ -252,7 +263,19 @@ Fmod_test_string_a_to_b (emacs_env *env, ptrdiff_t nargs, emacs_value args[],
if (buf[i] == 'a')
buf[i] = 'b';
- return env->make_string (env, buf, size - 1);
+ emacs_value ret = env->make_string (env, buf, size - 1);
+ free (buf);
+ return ret;
+}
+
+
+/* Return a unibyte string. */
+static emacs_value
+Fmod_test_return_unibyte (emacs_env *env, ptrdiff_t nargs, emacs_value args[],
+ void *data)
+{
+ const char *string = "foo\x00zot";
+ return env->make_unibyte_string (env, string, 7);
}
@@ -354,7 +377,7 @@ Fmod_test_invalid_store_copy (emacs_env *env, ptrdiff_t nargs,
}
/* An invalid finalizer: Finalizers are run during garbage collection,
- where Lisp code can’t be executed. -module-assertions tests for
+ where Lisp code can't be executed. -module-assertions tests for
this case. */
static emacs_env *current_env;
@@ -375,9 +398,9 @@ Fmod_test_invalid_finalizer (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
}
static void
-signal_errno (emacs_env *env, const char *function)
+signal_system_error (emacs_env *env, int error, const char *function)
{
- const char *message = strerror (errno);
+ const char *message = strerror (error);
emacs_value message_value = env->make_string (env, message, strlen (message));
emacs_value symbol = env->intern (env, "file-error");
emacs_value elements[2]
@@ -386,6 +409,12 @@ signal_errno (emacs_env *env, const char *function)
env->non_local_exit_signal (env, symbol, data);
}
+static void
+signal_errno (emacs_env *env, const char *function)
+{
+ signal_system_error (env, errno, function);
+}
+
/* A long-running operation that occasionally calls `should_quit' or
`process_input'. */
@@ -430,15 +459,20 @@ Fmod_test_add_nanosecond (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
}
static void
-memory_full (emacs_env *env)
+signal_error (emacs_env *env, const char *message)
{
- const char *message = "Memory exhausted";
emacs_value data = env->make_string (env, message, strlen (message));
env->non_local_exit_signal (env, env->intern (env, "error"),
env->funcall (env, env->intern (env, "list"), 1,
&data));
}
+static void
+memory_full (emacs_env *env)
+{
+ signal_error (env, "Memory exhausted");
+}
+
enum
{
max_count = ((SIZE_MAX < PTRDIFF_MAX ? SIZE_MAX : PTRDIFF_MAX)
@@ -547,6 +581,153 @@ Fmod_test_double (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
return result;
}
+static int function_data;
+static int finalizer_calls_with_correct_data;
+static int finalizer_calls_with_incorrect_data;
+
+static void
+finalizer (void *data)
+{
+ if (data == &function_data)
+ ++finalizer_calls_with_correct_data;
+ else
+ ++finalizer_calls_with_incorrect_data;
+}
+
+static emacs_value
+Fmod_test_make_function_with_finalizer (emacs_env *env, ptrdiff_t nargs,
+ emacs_value *args, void *data)
+{
+ emacs_value fun
+ = env->make_function (env, 2, 2, Fmod_test_sum, NULL, &function_data);
+ env->set_function_finalizer (env, fun, finalizer);
+ if (env->get_function_finalizer (env, fun) != finalizer)
+ signal_error (env, "Invalid finalizer");
+ return fun;
+}
+
+static emacs_value
+Fmod_test_function_finalizer_calls (emacs_env *env, ptrdiff_t nargs,
+ emacs_value *args, void *data)
+{
+ emacs_value Flist = env->intern (env, "list");
+ emacs_value list_args[]
+ = {env->make_integer (env, finalizer_calls_with_correct_data),
+ env->make_integer (env, finalizer_calls_with_incorrect_data)};
+ return env->funcall (env, Flist, 2, list_args);
+}
+
+static void
+sleep_for_half_second (void)
+{
+ /* mingw.org's MinGW has nanosleep, but MinGW64 doesn't. */
+#ifdef WINDOWSNT
+ Sleep (500);
+#else
+ const struct timespec sleep = {0, 500000000};
+ if (nanosleep (&sleep, NULL) != 0)
+ perror ("nanosleep");
+#endif
+}
+
+#ifdef WINDOWSNT
+static void ALIGN_STACK
+#else
+static void *
+#endif
+write_to_pipe (void *arg)
+{
+ /* We sleep a bit to test that writing to a pipe is indeed possible
+ if no environment is active. */
+ sleep_for_half_second ();
+ FILE *stream = arg;
+ /* The string below should be identical to the one we compare with
+ in emacs-module-tests.el:module/async-pipe. */
+ if (fputs ("data from thread", stream) < 0)
+ perror ("fputs");
+ if (fclose (stream) != 0)
+ perror ("close");
+#ifndef WINDOWSNT
+ return NULL;
+#endif
+}
+
+static emacs_value
+Fmod_test_async_pipe (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
+ void *data)
+{
+ assert (nargs == 1);
+ int fd = env->open_channel (env, args[0]);
+ if (env->non_local_exit_check (env) != emacs_funcall_exit_return)
+ return NULL;
+ FILE *stream = fdopen (fd, "w");
+ if (stream == NULL)
+ {
+ signal_errno (env, "fdopen");
+ return NULL;
+ }
+#ifdef WINDOWSNT
+ uintptr_t thd = _beginthread (write_to_pipe, 0, stream);
+ int error = (thd == (uintptr_t)-1L) ? errno : 0;
+#else /* !WINDOWSNT */
+ pthread_t thread;
+ int error
+ = pthread_create (&thread, NULL, write_to_pipe, stream);
+#endif
+ if (error != 0)
+ {
+ signal_system_error (env, error, "thread create");
+ if (fclose (stream) != 0)
+ perror ("fclose");
+ return NULL;
+ }
+ return env->intern (env, "nil");
+}
+
+static emacs_value
+Fmod_test_identity (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
+ void *data)
+{
+ assert (nargs == 1);
+ return args[0];
+}
+
+static emacs_value
+Fmod_test_funcall (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
+ void *data)
+{
+ assert (0 < nargs);
+ return env->funcall (env, args[0], nargs - 1, args + 1);
+}
+
+static emacs_value
+Fmod_test_make_string (emacs_env *env, ptrdiff_t nargs,
+ emacs_value *args, void *data)
+{
+ assert (nargs == 2);
+ intmax_t length_arg = env->extract_integer (env, args[0]);
+ if (env->non_local_exit_check (env) != emacs_funcall_exit_return)
+ return args[0];
+ if (length_arg < 0 || SIZE_MAX < length_arg)
+ {
+ signal_error (env, "Invalid string length");
+ return args[0];
+ }
+ size_t length = (size_t) length_arg;
+ bool multibyte = env->is_not_nil (env, args[1]);
+ char *buffer = length == 0 ? NULL : malloc (length);
+ if (buffer == NULL && length != 0)
+ {
+ memory_full (env);
+ return args[0];
+ }
+ memset (buffer, 'a', length);
+ emacs_value ret = multibyte ? env->make_string (env, buffer, length)
+ : env->make_unibyte_string (env, buffer, length);
+ free (buffer);
+ return ret;
+}
+
/* Lisp utilities for easier readability (simple wrappers). */
/* Provide FEATURE to Emacs. */
@@ -603,7 +784,8 @@ emacs_module_init (struct emacs_runtime *ert)
env->make_function (env, amin, amax, csym, doc, data))
DEFUN ("mod-test-return-t", Fmod_test_return_t, 1, 1, NULL, NULL);
- DEFUN ("mod-test-sum", Fmod_test_sum, 2, 2, "Return A + B\n\n(fn a b)", NULL);
+ DEFUN ("mod-test-sum", Fmod_test_sum, 2, 2, "Return A + B\n\n(fn a b)",
+ (void *) (uintptr_t) 0x1234);
DEFUN ("mod-test-signal", Fmod_test_signal, 0, 0, NULL, NULL);
DEFUN ("mod-test-throw", Fmod_test_throw, 0, 0, NULL, NULL);
DEFUN ("mod-test-non-local-exit-funcall", Fmod_test_non_local_exit_funcall,
@@ -615,6 +797,7 @@ emacs_module_init (struct emacs_runtime *ert)
DEFUN ("mod-test-globref-reordered", Fmod_test_globref_reordered, 0, 0, NULL,
NULL);
DEFUN ("mod-test-string-a-to-b", Fmod_test_string_a_to_b, 1, 1, NULL, NULL);
+ DEFUN ("mod-test-return-unibyte", Fmod_test_return_unibyte, 0, 0, NULL, NULL);
DEFUN ("mod-test-userptr-make", Fmod_test_userptr_make, 1, 1, NULL, NULL);
DEFUN ("mod-test-userptr-get", Fmod_test_userptr_get, 1, 1, NULL, NULL);
DEFUN ("mod-test-vector-fill", Fmod_test_vector_fill, 2, 2, NULL, NULL);
@@ -629,9 +812,36 @@ emacs_module_init (struct emacs_runtime *ert)
DEFUN ("mod-test-add-nanosecond", Fmod_test_add_nanosecond, 1, 1, NULL, NULL);
DEFUN ("mod-test-nanoseconds", Fmod_test_nanoseconds, 1, 1, NULL, NULL);
DEFUN ("mod-test-double", Fmod_test_double, 1, 1, NULL, NULL);
+ DEFUN ("mod-test-make-function-with-finalizer",
+ Fmod_test_make_function_with_finalizer, 0, 0, NULL, NULL);
+ DEFUN ("mod-test-function-finalizer-calls",
+ Fmod_test_function_finalizer_calls, 0, 0, NULL, NULL);
+ DEFUN ("mod-test-async-pipe", Fmod_test_async_pipe, 1, 1, NULL, NULL);
+ DEFUN ("mod-test-funcall", Fmod_test_funcall, 1, emacs_variadic_function,
+ NULL, NULL);
+ DEFUN ("mod-test-make-string", Fmod_test_make_string, 2, 2, NULL, NULL);
#undef DEFUN
+ emacs_value constant_fn
+ = env->make_function (env, 0, 0, Fmod_test_return_t, NULL, NULL);
+ env->make_interactive (env, constant_fn, env->intern (env, "nil"));
+ bind_function (env, "mod-test-return-t-int", constant_fn);
+
+ emacs_value identity_fn
+ = env->make_function (env, 1, 1, Fmod_test_identity, NULL, NULL);
+ const char *interactive_spec = "i";
+ env->make_interactive (env, identity_fn,
+ env->make_string (env, interactive_spec,
+ strlen (interactive_spec)));
+ bind_function (env, "mod-test-identity", identity_fn);
+
+ /* We allocate lots of values to trigger bugs in the frame allocator during
+ initialization. */
+ int count = 10000; /* larger than value_frame_size in emacs-module.c */
+ for (int i = 0; i < count; ++i)
+ env->make_integer (env, i);
+
provide (env, "mod-test");
return 0;
}
diff --git a/test/src/emacs-module-tests.el b/test/src/emacs-module-tests.el
index 23fa46958a1..af5bc2a0baf 100644
--- a/test/src/emacs-module-tests.el
+++ b/test/src/emacs-module-tests.el
@@ -21,21 +21,23 @@
;; Unit tests for the dynamic module facility. See Info node `(elisp)
;; Writing Dynamic Modules'. These tests make use of a small test
-;; module in test/data/emacs-module.
+;; module in the "emacs-module-resources" directory.
;;; Code:
+;;; Prelude
(require 'cl-lib)
(require 'ert)
+(require 'ert-x)
(require 'help-fns)
+(require 'subr-x)
(defconst mod-test-emacs
(expand-file-name invocation-name invocation-directory)
"File name of the Emacs binary currently running.")
(eval-and-compile
- (defconst mod-test-file
- (expand-file-name "../test/data/emacs-module/mod-test" invocation-directory)
+ (defconst mod-test-file (ert-resource-file "mod-test")
"File name of the module test file."))
(require 'mod-test mod-test-file)
@@ -48,9 +50,7 @@
(cl-defmethod emacs-module-tests--generic ((_ user-ptr))
'user-ptr)
-;;
-;; Basic tests.
-;;
+;;; Basic tests
(ert-deftest mod-test-sum-test ()
(should (= (mod-test-sum 1 2) 3))
@@ -60,8 +60,9 @@
(should (eq 0
(string-match
(concat "#<module function "
- "\\(at \\(0x\\)?[[:xdigit:]]+\\( from .*\\)?"
- "\\|Fmod_test_sum from .*\\)>")
+ "\\(at \\(0x\\)?[[:xdigit:]]+ "
+ "with data 0x1234\\( from .*\\)?"
+ "\\|Fmod_test_sum with data 0x1234 from .*\\)>")
(prin1-to-string (nth 1 descr)))))
(should (= (nth 2 descr) 3)))
(should-error (mod-test-sum "1" 2) :type 'wrong-type-argument)
@@ -97,13 +98,12 @@ changes."
(rx bos "#<module function "
(or "Fmod_test_sum"
(and "at 0x" (+ hex-digit)))
+ " with data 0x1234"
(? " from " (* nonl) "mod-test" (* nonl) )
">" eos)
(prin1-to-string func)))))
-;;
-;; Non-local exists (throw, signal).
-;;
+;;; Non-local exists (throw, signal)
(ert-deftest mod-test-non-local-exit-signal-test ()
(should-error (mod-test-signal))
@@ -140,9 +140,7 @@ changes."
(should (equal (mod-test-non-local-exit-funcall (lambda () (throw 'tag 32)))
'(throw tag 32))))
-;;
-;; String tests.
-;;
+;;; String tests
(defun multiply-string (s n)
"Return N copies of S concatenated together."
@@ -166,9 +164,7 @@ changes."
(ert-deftest mod-test-string-a-to-b-test ()
(should (string= (mod-test-string-a-to-b "aaa") "bbb")))
-;;
-;; User-pointer tests.
-;;
+;;; User-pointer tests
(ert-deftest mod-test-userptr-fun-test ()
(let* ((n 42)
@@ -182,9 +178,7 @@ changes."
;; TODO: try to test finalizer
-;;
-;; Vector tests.
-;;
+;;; Vector tests
(ert-deftest mod-test-vector-test ()
(dolist (s '(2 10 100 1000))
@@ -316,14 +310,15 @@ local reference."
(ert-deftest module/describe-function-1 ()
"Check that Bug#30163 is fixed."
(with-temp-buffer
- (let ((standard-output (current-buffer)))
+ (let ((standard-output (current-buffer))
+ (text-quoting-style 'grave))
(describe-function-1 #'mod-test-sum)
(goto-char (point-min))
- (while (re-search-forward "`[^']*/data/emacs-module/" nil t)
- (replace-match "`data/emacs-module/"))
+ (while (re-search-forward "`[^']*/src/emacs-module-resources/" nil t)
+ (replace-match "`src/emacs-module-resources/"))
(should (equal
(buffer-substring-no-properties 1 (point-max))
- (format "a module function in `data/emacs-module/mod-test%s'.
+ (format "a module function in `src/emacs-module-resources/mod-test%s'.
(mod-test-sum a b)
@@ -419,4 +414,166 @@ Interactively, you can try hitting \\[keyboard-quit] to quit."
(ert-info ((format "input: %d" input))
(should (= (mod-test-double input) (* 2 input))))))
+(ert-deftest module-darwin-secondary-suffix ()
+ "Check that on Darwin, both .so and .dylib suffixes work.
+See Bug#36226."
+ (skip-unless (eq system-type 'darwin))
+ (should (member ".dylib" load-suffixes))
+ (should (member ".so" load-suffixes))
+ ;; Preserve the old `load-history'. This is needed for some of the
+ ;; other unit tests that indirectly rely on `load-history'.
+ (let ((load-history load-history)
+ (dylib (concat mod-test-file ".dylib"))
+ (so (concat mod-test-file ".so")))
+ (should (file-regular-p dylib))
+ (should-not (file-exists-p so))
+ (add-name-to-file dylib so)
+ (unwind-protect
+ (load so nil nil :nosuffix :must-suffix)
+ (delete-file so))))
+
+(ert-deftest module/function-finalizer ()
+ "Test that module function finalizers are properly called."
+ ;; We create and leak a couple of module functions with attached
+ ;; finalizer. Creating only one function risks spilling it to the
+ ;; stack, where it wouldn't be garbage-collected. However, with one
+ ;; hundred functions, there should be at least one that's
+ ;; unreachable.
+ (dotimes (_ 100)
+ (mod-test-make-function-with-finalizer))
+ (cl-destructuring-bind (valid-before invalid-before)
+ (mod-test-function-finalizer-calls)
+ (should (zerop invalid-before))
+ (garbage-collect)
+ (cl-destructuring-bind (valid-after invalid-after)
+ (mod-test-function-finalizer-calls)
+ (should (zerop invalid-after))
+ ;; We don't require exactly 100 invocations of the finalizer,
+ ;; but at least one.
+ (should (> valid-after valid-before)))))
+
+(ert-deftest module/async-pipe ()
+ "Check that writing data from another thread works."
+ (skip-unless (not (eq system-type 'windows-nt))) ; FIXME!
+ (with-temp-buffer
+ (let ((process (make-pipe-process :name "module/async-pipe"
+ :buffer (current-buffer)
+ :coding 'utf-8-unix
+ :noquery t)))
+ (unwind-protect
+ (progn
+ (mod-test-async-pipe process)
+ (should (accept-process-output process 1))
+ ;; The string below must be identical to what
+ ;; mod-test.c:write_to_pipe produces.
+ (should (equal (buffer-string) "data from thread")))
+ (delete-process process)))))
+
+(ert-deftest module/interactive/return-t ()
+ (should (functionp (symbol-function #'mod-test-return-t)))
+ (should (module-function-p (symbol-function #'mod-test-return-t)))
+ (should-not (commandp #'mod-test-return-t))
+ (should-not (commandp (symbol-function #'mod-test-return-t)))
+ (should-not (interactive-form #'mod-test-return-t))
+ (should-not (interactive-form (symbol-function #'mod-test-return-t)))
+ (should-error (call-interactively #'mod-test-return-t)
+ :type 'wrong-type-argument))
+
+(ert-deftest module/interactive/return-t-int ()
+ (should (functionp (symbol-function #'mod-test-return-t-int)))
+ (should (module-function-p (symbol-function #'mod-test-return-t-int)))
+ (should (commandp #'mod-test-return-t-int))
+ (should (commandp (symbol-function #'mod-test-return-t-int)))
+ (should (equal (interactive-form #'mod-test-return-t-int) '(interactive)))
+ (should (equal (interactive-form (symbol-function #'mod-test-return-t-int))
+ '(interactive)))
+ (should (eq (mod-test-return-t-int) t))
+ (should (eq (call-interactively #'mod-test-return-t-int) t)))
+
+(ert-deftest module/interactive/identity ()
+ (should (functionp (symbol-function #'mod-test-identity)))
+ (should (module-function-p (symbol-function #'mod-test-identity)))
+ (should (commandp #'mod-test-identity))
+ (should (commandp (symbol-function #'mod-test-identity)))
+ (should (equal (interactive-form #'mod-test-identity) '(interactive "i")))
+ (should (equal (interactive-form (symbol-function #'mod-test-identity))
+ '(interactive "i")))
+ (should (eq (mod-test-identity 123) 123))
+ (should-not (call-interactively #'mod-test-identity)))
+
+(ert-deftest module/unibyte ()
+ (let ((result (mod-test-return-unibyte)))
+ (should (stringp result))
+ (should (not (multibyte-string-p (mod-test-return-unibyte))))
+ (should (equal result "foo\x00zot"))))
+
+(cl-defstruct (emacs-module-tests--variable
+ (:constructor nil)
+ (:constructor emacs-module-tests--make-variable
+ (name
+ &aux
+ (mutex (make-mutex name))
+ (condvar (make-condition-variable mutex name))))
+ (:copier nil))
+ "A variable that's protected by a mutex."
+ value
+ (mutex nil :read-only t :type mutex)
+ (condvar nil :read-only t :type condition-variable))
+
+(defun emacs-module-tests--wait-for-variable (variable desired)
+ (with-mutex (emacs-module-tests--variable-mutex variable)
+ (while (not (eq (emacs-module-tests--variable-value variable) desired))
+ (condition-wait (emacs-module-tests--variable-condvar variable)))))
+
+(defun emacs-module-tests--change-variable (variable new)
+ (with-mutex (emacs-module-tests--variable-mutex variable)
+ (setf (emacs-module-tests--variable-value variable) new)
+ (condition-notify (emacs-module-tests--variable-condvar variable) :all)))
+
+(ert-deftest emacs-module-tests/interleaved-threads ()
+ (let* ((state-1 (emacs-module-tests--make-variable "1"))
+ (state-2 (emacs-module-tests--make-variable "2"))
+ (thread-1
+ (make-thread
+ (lambda ()
+ (emacs-module-tests--change-variable state-1 'before-module)
+ (mod-test-funcall
+ (lambda ()
+ (emacs-module-tests--change-variable state-1 'in-module)
+ (emacs-module-tests--wait-for-variable state-2 'in-module)))
+ (emacs-module-tests--change-variable state-1 'after-module))
+ "thread 1"))
+ (thread-2
+ (make-thread
+ (lambda ()
+ (emacs-module-tests--change-variable state-2 'before-module)
+ (emacs-module-tests--wait-for-variable state-1 'in-module)
+ (mod-test-funcall
+ (lambda ()
+ (emacs-module-tests--change-variable state-2 'in-module)
+ (emacs-module-tests--wait-for-variable state-1 'after-module)))
+ (emacs-module-tests--change-variable state-2 'after-module))
+ "thread 2")))
+ (thread-join thread-1)
+ (thread-join thread-2)))
+
+(ert-deftest mod-test-make-string/empty ()
+ (dolist (multibyte '(nil t))
+ (ert-info ((format "Multibyte: %s" multibyte))
+ (let ((got (mod-test-make-string 0 multibyte)))
+ (should (stringp got))
+ (should (string-empty-p got))
+ (should (eq (multibyte-string-p got) multibyte))))))
+
+(ert-deftest mod-test-make-string/nonempty ()
+ (dolist (multibyte '(nil t))
+ (ert-info ((format "Multibyte: %s" multibyte))
+ (let ((first (mod-test-make-string 1 multibyte))
+ (second (mod-test-make-string 1 multibyte)))
+ (should (stringp first))
+ (should (eql (length first) 1))
+ (should (eq (multibyte-string-p first) multibyte))
+ (should (string-equal first second))
+ (should-not (eq first second))))))
+
;;; emacs-module-tests.el ends here
diff --git a/test/src/eval-tests.el b/test/src/eval-tests.el
index 46029d520d6..b2b7dfefda5 100644
--- a/test/src/eval-tests.el
+++ b/test/src/eval-tests.el
@@ -27,6 +27,7 @@
(require 'ert)
(eval-when-compile (require 'cl-lib))
+(require 'subr-x)
(ert-deftest eval-tests--bug24673 ()
"Check that Bug#24673 has been fixed."
@@ -176,4 +177,53 @@ in Common Lisp). Instead, make sure substitution in backquote
expressions works for identifiers starting with period."
(should (equal (let ((.x 'identity)) (eval `(,.x 'ok))) 'ok)))
+(ert-deftest eval-tests/backtrace-in-batch-mode ()
+ (let ((emacs (expand-file-name invocation-name invocation-directory)))
+ (skip-unless (file-executable-p emacs))
+ (with-temp-buffer
+ (let ((status (call-process emacs nil t nil
+ "--quick" "--batch"
+ (concat "--eval="
+ (prin1-to-string
+ '(progn
+ (defun foo () (error "Boo"))
+ (foo)))))))
+ (should (natnump status))
+ (should-not (eql status 0)))
+ (goto-char (point-min))
+ (ert-info ((concat "Process output:\n" (buffer-string)))
+ (search-forward " foo()")
+ (search-forward " normal-top-level()")))))
+
+(ert-deftest eval-tests/backtrace-in-batch-mode/inhibit ()
+ (let ((emacs (expand-file-name invocation-name invocation-directory)))
+ (skip-unless (file-executable-p emacs))
+ (with-temp-buffer
+ (let ((status (call-process
+ emacs nil t nil
+ "--quick" "--batch"
+ (concat "--eval="
+ (prin1-to-string
+ '(progn
+ (defun foo () (error "Boo"))
+ (let ((backtrace-on-error-noninteractive nil))
+ (foo))))))))
+ (should (natnump status))
+ (should-not (eql status 0)))
+ (should (equal (string-trim (buffer-string)) "Boo")))))
+
+(ert-deftest eval-tests/backtrace-in-batch-mode/demoted-errors ()
+ (let ((emacs (expand-file-name invocation-name invocation-directory)))
+ (skip-unless (file-executable-p emacs))
+ (with-temp-buffer
+ (should (eql 0 (call-process emacs nil t nil
+ "--quick" "--batch"
+ (concat "--eval="
+ (prin1-to-string
+ '(with-demoted-errors "Error: %S"
+ (error "Boo")))))))
+ (goto-char (point-min))
+ (should (equal (string-trim (buffer-string))
+ "Error: (error \"Boo\")")))))
+
;;; eval-tests.el ends here
diff --git a/test/src/fileio-tests.el b/test/src/fileio-tests.el
index c7f6e6f8eb1..7f193d4eeab 100644
--- a/test/src/fileio-tests.el
+++ b/test/src/fileio-tests.el
@@ -98,15 +98,14 @@ Also check that an encoding error can appear in a symlink."
(ert-deftest fileio-tests--relative-HOME ()
"Test that expand-file-name works even when HOME is relative."
- (let ((old-home (getenv "HOME")))
+ (let ((process-environment (copy-sequence process-environment)))
(setenv "HOME" "a/b/c")
(should (equal (expand-file-name "~/foo")
(expand-file-name "a/b/c/foo")))
(when (memq system-type '(ms-dos windows-nt))
;; Test expansion of drive-relative file names.
(setenv "HOME" "x:foo")
- (should (equal (expand-file-name "~/bar") "x:/foo/bar")))
- (setenv "HOME" old-home)))
+ (should (equal (expand-file-name "~/bar") "x:/foo/bar")))))
(ert-deftest fileio-tests--insert-file-interrupt ()
(let ((text "-*- coding: binary -*-\n\xc3\xc3help")
@@ -156,3 +155,9 @@ Also check that an encoding error can appear in a symlink."
(write-region "hello\n" nil f nil 'silent)
(should-error (insert-file-contents f) :type 'circular-list)
(delete-file f)))
+
+(ert-deftest fileio-tests/null-character ()
+ (should-error (file-exists-p "/foo\0bar")
+ :type 'wrong-type-argument))
+
+;;; fileio-tests.el ends here
diff --git a/test/src/floatfns-tests.el b/test/src/floatfns-tests.el
index d1943f1ee95..4a3c03d833e 100644
--- a/test/src/floatfns-tests.el
+++ b/test/src/floatfns-tests.el
@@ -1,4 +1,4 @@
-;;; floatfns-tests.el --- tests for floating point operations
+;;; floatfns-tests.el --- tests for floating point operations -*- lexical-binding: t -*-
;; Copyright 2017-2021 Free Software Foundation, Inc.
diff --git a/test/src/fns-tests.el b/test/src/fns-tests.el
index 16033a2ba90..a9daf878b81 100644
--- a/test/src/fns-tests.el
+++ b/test/src/fns-tests.el
@@ -1,4 +1,4 @@
-;;; fns-tests.el --- tests for src/fns.c
+;;; fns-tests.el --- tests for src/fns.c -*- lexical-binding:t -*-
;; Copyright (C) 2014-2021 Free Software Foundation, Inc.
@@ -49,21 +49,21 @@
(should-error (nreverse))
(should-error (nreverse 1))
(should-error (nreverse (make-char-table 'foo)))
- (should (equal (nreverse "xyzzy") "yzzyx"))
- (let ((A []))
+ (should (equal (nreverse (copy-sequence "xyzzy")) "yzzyx"))
+ (let ((A (vector)))
(nreverse A)
(should (equal A [])))
- (let ((A [0]))
+ (let ((A (vector 0)))
(nreverse A)
(should (equal A [0])))
- (let ((A [1 2 3 4]))
+ (let ((A (vector 1 2 3 4)))
(nreverse A)
(should (equal A [4 3 2 1])))
- (let ((A [1 2 3 4]))
+ (let ((A (vector 1 2 3 4)))
(nreverse A)
(nreverse A)
(should (equal A [1 2 3 4])))
- (let* ((A [1 2 3 4])
+ (let* ((A (vector 1 2 3 4))
(B (nreverse (nreverse A))))
(should (equal A B))))
@@ -146,13 +146,13 @@
;; Invalid UTF-8 sequences shall be indicated. How to create such strings?
(ert-deftest fns-tests-sort ()
- (should (equal (sort '(9 5 2 -1 5 3 8 7 4) (lambda (x y) (< x y)))
+ (should (equal (sort (list 9 5 2 -1 5 3 8 7 4) (lambda (x y) (< x y)))
'(-1 2 3 4 5 5 7 8 9)))
- (should (equal (sort '(9 5 2 -1 5 3 8 7 4) (lambda (x y) (> x y)))
+ (should (equal (sort (list 9 5 2 -1 5 3 8 7 4) (lambda (x y) (> x y)))
'(9 8 7 5 5 4 3 2 -1)))
- (should (equal (sort '[9 5 2 -1 5 3 8 7 4] (lambda (x y) (< x y)))
+ (should (equal (sort (vector 9 5 2 -1 5 3 8 7 4) (lambda (x y) (< x y)))
[-1 2 3 4 5 5 7 8 9]))
- (should (equal (sort '[9 5 2 -1 5 3 8 7 4] (lambda (x y) (> x y)))
+ (should (equal (sort (vector 9 5 2 -1 5 3 8 7 4) (lambda (x y) (> x y)))
[9 8 7 5 5 4 3 2 -1]))
(should (equal
(sort
@@ -166,13 +166,15 @@
(should (equal (should-error (sort "cba" #'<) :type 'wrong-type-argument)
'(wrong-type-argument list-or-vector-p "cba"))))
+(defvar w32-collate-ignore-punctuation)
+
(ert-deftest fns-tests-collate-sort ()
(skip-unless (fns-tests--collate-enabled-p))
;; Punctuation and whitespace characters are relevant for POSIX.
(should
(equal
- (sort '("11" "12" "1 1" "1 2" "1.1" "1.2")
+ (sort (list "11" "12" "1 1" "1 2" "1.1" "1.2")
(lambda (a b) (string-collate-lessp a b "POSIX")))
'("1 1" "1 2" "1.1" "1.2" "11" "12")))
;; Punctuation and whitespace characters are not taken into account
@@ -180,7 +182,7 @@
(when (eq system-type 'windows-nt)
(should
(equal
- (sort '("11" "12" "1 1" "1 2" "1.1" "1.2")
+ (sort (list "11" "12" "1 1" "1 2" "1.1" "1.2")
(lambda (a b)
(let ((w32-collate-ignore-punctuation t))
(string-collate-lessp
@@ -190,7 +192,7 @@
;; Diacritics are different letters for POSIX, they sort lexicographical.
(should
(equal
- (sort '("Ævar" "Agustín" "Adrian" "Eli")
+ (sort (list "Ævar" "Agustín" "Adrian" "Eli")
(lambda (a b) (string-collate-lessp a b "POSIX")))
'("Adrian" "Agustín" "Eli" "Ævar")))
;; Diacritics are sorted between similar letters for other locales,
@@ -198,7 +200,7 @@
(when (eq system-type 'windows-nt)
(should
(equal
- (sort '("Ævar" "Agustín" "Adrian" "Eli")
+ (sort (list "Ævar" "Agustín" "Adrian" "Eli")
(lambda (a b)
(let ((w32-collate-ignore-punctuation t))
(string-collate-lessp
@@ -212,7 +214,7 @@
(should (not (string-version-lessp "foo20000.png" "foo12.png")))
(should (string-version-lessp "foo.png" "foo2.png"))
(should (not (string-version-lessp "foo2.png" "foo.png")))
- (should (equal (sort '("foo12.png" "foo2.png" "foo1.png")
+ (should (equal (sort (list "foo12.png" "foo2.png" "foo1.png")
'string-version-lessp)
'("foo1.png" "foo2.png" "foo12.png")))
(should (string-version-lessp "foo2" "foo1234"))
@@ -228,9 +230,9 @@
(should (equal (func-arity 'format) '(1 . many)))
(require 'info)
(should (equal (func-arity 'Info-goto-node) '(1 . 3)))
- (should (equal (func-arity (lambda (&rest x))) '(0 . many)))
- (should (equal (func-arity (eval (lambda (x &optional y)) nil)) '(1 . 2)))
- (should (equal (func-arity (eval (lambda (x &optional y)) t)) '(1 . 2)))
+ (should (equal (func-arity (lambda (&rest _x))) '(0 . many)))
+ (should (equal (func-arity (eval '(lambda (_x &optional y)) nil)) '(1 . 2)))
+ (should (equal (func-arity (eval '(lambda (_x &optional y)) t)) '(1 . 2)))
(should (equal (func-arity 'let) '(1 . unevalled))))
(defun fns-tests--string-repeat (s o)
@@ -432,9 +434,9 @@
(should-error (mapcan))
(should-error (mapcan #'identity))
(should-error (mapcan #'identity (make-char-table 'foo)))
- (should (equal (mapcan #'list '(1 2 3)) '(1 2 3)))
+ (should (equal (mapcan #'list (list 1 2 3)) '(1 2 3)))
;; `mapcan' is destructive
- (let ((data '((foo) (bar))))
+ (let ((data (list (list 'foo) (list 'bar))))
(should (equal (mapcan #'identity data) '(foo bar)))
(should (equal data '((foo bar) (bar))))))
@@ -858,6 +860,22 @@
(puthash k k h)))
(should (= 100 (hash-table-count h)))))
+(ert-deftest test-sxhash-equal ()
+ (should (= (sxhash-equal (* most-positive-fixnum most-negative-fixnum))
+ (sxhash-equal (* most-positive-fixnum most-negative-fixnum))))
+ (should (= (sxhash-equal (make-string 1000 ?a))
+ (sxhash-equal (make-string 1000 ?a))))
+ (should (= (sxhash-equal (point-marker))
+ (sxhash-equal (point-marker))))
+ (should (= (sxhash-equal (make-vector 1000 (make-string 10 ?a)))
+ (sxhash-equal (make-vector 1000 (make-string 10 ?a)))))
+ (should (= (sxhash-equal (make-bool-vector 1000 t))
+ (sxhash-equal (make-bool-vector 1000 t))))
+ (should (= (sxhash-equal (make-char-table nil (make-string 10 ?a)))
+ (sxhash-equal (make-char-table nil (make-string 10 ?a)))))
+ (should (= (sxhash-equal (record 'a (make-string 10 ?a)))
+ (sxhash-equal (record 'a (make-string 10 ?a))))))
+
(ert-deftest test-secure-hash ()
(should (equal (secure-hash 'md5 "foobar")
"3858f62230ac3c915f300c664312c63f"))
@@ -874,6 +892,151 @@
(should (equal (secure-hash 'sha512 "foobar")
(concat "0a50261ebd1a390fed2bf326f2673c145582a6342d5"
"23204973d0219337f81616a8069b012587cf5635f69"
- "25f1b56c360230c19b273500ee013e030601bf2425"))))
+ "25f1b56c360230c19b273500ee013e030601bf2425")))
+ ;; Test that a call to getrandom returns the right format.
+ ;; This does not test randomness; it's merely a format check.
+ (should (string-match "\\`[0-9a-f]\\{128\\}\\'"
+ (secure-hash 'sha512 'iv-auto 100))))
+
+(ert-deftest test-vector-delete ()
+ (let ((v1 (make-vector 1000 1)))
+ (should (equal (delete t [nil t]) [nil]))
+ (should (equal (delete 1 v1) (vector)))
+ (should (equal (delete 2 v1) v1))))
+
+(ert-deftest string-search ()
+ (should (equal (string-search "zot" "foobarzot") 6))
+ (should (equal (string-search "foo" "foobarzot") 0))
+ (should (not (string-search "fooz" "foobarzot")))
+ (should (not (string-search "zot" "foobarzo")))
+ (should (equal (string-search "ab" "ab") 0))
+ (should (equal (string-search "ab\0" "ab") nil))
+ (should (equal (string-search "ab" "abababab" 3) 4))
+ (should (equal (string-search "ab" "ababac" 3) nil))
+ (should (equal (string-search "aaa" "aa") nil))
+ (let ((case-fold-search t))
+ (should (equal (string-search "ab" "AB") nil)))
-(provide 'fns-tests)
+ (should (equal
+ (string-search (make-string 2 130)
+ (concat "helló" (make-string 5 130 t) "bár"))
+ 5))
+ (should (equal
+ (string-search (make-string 2 127)
+ (concat "helló" (make-string 5 127 t) "bár"))
+ 5))
+
+ (should (equal (string-search "\377" "a\377ø") 1))
+ (should (equal (string-search "\377" "a\377a") 1))
+
+ (should (not (string-search (make-string 1 255) "a\377ø")))
+ (should (not (string-search (make-string 1 255) "a\377a")))
+
+ (should (equal (string-search "fóo" "zotfóo") 3))
+
+ (should (equal (string-search (string-to-multibyte "\377") "ab\377c") 2))
+ (should (equal (string-search "\303" "aøb") nil))
+ (should (equal (string-search "\270" "aøb") nil))
+ (should (equal (string-search "ø" "\303\270") nil))
+ (should (equal (string-search "ø" (make-string 32 ?a)) nil))
+ (should (equal (string-search "ø" (string-to-multibyte (make-string 32 ?a)))
+ nil))
+ (should (equal (string-search "o" (string-to-multibyte
+ (apply #'string
+ (number-sequence ?a ?z))))
+ 14))
+
+ (should (equal (string-search "a\U00010f98z" "a\U00010f98a\U00010f98z") 2))
+
+ (should-error (string-search "a" "abc" -1))
+ (should-error (string-search "a" "abc" 4))
+ (should-error (string-search "a" "abc" 100000000000))
+
+ (should (equal (string-search "a" "aaa" 3) nil))
+ (should (equal (string-search "aa" "aa" 1) nil))
+ (should (equal (string-search "\0" "") nil))
+
+ (should (equal (string-search "" "") 0))
+ (should-error (string-search "" "" 1))
+ (should (equal (string-search "" "abc") 0))
+ (should (equal (string-search "" "abc" 2) 2))
+ (should (equal (string-search "" "abc" 3) 3))
+ (should-error (string-search "" "abc" 4))
+ (should-error (string-search "" "abc" -1))
+
+ (should-not (string-search "ø" "foo\303\270"))
+ (should-not (string-search "\303\270" "ø"))
+ (should-not (string-search "\370" "ø"))
+ (should-not (string-search (string-to-multibyte "\370") "ø"))
+ (should-not (string-search "ø" "\370"))
+ (should-not (string-search "ø" (string-to-multibyte "\370")))
+ (should-not (string-search "\303\270" "\370"))
+ (should-not (string-search (string-to-multibyte "\303\270") "\370"))
+ (should-not (string-search "\303\270" (string-to-multibyte "\370")))
+ (should-not (string-search (string-to-multibyte "\303\270")
+ (string-to-multibyte "\370")))
+ (should-not (string-search "\370" "\303\270"))
+ (should-not (string-search (string-to-multibyte "\370") "\303\270"))
+ (should-not (string-search "\370" (string-to-multibyte "\303\270")))
+ (should-not (string-search (string-to-multibyte "\370")
+ (string-to-multibyte "\303\270")))
+ (should (equal (string-search (string-to-multibyte "o\303\270") "foo\303\270")
+ 2))
+ (should (equal (string-search "\303\270" "foo\303\270") 3)))
+
+(ert-deftest object-intervals ()
+ (should (equal (object-intervals (propertize "foo" 'bar 'zot))
+ '((0 3 (bar zot)))))
+ (should (equal (object-intervals (concat (propertize "foo" 'bar 'zot)
+ (propertize "foo" 'gazonk "gazonk")))
+ '((0 3 (bar zot)) (3 6 (gazonk "gazonk")))))
+ (should (equal
+ (with-temp-buffer
+ (insert "foobar")
+ (put-text-property 1 3 'foo 1)
+ (put-text-property 3 6 'bar 2)
+ (put-text-property 2 5 'zot 3)
+ (object-intervals (current-buffer)))
+ '((0 1 (foo 1)) (1 2 (zot 3 foo 1)) (2 4 (zot 3 bar 2))
+ (4 5 (bar 2)) (5 6 nil)))))
+
+(ert-deftest length-equals-tests ()
+ (should-not (length< (list 1 2 3) 2))
+ (should-not (length< (list 1 2 3) 3))
+ (should (length< (list 1 2 3) 4))
+
+ (should-not (length< "abc" 2))
+ (should-not (length< "abc" 3))
+ (should (length< "abc" 4))
+
+ (should (length> (list 1 2 3) 2))
+ (should-not (length> (list 1 2 3) 3))
+ (should-not (length> (list 1 2 3) 4))
+
+ (should (length> "abc" 2))
+ (should-not (length> "abc" 3))
+ (should-not (length> "abc" 4))
+
+ (should-not (length= (list 1 2 3) 2))
+ (should (length= (list 1 2 3) 3))
+ (should-not (length= (list 1 2 3) 4))
+
+ (should-not (length= "abc" 2))
+ (should (length= "abc" 3))
+ (should-not (length= "abc" 4))
+
+ (should-not (length< (list 1 2 3) -1))
+ (should-not (length< (list 1 2 3) 0))
+ (should-not (length< (list 1 2 3) -10))
+
+ (should (length> (list 1 2 3) -1))
+ (should (length> (list 1 2 3) 0))
+
+ (should-not (length= (list 1 2 3) -1))
+ (should-not (length= (list 1 2 3) 0))
+ (should-not (length= (list 1 2 3) 1))
+
+ (should-error
+ (let ((list (list 1)))
+ (setcdr list list)
+ (length< list #x1fffe))))
diff --git a/test/src/font-tests.el b/test/src/font-tests.el
index 1892ebf69ee..de153b8de9b 100644
--- a/test/src/font-tests.el
+++ b/test/src/font-tests.el
@@ -1,4 +1,4 @@
-;;; font-tests.el --- Test suite for font-related functions.
+;;; font-tests.el --- Test suite for font-related functions. -*- lexical-binding: t -*-
;; Copyright (C) 2011-2021 Free Software Foundation, Inc.
diff --git a/test/src/indent-tests.el b/test/src/indent-tests.el
new file mode 100644
index 00000000000..10f1202949b
--- /dev/null
+++ b/test/src/indent-tests.el
@@ -0,0 +1,59 @@
+;;; indent-tests.el --- tests for src/indent.c -*- lexical-binding:t -*-
+
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; This program 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.
+;;
+;; This program 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 `https://www.gnu.org/licenses/'.
+
+;;; Commentary:
+
+;;; Code:
+
+(ert-deftest indent-tests-move-to-column-invis-1tab ()
+ "Test `move-to-column' when a TAB is followed by invisible text."
+ (should
+ (string=
+ (with-temp-buffer
+ (insert "\tLine starting with INVISIBLE text after TAB\n")
+ (add-text-properties 2 21 '(invisible t))
+ (goto-char (point-min))
+ (move-to-column 7 t)
+ (buffer-substring-no-properties 1 8))
+ " ")))
+
+(ert-deftest indent-tests-move-to-column-invis-2tabs ()
+ "Test `move-to-column' when 2 TABs are followed by invisible text."
+ (should
+ (string=
+ (with-temp-buffer
+ (insert "\t\tLine starting with INVISIBLE text after TAB\n")
+ (add-text-properties 3 22 '(invisible t))
+ (goto-char (point-min))
+ (move-to-column 12 t)
+ (buffer-substring-no-properties 1 11))
+ "\t \tLine")))
+
+(ert-deftest indent-tests-move-to-column-invis-between-tabs ()
+ "Test `move-to-column' when 2 TABs are mixed with invisible text."
+ (should
+ (string=
+ (with-temp-buffer
+ (insert "\txxx\tLine starting with INVISIBLE text after TAB\n")
+ (add-text-properties 6 25 '(invisible t))
+ (add-text-properties 2 5 '(invisible t))
+ (goto-char (point-min))
+ (move-to-column 12 t)
+ (buffer-substring-no-properties 1 14))
+ "\txxx \tLine")))
diff --git a/test/src/keyboard-tests.el b/test/src/keyboard-tests.el
index 203c0b54154..607d2eafd45 100644
--- a/test/src/keyboard-tests.el
+++ b/test/src/keyboard-tests.el
@@ -32,5 +32,20 @@
(read-event nil nil 2))
?\C-b)))
+(ert-deftest keyboard-lossage-size ()
+ "Test `lossage-size'."
+ (let ((min-value 100)
+ (lossage-orig (lossage-size)))
+ (dolist (factor (list 1 3 4 5 10 7 3))
+ (let ((new-lossage (* factor min-value)))
+ (should (= new-lossage (lossage-size new-lossage)))))
+ ;; Wrong type
+ (should-error (lossage-size -5))
+ (should-error (lossage-size "200"))
+ ;; Less that minimum value
+ (should-error (lossage-size (1- min-value)))
+ (should (= lossage-orig (lossage-size lossage-orig)))))
+
+
(provide 'keyboard-tests)
;;; keyboard-tests.el ends here
diff --git a/test/src/keymap-tests.el b/test/src/keymap-tests.el
index 5402916d7c0..74fb3c892db 100644
--- a/test/src/keymap-tests.el
+++ b/test/src/keymap-tests.el
@@ -1,8 +1,9 @@
-;;; keymap-tests.el --- Test suite for src/keymap.c
+;;; keymap-tests.el --- Test suite for src/keymap.c -*- lexical-binding: t -*-
;; Copyright (C) 2015-2021 Free Software Foundation, Inc.
;; Author: Juanma Barranquero <lekktu@gmail.com>
+;; Stefan Kangas <stefankangas@gmail.com>
;; This file is part of GNU Emacs.
@@ -23,6 +24,83 @@
(require 'ert)
+(defun keymap-tests--make-keymap-test (fun)
+ (should (eq (car (funcall fun)) 'keymap))
+ (should (proper-list-p (funcall fun)))
+ (should (equal (car (last (funcall fun "foo"))) "foo")))
+
+(ert-deftest keymap-make-keymap ()
+ (keymap-tests--make-keymap-test #'make-keymap)
+ (should (char-table-p (cadr (make-keymap)))))
+
+(ert-deftest keymap-make-sparse-keymap ()
+ (keymap-tests--make-keymap-test #'make-sparse-keymap))
+
+(ert-deftest keymap-keymapp ()
+ (should (keymapp (make-keymap)))
+ (should (keymapp (make-sparse-keymap)))
+ (should-not (keymapp '(foo bar))))
+
+(ert-deftest keymap-keymap-parent ()
+ (should-not (keymap-parent (make-keymap)))
+ (should-not (keymap-parent (make-sparse-keymap)))
+ (let ((map (make-keymap)))
+ (set-keymap-parent map help-mode-map)
+ (should (equal (keymap-parent map) help-mode-map))))
+
+(ert-deftest keymap-copy-keymap/is-equal ()
+ (should (equal (copy-keymap help-mode-map) help-mode-map)))
+
+(ert-deftest keymap-copy-keymap/is-not-eq ()
+ (should-not (eq (copy-keymap help-mode-map) help-mode-map)))
+
+(ert-deftest keymap---get-keyelt/runs-menu-item-filter ()
+ (let* (menu-item-filter-ran
+ (object `(menu-item "2" identity
+ :filter ,(lambda (cmd)
+ (setq menu-item-filter-ran t)
+ cmd))))
+ (keymap--get-keyelt object t)
+ (should menu-item-filter-ran)))
+
+(ert-deftest keymap-lookup-key ()
+ (let ((map (make-keymap)))
+ (define-key map [?a] 'foo)
+ (should (eq (lookup-key map [?a]) 'foo))))
+
+(ert-deftest describe-buffer-bindings/header-in-current-buffer ()
+ "Header should be inserted into the current buffer.
+https://debbugs.gnu.org/39149#31"
+ (with-temp-buffer
+ (describe-buffer-bindings (current-buffer))
+ (should (string-match (rx bol "key" (+ space) "binding" eol)
+ (buffer-string)))))
+
+(ert-deftest describe-buffer-bindings/returns-nil ()
+ "Should return nil."
+ (with-temp-buffer
+ (should (eq (describe-buffer-bindings (current-buffer)) nil))))
+
+(defun keymap-tests--test-menu-item-filter (show filter-fun)
+ (unwind-protect
+ (progn
+ (define-key global-map (kbd "C-c C-l r")
+ `(menu-item "2" identity :filter ,filter-fun))
+ (with-temp-buffer
+ (describe-buffer-bindings (current-buffer))
+ (goto-char (point-min))
+ (if (eq show 'show)
+ (should (search-forward "C-c C-l r" nil t))
+ (should-not (search-forward "C-c C-l r" nil t)))))
+ (define-key global-map (kbd "C-c C-l r") nil)
+ (define-key global-map (kbd "C-c C-l") nil)))
+
+(ert-deftest describe-buffer-bindings/menu-item-filter-show-binding ()
+ (keymap-tests--test-menu-item-filter 'show (lambda (cmd) cmd)))
+
+(ert-deftest describe-buffer-bindings/menu-item-filter-hide-binding ()
+ (keymap-tests--test-menu-item-filter 'hide (lambda (_) nil)))
+
(ert-deftest keymap-store_in_keymap-XFASTINT-on-non-characters ()
"Check for bug fixed in \"Fix assertion violation in define-key\",
commit 86c19714b097aa477d339ed99ffb5136c755a046."
@@ -38,13 +116,138 @@ commit 86c19714b097aa477d339ed99ffb5136c755a046."
(should (eq (lookup-key Buffer-menu-mode-map [32]) 'undefined)))
(define-key Buffer-menu-mode-map [32] def))))
-(ert-deftest keymap-where-is-internal-test ()
+
+;;;; where-is-internal
+
+(defun keymap-tests--command-1 () (interactive) nil)
+(defun keymap-tests--command-2 () (interactive) nil)
+(put 'keymap-tests--command-1 :advertised-binding [?y])
+
+(ert-deftest keymap-where-is-internal ()
+ (let ((map (make-sparse-keymap)))
+ (define-key map "x" 'keymap-tests--command-1)
+ (define-key map "y" 'keymap-tests--command-1)
+ (should (equal (where-is-internal 'keymap-tests--command-1 map)
+ '([?y] [?x])))))
+
+(ert-deftest keymap-where-is-internal/firstonly-t ()
+ (let ((map (make-sparse-keymap)))
+ (define-key map "x" 'keymap-tests--command-1)
+ (define-key map "y" 'keymap-tests--command-1)
+ (should (equal (where-is-internal 'keymap-tests--command-1 map t)
+ [?y]))))
+
+(ert-deftest keymap-where-is-internal/menu-item ()
+ (let ((map (make-sparse-keymap)))
+ (define-key map [menu-bar foobar cmd1]
+ '(menu-item "Run Command 1" keymap-tests--command-1
+ :help "Command 1 Help"))
+ (define-key map "x" 'keymap-tests--command-1)
+ (should (equal (where-is-internal 'keymap-tests--command-1 map)
+ '([?x] [menu-bar foobar cmd1])))
+ (should (equal (where-is-internal 'keymap-tests--command-1 map t) [?x]))))
+
+
+(ert-deftest keymap-where-is-internal/advertised-binding ()
+ ;; Make sure order does not matter.
+ (dolist (keys '(("x" . "y") ("y" . "x")))
+ (let ((map (make-sparse-keymap)))
+ (define-key map (car keys) 'keymap-tests--command-1)
+ (define-key map (cdr keys) 'keymap-tests--command-1)
+ (should (equal (where-is-internal 'keymap-tests--command-1 map t) [121])))))
+
+(ert-deftest keymap-where-is-internal/advertised-binding-respect-remap ()
+ (let ((map (make-sparse-keymap)))
+ (define-key map "x" 'next-line)
+ (define-key map [remap keymap-tests--command-1] 'next-line)
+ (define-key map "y" 'keymap-tests--command-1)
+ (should (equal (where-is-internal 'keymap-tests--command-1 map t) [?x]))))
+
+(ert-deftest keymap-where-is-internal/remap ()
+ (let ((map (make-keymap)))
+ (define-key map (kbd "x") 'foo)
+ (define-key map (kbd "y") 'bar)
+ (define-key map [remap foo] 'bar)
+ (should (equal (where-is-internal 'foo map t) [?y]))
+ (should (equal (where-is-internal 'bar map t) [?y]))))
+
+(defvar keymap-tests-minor-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map "x" 'keymap-tests--command-2)
+ map))
+
+(defvar keymap-tests-major-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map "x" 'keymap-tests--command-1)
+ map))
+
+(define-minor-mode keymap-tests-minor-mode "Test.")
+
+(define-derived-mode keymap-tests-major-mode nil "Test.")
+
+(ert-deftest keymap-where-is-internal/shadowed ()
+ (with-temp-buffer
+ (keymap-tests-major-mode)
+ (keymap-tests-minor-mode)
+ (should-not (where-is-internal 'keymap-tests--command-1 nil t))
+ (should (equal (where-is-internal 'keymap-tests--command-2 nil t) [120]))))
+
+(ert-deftest keymap-where-is-internal/preferred-modifier-is-a-string ()
"Make sure we don't crash when `where-is-preferred-modifier' is not a symbol."
(should
(equal (let ((where-is-preferred-modifier "alt"))
(where-is-internal 'execute-extended-command global-map t))
[#x8000078])))
+
+;;;; describe_vector
+
+(ert-deftest help--describe-vector/bug-9293-one-shadowed-in-range ()
+ "Check that we only show a range if shadowed by the same command."
+ (let ((orig-map (let ((map (make-keymap)))
+ (define-key map "e" 'foo)
+ (define-key map "f" 'foo)
+ (define-key map "g" 'foo)
+ (define-key map "h" 'foo)
+ map))
+ (shadow-map (let ((map (make-keymap)))
+ (define-key map "f" 'bar)
+ map))
+ (text-quoting-style 'grave))
+ (with-temp-buffer
+ (help--describe-vector (cadr orig-map) nil #'help--describe-command
+ t shadow-map orig-map t)
+ (should (equal (buffer-string)
+ "
+e foo
+f foo (currently shadowed by `bar')
+g .. h foo
+")))))
+
+(ert-deftest help--describe-vector/bug-9293-same-command-does-not-shadow ()
+ "Check that a command can't be shadowed by the same command."
+ (let ((range-map
+ (let ((map (make-keymap)))
+ (define-key map "0" 'foo)
+ (define-key map "1" 'foo)
+ (define-key map "2" 'foo)
+ (define-key map "3" 'foo)
+ map))
+ (shadow-map
+ (let ((map (make-keymap)))
+ (define-key map "0" 'foo)
+ (define-key map "1" 'foo)
+ (define-key map "2" 'foo)
+ (define-key map "3" 'foo)
+ map)))
+ (with-temp-buffer
+ (help--describe-vector (cadr range-map) nil #'help--describe-command
+ t shadow-map range-map t)
+ (should (equal (buffer-string)
+ "
+0 .. 3 foo
+")))))
+
(provide 'keymap-tests)
;;; keymap-tests.el ends here
diff --git a/test/data/somelib.el b/test/src/lread-resources/somelib.el
index 7b8d4037396..7b8d4037396 100644
--- a/test/data/somelib.el
+++ b/test/src/lread-resources/somelib.el
diff --git a/test/data/somelib2.el b/test/src/lread-resources/somelib2.el
index 05156145a22..05156145a22 100644
--- a/test/data/somelib2.el
+++ b/test/src/lread-resources/somelib2.el
diff --git a/test/src/lread-tests.el b/test/src/lread-tests.el
index 87c1c706657..edf88214f97 100644
--- a/test/src/lread-tests.el
+++ b/test/src/lread-tests.el
@@ -6,18 +6,18 @@
;; This file is part of GNU Emacs.
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
@@ -25,6 +25,9 @@
;;; Code:
+(require 'ert)
+(require 'ert-x)
+
(ert-deftest lread-char-number ()
(should (equal (read "?\\N{U+A817}") #xA817)))
@@ -146,10 +149,7 @@ literals (Bug#20852)."
(ert-deftest lread-test-bug26837 ()
"Test for https://debbugs.gnu.org/26837 ."
- (let ((load-path (cons
- (file-name-as-directory
- (expand-file-name "data" (getenv "EMACS_TEST_DIRECTORY")))
- load-path)))
+ (let ((load-path (cons (ert-resource-directory) load-path)))
(load "somelib" nil t)
(should (string-suffix-p "/somelib.el" (caar load-history)))
(load "somelib2" nil t)
@@ -157,22 +157,6 @@ literals (Bug#20852)."
(load "somelib" nil t)
(should (string-suffix-p "/somelib.el" (caar load-history)))))
-(ert-deftest lread-tests--old-style-backquotes ()
- "Check that loading doesn't accept old-style backquotes."
- (lread-tests--with-temp-file file-name
- (write-region "(` (a b))" nil file-name)
- (let ((data (should-error (load file-name nil :nomessage :nosuffix))))
- (should (equal (cdr data)
- (list (concat (format-message "Loading `%s': " file-name)
- "old-style backquotes detected!")))))))
-
-(ert-deftest lread-tests--force-new-style-backquotes ()
- (let ((data (should-error (read "(` (a b))"))))
- (should (equal (cdr data) '("Old-style backquotes detected!"))))
- (should (equal (let ((force-new-style-backquotes t))
- (read "(` (a b))"))
- '(`(a b)))))
-
(ert-deftest lread-lread--substitute-object-in-subtree ()
(let ((x (cons 0 1)))
(setcar x x)
diff --git a/test/src/print-tests.el b/test/src/print-tests.el
index f094201443d..0d2ea6e3834 100644
--- a/test/src/print-tests.el
+++ b/test/src/print-tests.el
@@ -4,18 +4,18 @@
;; This file is part of GNU Emacs.
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Code:
@@ -355,5 +355,56 @@ otherwise, use a different charset."
(setcdr err err)
(should-error (error-message-string err) :type 'circular-list)))
+(print-tests--deftest print-hash-table-test ()
+ (should
+ (string-match
+ "data (2 3)"
+ (let ((h (make-hash-table)))
+ (puthash 1 2 h)
+ (puthash 2 3 h)
+ (remhash 1 h)
+ (format "%S" h))))
+
+ (should
+ (string-match
+ "data ()"
+ (let ((h (make-hash-table)))
+ (let ((print-length 0))
+ (format "%S" h)))))
+
+ (should
+ (string-match
+ "data (99 99)"
+ (let ((h (make-hash-table)))
+ (dotimes (i 100)
+ (puthash i i h))
+ (dotimes (i 99)
+ (remhash i h))
+ (let ((print-length 1))
+ (format "%S" h))))))
+
+(print-tests--deftest print-integers-as-characters ()
+ ;; Bug#44155.
+ (let* ((print-integers-as-characters t)
+ (chars '(?? ?\; ?\( ?\) ?\{ ?\} ?\[ ?\] ?\" ?\' ?\\ ?f ?~ ?Á 32
+ ?\n ?\r ?\t ?\b ?\f ?\a ?\v ?\e ?\d))
+ (nums '(-1 -65 0 1 31 #x80 #x9f #x110000 #x3fff80 #x3fffff))
+ (nonprints '(#xd800 #xdfff #x030a #xffff #x2002 #x200c))
+ (printed-chars (print-tests--prin1-to-string chars))
+ (printed-nums (print-tests--prin1-to-string nums))
+ (printed-nonprints (print-tests--prin1-to-string nonprints)))
+ (should (equal (read printed-chars) chars))
+ (should (equal
+ printed-chars
+ (concat
+ "(?? ?\\; ?\\( ?\\) ?\\{ ?\\} ?\\[ ?\\] ?\\\" ?\\' ?\\\\"
+ " ?f ?~ ?Á ?\\s ?\\n ?\\r ?\\t ?\\b ?\\f 7 11 27 127)")))
+ (should (equal (read printed-nums) nums))
+ (should (equal printed-nums
+ "(-1 -65 0 1 31 128 159 1114112 4194176 4194303)"))
+ (should (equal (read printed-nonprints) nonprints))
+ (should (equal printed-nonprints
+ "(55296 57343 778 65535 8194 8204)"))))
+
(provide 'print-tests)
;;; print-tests.el ends here
diff --git a/test/src/process-tests.el b/test/src/process-tests.el
index 4088f11c27e..cddf955853e 100644
--- a/test/src/process-tests.el
+++ b/test/src/process-tests.el
@@ -1,19 +1,21 @@
-;;; process-tests.el --- Testing the process facilities
+;;; process-tests.el --- Testing the process facilities -*- lexical-binding: t -*-
;; Copyright (C) 2013-2021 Free Software Foundation, Inc.
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
@@ -21,8 +23,11 @@
;;; Code:
+(require 'cl-lib)
(require 'ert)
(require 'puny)
+(require 'rx)
+(require 'subr-x)
;; Timeout in seconds; the test fails if the timeout is reached.
(defvar process-test-sentinel-wait-timeout 2.0)
@@ -33,7 +38,7 @@
(let ((proc (start-process "test" nil "bash" "-c" "exit 20"))
(sentinel-called nil)
(start-time (float-time)))
- (set-process-sentinel proc (lambda (proc msg)
+ (set-process-sentinel proc (lambda (_proc _msg)
(setq sentinel-called t)))
(while (not (or sentinel-called
(> (- (float-time) start-time)
@@ -45,13 +50,15 @@
(ert-deftest process-test-sentinel-accept-process-output ()
(skip-unless (executable-find "bash"))
+ (with-timeout (60 (ert-fail "Test timed out"))
(should (process-test-sentinel-wait-function-working-p
- #'accept-process-output)))
+ #'accept-process-output))))
(ert-deftest process-test-sentinel-sit-for ()
(skip-unless (executable-find "bash"))
+ (with-timeout (60 (ert-fail "Test timed out"))
(should
- (process-test-sentinel-wait-function-working-p (lambda () (sit-for 0.01 t)))))
+ (process-test-sentinel-wait-function-working-p (lambda () (sit-for 0.01 t))))))
(when (eq system-type 'windows-nt)
(ert-deftest process-test-quoted-batfile ()
@@ -77,6 +84,7 @@
(ert-deftest process-test-stderr-buffer ()
(skip-unless (executable-find "bash"))
+ (with-timeout (60 (ert-fail "Test timed out"))
(let* ((stdout-buffer (generate-new-buffer "*stdout*"))
(stderr-buffer (generate-new-buffer "*stderr*"))
(proc (make-process :name "test"
@@ -88,7 +96,7 @@
:stderr stderr-buffer))
(sentinel-called nil)
(start-time (float-time)))
- (set-process-sentinel proc (lambda (proc msg)
+ (set-process-sentinel proc (lambda (_proc _msg)
(setq sentinel-called t)))
(while (not (or sentinel-called
(> (- (float-time) start-time)
@@ -101,10 +109,11 @@
(looking-at "hello stdout!")))
(should (with-current-buffer stderr-buffer
(goto-char (point-min))
- (looking-at "hello stderr!")))))
+ (looking-at "hello stderr!"))))))
(ert-deftest process-test-stderr-filter ()
(skip-unless (executable-find "bash"))
+ (with-timeout (60 (ert-fail "Test timed out"))
(let* ((sentinel-called nil)
(stderr-sentinel-called nil)
(stdout-output nil)
@@ -120,13 +129,13 @@
"exit 20"))
:stderr stderr-proc))
(start-time (float-time)))
- (set-process-filter proc (lambda (proc input)
+ (set-process-filter proc (lambda (_proc input)
(push input stdout-output)))
- (set-process-sentinel proc (lambda (proc msg)
+ (set-process-sentinel proc (lambda (_proc _msg)
(setq sentinel-called t)))
- (set-process-filter stderr-proc (lambda (proc input)
+ (set-process-filter stderr-proc (lambda (_proc input)
(push input stderr-output)))
- (set-process-sentinel stderr-proc (lambda (proc input)
+ (set-process-sentinel stderr-proc (lambda (_proc _input)
(setq stderr-sentinel-called t)))
(while (not (or sentinel-called
(> (- (float-time) start-time)
@@ -143,10 +152,11 @@
(should (equal 1 (with-current-buffer stderr-buffer
(point-max))))
(should (equal "hello stderr!\n"
- (mapconcat #'identity (nreverse stderr-output) "")))))
+ (mapconcat #'identity (nreverse stderr-output) ""))))))
(ert-deftest set-process-filter-t ()
"Test setting process filter to t and back." ;; Bug#36591
+ (with-timeout (60 (ert-fail "Test timed out"))
(with-temp-buffer
(let* ((print-level nil)
(print-length nil)
@@ -178,11 +188,12 @@
(line-beginning-position) (point-max))
"2> "))
(accept-process-output proc)) ; Read "Two".
- (should (equal (buffer-string) "0> one\n1> two\n2> ")))))
+ (should (equal (buffer-string) "0> one\n1> two\n2> "))))))
(ert-deftest start-process-should-not-modify-arguments ()
"`start-process' must not modify its arguments in-place."
;; See bug#21831.
+ (with-timeout (60 (ert-fail "Test timed out"))
(let* ((path (pcase system-type
((or 'windows-nt 'ms-dos)
;; Make sure the file name uses forward slashes.
@@ -196,11 +207,12 @@
(should (process-live-p (condition-case nil
(start-process "" nil path)
(error nil))))
- (should (equal path samepath))))
+ (should (equal path samepath)))))
(ert-deftest make-process/noquery-stderr ()
"Checks that Bug#30031 is fixed."
(skip-unless (executable-find "sleep"))
+ (with-timeout (60 (ert-fail "Test timed out"))
(with-temp-buffer
(let* ((previous-processes (process-list))
(process (make-process :name "sleep"
@@ -215,7 +227,7 @@
(should new-processes)
(dolist (process new-processes)
(should-not (process-query-on-exit-flag process))))
- (kill-process process)))))
+ (kill-process process))))))
;; Return t if OUTPUT could have been generated by merging the INPUTS somehow.
(defun process-tests--mixable (output &rest inputs)
@@ -231,6 +243,7 @@
(ert-deftest make-process/mix-stderr ()
"Check that `make-process' mixes the output streams if STDERR is nil."
(skip-unless (executable-find "bash"))
+ (with-timeout (60 (ert-fail "Test timed out"))
;; Frequent random (?) failures on hydra.nixos.org, with no process output.
;; Maybe this test should be tagged unstable? See bug#31214.
(skip-unless (not (getenv "EMACS_HYDRA_CI")))
@@ -249,11 +262,12 @@
(should (eq (process-exit-status process) 0))
(should (process-tests--mixable (string-to-list (buffer-string))
(string-to-list "stdout\n")
- (string-to-list "stderr\n"))))))
+ (string-to-list "stderr\n")))))))
(ert-deftest make-process-w32-debug-spawn-error ()
"Check that debugger runs on `make-process' failure (Bug#33016)."
(skip-unless (eq system-type 'windows-nt))
+ (with-timeout (60 (ert-fail "Test timed out"))
(let* ((debug-on-error t)
(have-called-debugger nil)
(debugger (lambda (&rest _)
@@ -269,11 +283,12 @@
;; code.
(make-process :name "test" :command '("c:/No-Such-Command"))
(error :got-error))))
- (should have-called-debugger)))
+ (should have-called-debugger))))
(ert-deftest make-process/file-handler/found ()
- "Check that the ‘:file-handler’ argument of ‘make-process’
+ "Check that the `:file-handler’ argument of `make-process’
works as expected if a file name handler is found."
+ (with-timeout (60 (ert-fail "Test timed out"))
(let ((file-handler-calls 0))
(cl-flet ((file-handler
(&rest args)
@@ -290,27 +305,29 @@ works as expected if a file name handler is found."
:command '("/some/binary")
:file-handler t)
'fake-process))
- (should (= file-handler-calls 1))))))
+ (should (= file-handler-calls 1)))))))
(ert-deftest make-process/file-handler/not-found ()
- "Check that the ‘:file-handler’ argument of ‘make-process’
+ "Check that the `:file-handler’ argument of `make-process’
works as expected if no file name handler is found."
+ (with-timeout (60 (ert-fail "Test timed out"))
(let ((file-name-handler-alist ())
(default-directory invocation-directory)
(program (expand-file-name invocation-name invocation-directory)))
(should (processp (make-process :name "name"
:command (list program "--version")
- :file-handler t)))))
+ :file-handler t))))))
(ert-deftest make-process/file-handler/disable ()
- "Check ‘make-process’ works as expected if it shouldn’t use the
+ "Check `make-process’ works as expected if it shouldn’t use the
file name handler."
+ (with-timeout (60 (ert-fail "Test timed out"))
(let ((file-name-handler-alist (list (cons (rx bos "test-handler:")
#'process-tests--file-handler)))
(default-directory "test-handler:/dir/")
(program (expand-file-name invocation-name invocation-directory)))
(should (processp (make-process :name "name"
- :command (list program "--version"))))))
+ :command (list program "--version")))))))
(defun process-tests--file-handler (operation &rest _args)
(cl-ecase operation
@@ -323,48 +340,419 @@ file name handler."
(ert-deftest make-process/stop ()
"Check that `make-process' doesn't accept a `:stop' key.
See Bug#30460."
+ (with-timeout (60 (ert-fail "Test timed out"))
(should-error
(make-process :name "test"
:command (list (expand-file-name invocation-name
invocation-directory))
- :stop t)))
+ :stop t))))
;; All the following tests require working DNS, which appears not to
;; be the case for hydra.nixos.org, so disable them there for now.
(ert-deftest lookup-family-specification ()
- "network-lookup-address-info should only accept valid family symbols."
+ "`network-lookup-address-info' should only accept valid family symbols."
(skip-unless (not (getenv "EMACS_HYDRA_CI")))
+ (with-timeout (60 (ert-fail "Test timed out"))
(should-error (network-lookup-address-info "google.com" 'both))
(should (network-lookup-address-info "google.com" 'ipv4))
(when (featurep 'make-network-process '(:family ipv6))
- (should (network-lookup-address-info "google.com" 'ipv6))))
+ (should (network-lookup-address-info "google.com" 'ipv6)))))
(ert-deftest lookup-unicode-domains ()
- "Unicode domains should fail"
+ "Unicode domains should fail."
(skip-unless (not (getenv "EMACS_HYDRA_CI")))
+ (with-timeout (60 (ert-fail "Test timed out"))
(should-error (network-lookup-address-info "faß.de"))
- (should (network-lookup-address-info (puny-encode-domain "faß.de"))))
+ (should (network-lookup-address-info (puny-encode-domain "faß.de")))))
(ert-deftest unibyte-domain-name ()
- "Unibyte domain names should work"
+ "Unibyte domain names should work."
(skip-unless (not (getenv "EMACS_HYDRA_CI")))
- (should (network-lookup-address-info (string-to-unibyte "google.com"))))
+ (with-timeout (60 (ert-fail "Test timed out"))
+ (should (network-lookup-address-info (string-to-unibyte "google.com")))))
(ert-deftest lookup-google ()
- "Check that we can look up google IP addresses"
+ "Check that we can look up google IP addresses."
(skip-unless (not (getenv "EMACS_HYDRA_CI")))
+ (with-timeout (60 (ert-fail "Test timed out"))
(let ((addresses-both (network-lookup-address-info "google.com"))
(addresses-v4 (network-lookup-address-info "google.com" 'ipv4)))
(should addresses-both)
(should addresses-v4))
(when (featurep 'make-network-process '(:family ipv6))
- (should (network-lookup-address-info "google.com" 'ipv6))))
+ (should (network-lookup-address-info "google.com" 'ipv6)))))
(ert-deftest non-existent-lookup-failure ()
+ "Check that looking up non-existent domain returns nil."
(skip-unless (not (getenv "EMACS_HYDRA_CI")))
- "Check that looking up non-existent domain returns nil"
- (should (eq nil (network-lookup-address-info "emacs.invalid"))))
+ (with-timeout (60 (ert-fail "Test timed out"))
+ (should (eq nil (network-lookup-address-info "emacs.invalid")))))
+
+(defmacro process-tests--ignore-EMFILE (&rest body)
+ "Evaluate BODY, ignoring EMFILE errors."
+ (declare (indent 0) (debug t))
+ (let ((err (make-symbol "err"))
+ (message (make-symbol "message")))
+ `(let ((,message (process-tests--EMFILE-message)))
+ (condition-case ,err
+ ,(macroexp-progn body)
+ (file-error
+ ;; If we couldn't determine the EMFILE message, just ignore
+ ;; all `file-error' signals.
+ (and ,message
+ (not (string-equal (caddr ,err) ,message))
+ (signal (car ,err) (cdr ,err))))))))
+
+(defmacro process-tests--with-buffers (var &rest body)
+ "Bind VAR to nil and evaluate BODY.
+Afterwards, kill all buffers in the list VAR. BODY should add
+some buffer objects to VAR."
+ (declare (indent 1) (debug (symbolp body)))
+ (cl-check-type var symbol)
+ `(let ((,var nil))
+ (unwind-protect
+ ,(macroexp-progn body)
+ (mapc #'kill-buffer ,var))))
+
+(defmacro process-tests--with-processes (var &rest body)
+ "Bind VAR to nil and evaluate BODY.
+Afterwards, delete all processes in the list VAR. BODY should
+add some process objects to VAR."
+ (declare (indent 1) (debug (symbolp body)))
+ (cl-check-type var symbol)
+ `(let ((,var nil))
+ (unwind-protect
+ ,(macroexp-progn body)
+ (mapc #'delete-process ,var))))
+
+(defmacro process-tests--with-raised-rlimit (&rest body)
+ "Evaluate BODY using a higher limit for the number of open files.
+Attempt to set the resource limit for the number of open files
+temporarily to the highest possible value."
+ (declare (indent 0) (debug t))
+ (let ((prlimit (make-symbol "prlimit"))
+ (soft (make-symbol "soft"))
+ (hard (make-symbol "hard"))
+ (pid-arg (make-symbol "pid-arg")))
+ `(let ((,prlimit (executable-find "prlimit"))
+ (,pid-arg (format "--pid=%d" (emacs-pid)))
+ (,soft nil) (,hard nil))
+ (cl-flet ((set-limit
+ (value)
+ (cl-check-type value natnum)
+ (when ,prlimit
+ (call-process ,prlimit nil nil nil
+ ,pid-arg
+ (format "--nofile=%d:" value)))))
+ (when ,prlimit
+ (with-temp-buffer
+ (when (eql (call-process ,prlimit nil t nil
+ ,pid-arg "--nofile"
+ "--raw" "--noheadings"
+ "--output=SOFT,HARD")
+ 0)
+ (goto-char (point-min))
+ (when (looking-at (rx (group (+ digit)) (+ blank)
+ (group (+ digit)) ?\n))
+ (setq ,soft (string-to-number
+ (match-string-no-properties 1))
+ ,hard (string-to-number
+ (match-string-no-properties 2))))))
+ (and ,soft ,hard (< ,soft ,hard)
+ (set-limit ,hard)))
+ (unwind-protect
+ ,(macroexp-progn body)
+ (when ,soft (set-limit ,soft)))))))
+
+(defmacro process-tests--fd-setsize-test (&rest body)
+ "Run BODY as a test for FD_SETSIZE overflow.
+Try to generate pipe processes until we are close to the
+FD_SETSIZE limit. Within BODY, only a small number of file
+descriptors should still be available. Furthermore, raise the
+maximum number of open files in the Emacs process above
+FD_SETSIZE."
+ (declare (indent 0) (debug t))
+ (let ((process (make-symbol "process"))
+ (processes (make-symbol "processes"))
+ (buffer (make-symbol "buffer"))
+ (buffers (make-symbol "buffers"))
+ ;; FD_SETSIZE is typically 1024 on Unix-like systems. On
+ ;; MS-Windows we artificially limit FD_SETSIZE to 64, see the
+ ;; commentary in w32proc.c.
+ (fd-setsize (if (eq system-type 'windows-nt) 64 1024)))
+ `(process-tests--with-raised-rlimit
+ (process-tests--with-buffers ,buffers
+ (process-tests--with-processes ,processes
+ ;; First, allocate enough pipes to definitely exceed the
+ ;; FD_SETSIZE limit.
+ (cl-loop for i from 1 to ,(1+ fd-setsize)
+ for ,buffer = (generate-new-buffer
+ (format " *pipe %d*" i))
+ do (push ,buffer ,buffers)
+ for ,process = (process-tests--ignore-EMFILE
+ (make-pipe-process
+ :name (format "pipe %d" i)
+ ;; Prevent delete-process from
+ ;; trying to read from pipe
+ ;; processes that didn't exit
+ ;; yet, because no one is
+ ;; writing to those pipes, and
+ ;; the read will stall.
+ :stop (eq system-type 'windows-nt)
+ :buffer ,buffer
+ :coding 'no-conversion
+ :noquery t))
+ while ,process
+ do (push ,process ,processes))
+ (unless (cddr ,processes)
+ (ert-fail "Couldn't allocate enough pipes"))
+ ;; Delete two pipes to test more edge cases.
+ (delete-process (pop ,processes))
+ (delete-process (pop ,processes))
+ ,@body)))))
+
+(defmacro process-tests--with-temp-file (var &rest body)
+ "Bind VAR to the name of a new regular file and evaluate BODY.
+Afterwards, delete the file."
+ (declare (indent 1) (debug (symbolp body)))
+ (cl-check-type var symbol)
+ (let ((file (make-symbol "file")))
+ `(let ((,file (make-temp-file "emacs-test-")))
+ (unwind-protect
+ (let ((,var ,file))
+ ,@body)
+ (delete-file ,file)))))
+
+(defmacro process-tests--with-temp-directory (var &rest body)
+ "Bind VAR to the name of a new directory and evaluate BODY.
+Afterwards, delete the directory."
+ (declare (indent 1) (debug (symbolp body)))
+ (cl-check-type var symbol)
+ (let ((dir (make-symbol "dir")))
+ `(let ((,dir (make-temp-file "emacs-test-" :dir)))
+ (unwind-protect
+ (let ((,var ,dir))
+ ,@body)
+ (delete-directory ,dir :recursive)))))
+
+;; Tests for FD_SETSIZE overflow (Bug#24325). The following tests
+;; generate lots of process objects of the various kinds. Running the
+;; tests with assertions enabled should not result in any crashes due
+;; to file descriptor set overflow. These tests first generate lots
+;; of unused pipe processes to fill up the file descriptor space.
+;; Then, they create a few instances of the process type under test.
+
+(ert-deftest process-tests/fd-setsize-no-crash/make-process ()
+ "Check that Emacs doesn't crash when trying to use more than
+FD_SETSIZE file descriptors (Bug#24325)."
+ (with-timeout (60 (ert-fail "Test timed out"))
+ (let ((sleep (executable-find "sleep")))
+ (skip-unless sleep)
+ (dolist (conn-type '(pipe pty))
+ (ert-info ((format "Connection type `%s'" conn-type))
+ (process-tests--fd-setsize-test
+ (process-tests--with-processes processes
+ ;; Start processes until we exhaust the file descriptor
+ ;; set size. We assume that each process requires at
+ ;; least one file descriptor.
+ (dotimes (i 10)
+ (let ((process
+ ;; Failure to allocate more file descriptors
+ ;; should signal `file-error', but not crash.
+ ;; Since we don't know the exact limit, we
+ ;; ignore `file-error'.
+ (process-tests--ignore-EMFILE
+ (make-process :name (format "test %d" i)
+ :command (list sleep "5")
+ :connection-type conn-type
+ :coding 'no-conversion
+ :noquery t))))
+ (when process (push process processes))))
+ ;; We should have managed to start at least one process.
+ (should processes)
+ (dolist (process processes)
+ (while (accept-process-output process))
+ (should (eq (process-status process) 'exit))
+ ;; If there's an error between fork and exec, Emacs
+ ;; will use exit statuses between 125 and 127, see
+ ;; process.h. This can happen if the child process
+ ;; tries to set up terminal device but fails due to
+ ;; file number limits. We don't treat this as an
+ ;; error.
+ (should (memql (process-exit-status process)
+ '(0 125 126 127)))))))))))
+
+(ert-deftest process-tests/fd-setsize-no-crash/make-pipe-process ()
+ "Check that Emacs doesn't crash when trying to use more than
+FD_SETSIZE file descriptors (Bug#24325)."
+ (with-timeout (60 (ert-fail "Test timed out"))
+ (process-tests--fd-setsize-test
+ (process-tests--with-buffers buffers
+ (process-tests--with-processes processes
+ ;; Start processes until we exhaust the file descriptor set
+ ;; size. We assume that each process requires at least one
+ ;; file descriptor.
+ (dotimes (i 10)
+ (let ((buffer (generate-new-buffer (format " *%d*" i))))
+ (push buffer buffers)
+ (let ((process
+ ;; Failure to allocate more file descriptors
+ ;; should signal `file-error', but not crash.
+ ;; Since we don't know the exact limit, we ignore
+ ;; `file-error'.
+ (process-tests--ignore-EMFILE
+ (make-pipe-process :name (format "test %d" i)
+ :buffer buffer
+ :coding 'no-conversion
+ :noquery t))))
+ (when process (push process processes)))))
+ ;; We should have managed to start at least one process.
+ (should processes))))))
+
+(ert-deftest process-tests/fd-setsize-no-crash/make-network-process ()
+ "Check that Emacs doesn't crash when trying to use more than
+FD_SETSIZE file descriptors (Bug#24325)."
+ (skip-unless (featurep 'make-network-process '(:server t)))
+ (skip-unless (featurep 'make-network-process '(:family local)))
+ (with-timeout (60 (ert-fail "Test timed out"))
+ (process-tests--with-temp-directory directory
+ (process-tests--with-processes processes
+ (let* ((num-clients 10)
+ (socket-name (expand-file-name "socket" directory))
+ ;; Run a UNIX server to connect to.
+ (server (make-network-process :name "server"
+ :server num-clients
+ :buffer nil
+ :service socket-name
+ :family 'local
+ :coding 'no-conversion
+ :noquery t)))
+ (push server processes)
+ (process-tests--fd-setsize-test
+ ;; Start processes until we exhaust the file descriptor
+ ;; set size. We assume that each process requires at
+ ;; least one file descriptor.
+ (dotimes (i num-clients)
+ (let ((client
+ ;; Failure to allocate more file descriptors
+ ;; should signal `file-error', but not crash.
+ ;; Since we don't know the exact limit, we ignore
+ ;; `file-error'.
+ (process-tests--ignore-EMFILE
+ (make-network-process
+ :name (format "client %d" i)
+ :service socket-name
+ :family 'local
+ :coding 'no-conversion
+ :noquery t))))
+ (when client (push client processes))))
+ ;; We should have managed to start at least one process.
+ (should processes)))))))
+
+(ert-deftest process-tests/fd-setsize-no-crash/make-serial-process ()
+ "Check that Emacs doesn't crash when trying to use more than
+FD_SETSIZE file descriptors (Bug#24325)."
+ (with-timeout (60 (ert-fail "Test timed out"))
+ (skip-unless (file-executable-p shell-file-name))
+ (skip-unless (executable-find "tty"))
+ (skip-unless (executable-find "sleep"))
+ ;; `process-tests--new-pty' probably only works with GNU Bash.
+ (skip-unless (string-equal
+ (file-name-nondirectory shell-file-name) "bash"))
+ (process-tests--with-processes processes
+ ;; In order to use `make-serial-process', we need to create some
+ ;; pseudoterminals. The easiest way to do that is to start a
+ ;; normal process using the `pty' connection type. We need to
+ ;; ensure that the terminal stays around while we connect to it.
+ ;; Create the host processes before the dummy pipes so we have a
+ ;; high chance of succeeding here.
+ (let ((tty-names ()))
+ (dotimes (_ 10)
+ (cl-destructuring-bind
+ (host tty-name) (process-tests--new-pty)
+ (should (processp host))
+ (push host processes)
+ (should tty-name)
+ (should (file-exists-p tty-name))
+ (push tty-name tty-names)))
+ (process-tests--fd-setsize-test
+ (process-tests--with-processes processes
+ (process-tests--with-buffers buffers
+ (dolist (tty-name tty-names)
+ (let ((buffer (generate-new-buffer
+ (format " *%s*" tty-name))))
+ (push buffer buffers)
+ ;; Failure to allocate more file descriptors should
+ ;; signal `file-error', but not crash. Since we
+ ;; don't know the exact limit, we ignore
+ ;; `file-error'.
+ (let ((process (process-tests--ignore-EMFILE
+ (make-serial-process
+ :name (format "test %s" tty-name)
+ :port tty-name
+ :speed 9600
+ :buffer buffer
+ :coding 'no-conversion
+ :noquery t))))
+ (when process (push process processes))))))
+ ;; We should have managed to start at least one process.
+ (should processes)))))))
+
+(defvar process-tests--EMFILE-message :unknown
+ "Cached result of the function `process-tests--EMFILE-message'.")
+
+(defun process-tests--EMFILE-message ()
+ "Return the error message for the EMFILE POSIX error.
+Return nil if that can't be determined."
+ (when (eq process-tests--EMFILE-message :unknown)
+ (setq process-tests--EMFILE-message
+ (with-temp-buffer
+ (when (eql (ignore-error 'file-error
+ (call-process "errno" nil t nil "EMFILE"))
+ 0)
+ (goto-char (point-min))
+ (when (looking-at (rx "EMFILE" (+ blank) (+ digit)
+ (+ blank) (group (+ nonl))))
+ (match-string-no-properties 1))))))
+ process-tests--EMFILE-message)
+
+(defun process-tests--new-pty ()
+ "Allocate a new pseudoterminal.
+Return a list (PROCESS TTY-NAME)."
+ ;; The command below will typically only work with GNU Bash.
+ (should (string-equal (file-name-nondirectory shell-file-name)
+ "bash"))
+ (process-tests--with-temp-file temp-file
+ (should-not (file-remote-p temp-file))
+ (let* ((command (list shell-file-name shell-command-switch
+ (format "tty > %s && sleep 60"
+ (shell-quote-argument
+ (file-name-unquote temp-file)))))
+ (process (make-process :name "tty host"
+ :command command
+ :buffer nil
+ :coding 'utf-8-unix
+ :connection-type 'pty
+ :noquery t))
+ (tty-name nil)
+ (coding-system-for-read 'utf-8-unix)
+ (coding-system-for-write 'utf-8-unix))
+ ;; Wait until TTY name has arrived.
+ (with-timeout (2 (message "Timed out waiting for TTY name"))
+ (while (and (process-live-p process) (not tty-name))
+ (sleep-for 0.1)
+ (when-let ((attributes (file-attributes temp-file)))
+ (when (cl-plusp (file-attribute-size attributes))
+ (with-temp-buffer
+ (insert-file-contents temp-file)
+ (goto-char (point-max))
+ ;; `tty' has printed a trailing newline.
+ (skip-chars-backward "\n")
+ (unless (bobp)
+ (setq tty-name (buffer-substring-no-properties
+ (point-min) (point)))))))))
+ (list process tty-name))))
(provide 'process-tests)
-;; process-tests.el ends here.
+;;; process-tests.el ends here
diff --git a/test/src/regex-emacs-tests.el b/test/src/regex-emacs-tests.el
index bb564a4fe25..0607eacf397 100644
--- a/test/src/regex-emacs-tests.el
+++ b/test/src/regex-emacs-tests.el
@@ -161,7 +161,7 @@ what failed, if anything; valid values are 'search-failed,
'compilation-failed and nil. I compare the beginning/end of each
group with their expected values. This is done with either
BOUNDS-REF or SUBSTRING-REF; one of those should be non-nil.
-BOUNDS-REF is a sequence \[start-ref0 end-ref0 start-ref1
+BOUNDS-REF is a sequence [start-ref0 end-ref0 start-ref1
end-ref1 ....] while SUBSTRING-REF is the expected substring
obtained by indexing the input string by start/end-ref.
@@ -327,7 +327,7 @@ emacs requires an extra symbol character"
(defun regex-tests-BOOST-frob-escapes (s ispattern)
"Mangle \\ the way it is done in frob_escapes() in
regex-tests-BOOST.c in glibc: \\t, \\n, \\r are interpreted;
-\\\\, \\^, \{, \\|, \} are unescaped for the string (not
+\\\\, \\^, \\{, \\|, \\} are unescaped for the string (not
pattern)"
;; this is all similar to (regex-tests-unextend)
@@ -505,7 +505,7 @@ differences in behavior.")
(cond
;; pattern
- ((save-excursion (re-search-forward "^/\\(.*\\)/\\(.*i?\\)$" nil t))
+ ((save-excursion (re-search-forward "^/\\(.*\\)/\\(.*\\)$" nil t))
(setq icase (string= "i" (match-string 2))
pattern (regex-tests-unextend (match-string 1))))
@@ -803,4 +803,68 @@ This evaluates the TESTS test cases from glibc."
(should-not (string-match "å" "\xe5"))
(should-not (string-match "[å]" "\xe5")))
+(ert-deftest regexp-case-fold ()
+ "Test case-sensitive and case-insensitive matching."
+ (let ((case-fold-search nil))
+ (should (equal (string-match "aB" "ABaB") 2))
+ (should (equal (string-match "åÄ" "ÅäåäÅÄåÄ") 6))
+ (should (equal (string-match "λΛ" "lΛλλΛ") 3))
+ (should (equal (string-match "шШ" "zШшшШ") 3))
+ (should (equal (string-match "[[:alpha:]]+" ".3aBåÄßλΛшШ中﷽") 2))
+ (should (equal (match-end 0) 12))
+ (should (equal (string-match "[[:alnum:]]+" ".3aBåÄßλΛшШ中﷽") 1))
+ (should (equal (match-end 0) 12))
+ (should (equal (string-match "[[:upper:]]+" ".3aåλшBÄΛШ中﷽") 6))
+ (should (equal (match-end 0) 10))
+ (should (equal (string-match "[[:lower:]]+" ".3BÄΛШaåλш中﷽") 6))
+ (should (equal (match-end 0) 10)))
+ (let ((case-fold-search t))
+ (should (equal (string-match "aB" "ABaB") 0))
+ (should (equal (string-match "åÄ" "ÅäåäÅÄåÄ") 0))
+ (should (equal (string-match "λΛ" "lΛλλΛ") 1))
+ (should (equal (string-match "шШ" "zШшшШ") 1))
+ (should (equal (string-match "[[:alpha:]]+" ".3aBåÄßλΛшШ中﷽") 2))
+ (should (equal (match-end 0) 12))
+ (should (equal (string-match "[[:alnum:]]+" ".3aBåÄßλΛшШ中﷽") 1))
+ (should (equal (match-end 0) 12))
+ (should (equal (string-match "[[:upper:]]+" ".3aåλшBÄΛШ中﷽") 2))
+ (should (equal (match-end 0) 10))
+ (should (equal (string-match "[[:lower:]]+" ".3BÄΛШaåλш中﷽") 2))
+ (should (equal (match-end 0) 10))))
+
+(ert-deftest regexp-eszett ()
+ "Test matching of ß and ẞ."
+ ;; Sanity checks.
+ (should (equal (upcase "ß") "SS"))
+ (should (equal (downcase "ß") "ß"))
+ (should (equal (capitalize "ß") "Ss")) ; undeutsch...
+ (should (equal (upcase "ẞ") "ẞ"))
+ (should (equal (downcase "ẞ") "ß"))
+ (should (equal (capitalize "ẞ") "ẞ"))
+ ;; ß is a lower-case letter (Ll); ẞ is an upper-case letter (Lu).
+ (let ((case-fold-search nil))
+ (should (equal (string-match "ß" "ß") 0))
+ (should (equal (string-match "ß" "ẞ") nil))
+ (should (equal (string-match "ẞ" "ß") nil))
+ (should (equal (string-match "ẞ" "ẞ") 0))
+ (should (equal (string-match "[[:alpha:]]" "ß") 0))
+ ;; bug#11309
+ (should (equal (string-match "[[:lower:]]" "ß") 0))
+ (should (equal (string-match "[[:upper:]]" "ß") nil))
+ (should (equal (string-match "[[:alpha:]]" "ẞ") 0))
+ (should (equal (string-match "[[:lower:]]" "ẞ") nil))
+ (should (equal (string-match "[[:upper:]]" "ẞ") 0)))
+ (let ((case-fold-search t))
+ (should (equal (string-match "ß" "ß") 0))
+ (should (equal (string-match "ß" "ẞ") 0))
+ (should (equal (string-match "ẞ" "ß") 0))
+ (should (equal (string-match "ẞ" "ẞ") 0))
+ (should (equal (string-match "[[:alpha:]]" "ß") 0))
+ ;; bug#11309
+ (should (equal (string-match "[[:lower:]]" "ß") 0))
+ (should (equal (string-match "[[:upper:]]" "ß") 0))
+ (should (equal (string-match "[[:alpha:]]" "ẞ") 0))
+ (should (equal (string-match "[[:lower:]]" "ẞ") 0))
+ (should (equal (string-match "[[:upper:]]" "ẞ") 0))))
+
;;; regex-emacs-tests.el ends here
diff --git a/test/src/regex-resources/BOOST.tests b/test/src/regex-resources/BOOST.tests
index 98fd3b6abf3..756fa00486b 100644
--- a/test/src/regex-resources/BOOST.tests
+++ b/test/src/regex-resources/BOOST.tests
@@ -93,7 +93,7 @@ aa\) !
. \0 0 1
;
-; now move on to the repetion ops,
+; now move on to the repetition ops,
; starting with operator *
- match_default normal REG_EXTENDED
a* b 0 0
@@ -275,7 +275,7 @@ a(b*)c\1d abbcbbbd -1 -1
^(.)\1 abc -1 -1
a([bc])\1d abcdabbd 4 8 5 6
; strictly speaking this is at best ambiguous, at worst wrong, this is what most
-; re implimentations will match though.
+; re implementations will match though.
a(([bc])\2)*d abbccd 0 6 3 5 3 4
a(([bc])\2)*d abbcbd -1 -1
diff --git a/test/src/syntax-resources/syntax-comments.txt b/test/src/syntax-resources/syntax-comments.txt
new file mode 100644
index 00000000000..a292d816b9d
--- /dev/null
+++ b/test/src/syntax-resources/syntax-comments.txt
@@ -0,0 +1,94 @@
+/* This file is a test file for tests of the comment handling in src/syntax.c.
+ This includes the testing of comments which figure in parse-partial-sexp
+ and scan-lists. */
+
+/* Straight C comments */
+1/* comment */1
+2/**/2
+3// comment
+3
+4//
+4
+5/*/5
+6*/6
+7/* \*/7
+8*/8
+9/* \\*/9
+10*/10
+11// \
+12
+11
+13// \\
+14
+13
+15/* /*/15
+
+/* C Comments within lists */
+59}59
+50{ /*70 comment */71 }50
+51{ /**/ }51
+52{ //72 comment
+73}52
+53{ //
+}53
+54{ //74 \
+}54
+55{/* */}55
+56{ /*76 \*/ }56
+57*/77
+58}58
+60{ /*78 \\*/79}60
+
+
+/* Straight Pascal comments (not nested) */
+20}20
+21{ Comment }21
+22{}22
+23{
+}23
+24{
+25{25
+}24
+26{ \}26
+
+
+/* Straight Lisp comments (not nested) */
+30
+30
+31; Comment
+31
+32;;;;;;;;;
+32
+33; \
+33
+
+/* Lisp comments within lists */
+40)40
+41(;90 comment
+91)41
+42(;92\
+93)42
+43( ;94
+95
+
+/* Nested Lisp comments */
+100|#100
+101#|#
+102#||#102
+103#| Comment |#103
+104#| Comment
+|#104
+105#|#|#105
+106#| #| Comment |# |#106
+107#|#|#|#|#|#|#|#|#| Comment |#|#|#|#|#|#|#|#|#107
+
+/* Mixed Lisp comments */
+110; #|
+110
+111#| ; |#111
+
+Local Variables:
+mode: fundamental
+eval: (set-syntax-table (make-syntax-table))
+End:
+999 \ No newline at end of file
diff --git a/test/src/syntax-tests.el b/test/src/syntax-tests.el
index 52b70fc404d..479b818935f 100644
--- a/test/src/syntax-tests.el
+++ b/test/src/syntax-tests.el
@@ -20,6 +20,7 @@
;;; Code:
(require 'ert)
+(require 'ert-x)
(ert-deftest parse-partial-sexp-continue-over-comment-marker ()
"Continue a parse that stopped in the middle of a comment marker."
@@ -82,4 +83,410 @@ also has open paren syntax (see Bug#24870)."
(should (equal (parse-partial-sexp pointC pointX nil nil ppsC)
ppsX)))))
+
+;;; Commentary:
+;; The next bit tests the handling of comments in syntax.c, in
+;; particular the functions `forward-comment' and `scan-lists' and
+;; `parse-partial-sexp' (in so far as they relate to comments).
+
+;; It is intended to enhance this bit to test nested comments
+;; (2020-10-01).
+
+;; This bit uses the data file syntax-resources/syntax-comments.txt.
+
+(defun syntax-comments-point (n forw)
+ "Return the buffer offset corresponding to the \"label\" N.
+N is a decimal number which appears in the data file, usually
+twice, as \"labels\". It can also be a negative number or zero.
+FORW is t when we're using the label at BOL, nil for the one at EOL.
+
+If the label N doesn't exist in the current buffer, an exception
+is thrown.
+
+When FORW is t and N positive, we return the position after the
+first occurrence of label N at BOL in the data file. With FORW
+nil, we return the position before the last occurrence of the
+label at EOL in the data file.
+
+When N is negative, we return instead the position of the end of
+line that the -N label is on. When it is zero, we return POINT."
+ (if (zerop n)
+ (point)
+ (let ((str (format "%d" (abs n))))
+ (save-excursion
+ (if forw
+ (progn
+ (goto-char (point-min))
+ (re-search-forward
+ (concat "^\\(" str "\\)\\([^0-9\n]\\|$\\)"))
+ (if (< n 0)
+ (progn (end-of-line) (point))
+ (match-end 1)))
+ (goto-char (point-max))
+ (re-search-backward
+ (concat "\\(^\\|[^0-9]\\)\\(" str "\\)$"))
+ (if (< n 0)
+ (progn (end-of-line) (point))
+ (match-beginning 2)))))))
+
+(defun syntax-comments-midpoint (n)
+ "Return the buffer offset corresponding to the \"label\" N.
+N is a positive decimal number which should appear in the buffer
+exactly once. The label need not be at the beginning or end of a
+line.
+
+The return value is the position just before the label.
+
+If the label N doesn't exist in the current buffer, an exception
+is thrown."
+ (let ((str (format "%d" n)))
+ (save-excursion
+ (goto-char (point-min))
+ (re-search-forward
+ (concat "\\(^\\|[^0-9]\\)\\(" str "\\)\\([^0-9\n]\\|$\\)"))
+ (match-beginning 2))))
+
+(eval-and-compile
+ (defvar syntax-comments-section))
+
+(defmacro syntax-comments (-type- -dir- res start &optional stop)
+ "Create an ERT test to test (forward-comment 1/-1).
+The test uses a fixed name data file, which it visits. It calls
+entry and exit functions to set up and tear down syntax entries
+for comment characters. The test is given a name based on the
+global variable `syntax-comments-section', the direction of
+movement and the value of START.
+
+-TYPE- (unquoted) is a symbol from whose name the entry and exit
+function names are derived by appending \"-in\" and \"-out\".
+
+-DIR- (unquoted) is `forward' or `backward', the direction
+`forward-comment' is attempted.
+
+RES, t or nil, is the expected result from `forward-comment'.
+
+START and STOP are decimal numbers corresponding to labels in the
+data file marking the start and expected stop positions. See
+`syntax-comments-point' for a precise specification. If STOP is
+missing or nil, the value of START is assumed for it."
+ (declare (debug t))
+ (let ((forw
+ (cond
+ ((eq -dir- 'forward) t)
+ ((eq -dir- 'backward) nil)
+ (t (error "Invalid -dir- argument \"%s\" to `syntax-comments'" -dir-))))
+ (start-str (format "%d" (abs start)))
+ (type -type-))
+ `(ert-deftest ,(intern (concat "syntax-comments-"
+ syntax-comments-section
+ (if forw "-f" "-b") start-str))
+ ()
+ (with-current-buffer
+ (find-file
+ ,(ert-resource-file "syntax-comments.txt"))
+ (,(intern (concat (symbol-name type) "-in")))
+ (goto-char (syntax-comments-point ,start ,forw))
+ (let ((stop (syntax-comments-point ,(or stop start) ,(not forw))))
+ (should (eq (forward-comment ,(if forw 1 -1)) ,res))
+ (should (eq (point) stop)))
+ (,(intern (concat (symbol-name type) "-out")))))))
+
+(defmacro syntax-br-comments (-type- -dir- res -start- &optional stop)
+ "Create an ERT test to test (scan-lists <position> 1/-1 0).
+This is to test the interface between scan-lists and the internal
+comment routines in syntax.c.
+
+The test uses a fixed name data file, which it visits. It calls
+entry and exit functions to set up and tear down syntax entries
+for comment and paren characters. The test is given a name based
+on the global variable `syntax-comments-section', the direction
+of movement and the value of -START-.
+
+-TYPE- (unquoted) is a symbol from whose name the entry and exit
+function names are derived by appending \"-in\" and \"-out\".
+
+-DIR- (unquoted) is `forward' or `backward', the direction
+`scan-lists' is attempted.
+
+RES is t if `scan-lists' is expected to return, nil if it is
+expected to raise a `scan-error' exception.
+
+-START- and STOP are decimal numbers corresponding to labels in the
+data file marking the start and expected stop positions. See
+`syntax-comments-point' for a precise specification. If STOP is
+missing or nil, the value of -START- is assumed for it."
+ (declare (debug t))
+ (let* ((forw
+ (cond
+ ((eq -dir- 'forward) t)
+ ((eq -dir- 'backward) nil)
+ (t (error "Invalid -dir- argument \"%s\" to `syntax-br-comments'" -dir-))))
+ (start -start-)
+ (start-str (format "%d" (abs start)))
+ (type -type-))
+ `(ert-deftest ,(intern (concat "syntax-br-comments-"
+ syntax-comments-section
+ (if forw "-f" "-b") start-str))
+ ()
+ (with-current-buffer
+ (find-file
+ ,(ert-resource-file "syntax-comments.txt"))
+ (,(intern (concat (symbol-name type) "-in")))
+ (let ((start-pos (syntax-comments-point ,start ,forw))
+ ,@(if res
+ `((stop-pos (syntax-comments-point
+ ,(or stop start) ,(not forw))))))
+ ,(if res
+ `(should
+ (eq (scan-lists start-pos ,(if forw 1 -1) 0)
+ stop-pos))
+ `(should-error (scan-lists start-pos ,(if forw 1 -1) 0)
+ :type 'scan-error)))
+ (,(intern (concat (symbol-name type) "-out")))))))
+
+(defmacro syntax-pps-comments (-type- -start- open close &optional -stop-)
+ "Create an ERT test to test `parse-partial-sexp' with comments.
+This is to test the interface between `parse-partial-sexp' and
+the internal comment routines in syntax.c.
+
+The test uses a fixed name data file, which it visits. It calls
+entry and exit functions to set up and tear down syntax entries
+for comment and paren characters. The test is given a name based
+on the global variable `syntax-comments-section', and the value
+of -START-.
+
+The generated test calls `parse-partial-sexp' three times, the
+first two with COMMENTSTOP set to `syntax-table' so as to stop
+after the start and end of the comment. The third call is
+expected to stop at the brace/paren matching the one where the
+test started.
+
+-TYPE- (unquoted) is a symbol from whose name the entry and exit
+function names are derived by appending \"-in\" and \"-out\".
+
+-START- and -STOP- are decimal numbers corresponding to labels in
+the data file marking the start and expected stop positions. See
+`syntax-comments-point' for a precise specification. If -STOP-
+is missing or nil, the value of -START- is assumed for it.
+
+OPEN and CLOSE are decimal numbers corresponding to labels in the
+data file marking just after the comment opener and closer where
+the `parse-partial-sexp's are expected to stop. See
+`syntax-comments-midpoint' for a precise specification."
+ (declare (debug t))
+ (let* ((type -type-)
+ (start -start-)
+ (start-str (format "%d" start))
+ (stop (or -stop- start)))
+ `(ert-deftest ,(intern (concat "syntax-pps-comments-"
+ syntax-comments-section
+ "-" start-str))
+ ()
+ (with-current-buffer
+ (find-file
+ ,(ert-resource-file "syntax-comments.txt"))
+ (,(intern (concat (symbol-name type) "-in")))
+ (let ((start-pos (syntax-comments-point ,start t))
+ (open-pos (syntax-comments-midpoint ,open))
+ (close-pos (syntax-comments-midpoint ,close))
+ (stop-pos (syntax-comments-point ,stop nil))
+ s)
+ (setq s (parse-partial-sexp
+ start-pos (point-max) 0 nil nil 'syntax-table))
+ (should (eq (point) open-pos))
+ (setq s (parse-partial-sexp
+ (point) (point-max) 0 nil s 'syntax-table))
+ (should (eq (point) close-pos))
+ (setq s (parse-partial-sexp (point) (point-max) 0 nil s))
+ (should (eq (point) stop-pos)))
+ (,(intern (concat (symbol-name type) "-out")))))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; "Pascal" style comments - single character delimiters, the closing
+;; delimiter not being newline.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(defun {-in ()
+ (setq parse-sexp-ignore-comments t)
+ (setq comment-end-can-be-escaped nil)
+ (modify-syntax-entry ?{ "<")
+ (modify-syntax-entry ?} ">"))
+(defun {-out ()
+ (modify-syntax-entry ?{ "(}")
+ (modify-syntax-entry ?} "){"))
+(eval-and-compile
+ (setq syntax-comments-section "pascal"))
+
+(syntax-comments { forward nil 20 0)
+(syntax-comments { backward nil 20 0)
+(syntax-comments { forward t 21)
+(syntax-comments { backward t 21)
+(syntax-comments { forward t 22)
+(syntax-comments { backward t 22)
+
+(syntax-comments { forward t 23)
+(syntax-comments { backward t 23)
+(syntax-comments { forward t 24)
+(syntax-comments { backward t 24)
+(syntax-comments { forward t 26)
+(syntax-comments { backward t 26)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; "Lisp" style comments - single character opening delimiters on line
+;; comments.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(defun \;-in ()
+ (setq parse-sexp-ignore-comments t)
+ (setq comment-end-can-be-escaped nil)
+ (modify-syntax-entry ?\n ">")
+ (modify-syntax-entry ?\; "<")
+ (modify-syntax-entry ?{ ".")
+ (modify-syntax-entry ?} "."))
+(defun \;-out ()
+ (modify-syntax-entry ?\n " ")
+ (modify-syntax-entry ?\; ".")
+ (modify-syntax-entry ?{ "(}")
+ (modify-syntax-entry ?} "){"))
+(eval-and-compile
+ (setq syntax-comments-section "lisp"))
+
+(syntax-comments \; backward nil 30 30)
+(syntax-comments \; forward t 31)
+(syntax-comments \; backward t 31)
+(syntax-comments \; forward t 32)
+(syntax-comments \; backward t 32)
+(syntax-comments \; forward t 33)
+(syntax-comments \; backward t 33)
+
+;; "Lisp" style comments inside lists.
+(syntax-br-comments \; backward nil 40)
+(syntax-br-comments \; forward t 41)
+(syntax-br-comments \; backward t 41)
+(syntax-br-comments \; forward t 42)
+(syntax-br-comments \; backward t 42)
+(syntax-br-comments \; forward nil 43)
+
+;; "Lisp" style comments parsed by `parse-partial-sexp'.
+(syntax-pps-comments \; 41 90 91)
+(syntax-pps-comments \; 42 92 93)
+(syntax-pps-comments \; 43 94 95 -999)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; "Lisp" style nested comments: between delimiters #| |#.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(defun \#|-in ()
+ (setq parse-sexp-ignore-comments t)
+ (modify-syntax-entry ?# ". 14")
+ (modify-syntax-entry ?| ". 23n")
+ (modify-syntax-entry ?\; "< b")
+ (modify-syntax-entry ?\n "> b"))
+(defun \#|-out ()
+ (modify-syntax-entry ?# ".")
+ (modify-syntax-entry ?| ".")
+ (modify-syntax-entry ?\; ".")
+ (modify-syntax-entry ?\n " "))
+(eval-and-compile
+ (setq syntax-comments-section "lisp-n"))
+
+(syntax-comments \#| forward nil 100 0)
+(syntax-comments \#| backward nil 100 0)
+(syntax-comments \#| forward nil 101 -999)
+(syntax-comments \#| forward t 102)
+(syntax-comments \#| backward t 102)
+
+(syntax-comments \#| forward t 103)
+(syntax-comments \#| backward t 103)
+(syntax-comments \#| forward t 104)
+(syntax-comments \#| backward t 104)
+
+(syntax-comments \#| forward nil 105 -999)
+(syntax-comments \#| backward t 105)
+(syntax-comments \#| forward t 106)
+(syntax-comments \#| backward t 106)
+(syntax-comments \#| forward t 107)
+(syntax-comments \#| backward t 107)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Mixed "Lisp" style (nested and unnested) comments.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(syntax-comments \#| forward t 110)
+(syntax-comments \#| backward t 110)
+(syntax-comments \#| forward t 111)
+(syntax-comments \#| backward t 111)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Emacs 27 "C" style comments - `comment-end-can-be-escaped' is non-nil.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(defun /*-in ()
+ (setq parse-sexp-ignore-comments t)
+ (setq comment-end-can-be-escaped t)
+ (modify-syntax-entry ?/ ". 124b")
+ (modify-syntax-entry ?* ". 23")
+ (modify-syntax-entry ?\n "> b"))
+(defun /*-out ()
+ (setq comment-end-can-be-escaped nil)
+ (modify-syntax-entry ?/ ".")
+ (modify-syntax-entry ?* ".")
+ (modify-syntax-entry ?\n " "))
+(eval-and-compile
+ (setq syntax-comments-section "c"))
+
+(syntax-comments /* forward t 1)
+(syntax-comments /* backward t 1)
+(syntax-comments /* forward t 2)
+(syntax-comments /* backward t 2)
+(syntax-comments /* forward t 3)
+(syntax-comments /* backward t 3)
+
+(syntax-comments /* forward t 4)
+(syntax-comments /* backward t 4)
+(syntax-comments /* forward t 5 6)
+(syntax-comments /* backward nil 5 0)
+(syntax-comments /* forward nil 6 0)
+(syntax-comments /* backward t 6 5)
+
+(syntax-comments /* forward t 7 8)
+(syntax-comments /* backward nil 7 0)
+(syntax-comments /* forward nil 8 0)
+(syntax-comments /* backward t 8 7)
+(syntax-comments /* forward t 9)
+(syntax-comments /* backward t 9)
+
+(syntax-comments /* forward nil 10 0)
+(syntax-comments /* backward nil 10 0)
+(syntax-comments /* forward t 11)
+(syntax-comments /* backward t 11)
+
+(syntax-comments /* forward t 13 14)
+(syntax-comments /* backward nil 13 -14)
+(syntax-comments /* forward t 15)
+(syntax-comments /* backward t 15)
+
+;; Emacs 27 "C" style comments inside brace lists.
+(syntax-br-comments /* forward t 50)
+(syntax-br-comments /* backward t 50)
+(syntax-br-comments /* forward t 51)
+(syntax-br-comments /* backward t 51)
+(syntax-br-comments /* forward t 52)
+(syntax-br-comments /* backward t 52)
+
+(syntax-br-comments /* forward t 53)
+(syntax-br-comments /* backward t 53)
+(syntax-br-comments /* forward t 54 20)
+(syntax-br-comments /* backward t 54)
+(syntax-br-comments /* forward t 55)
+(syntax-br-comments /* backward t 55)
+
+(syntax-br-comments /* forward t 56 58)
+(syntax-br-comments /* backward t 58 56)
+(syntax-br-comments /* backward nil 59)
+(syntax-br-comments /* forward t 60)
+(syntax-br-comments /* backward t 60)
+
+;; Emacs 27 "C" style comments parsed by `parse-partial-sexp'.
+(syntax-pps-comments /* 50 70 71)
+(syntax-pps-comments /* 52 72 73)
+(syntax-pps-comments /* 54 74 55 20)
+(syntax-pps-comments /* 56 76 77 58)
+(syntax-pps-comments /* 60 78 79)
+
;;; syntax-tests.el ends here
diff --git a/test/src/textprop-tests.el b/test/src/textprop-tests.el
index aadd7a9474e..b083588e645 100644
--- a/test/src/textprop-tests.el
+++ b/test/src/textprop-tests.el
@@ -1,4 +1,4 @@
-;;; textprop-tests.el --- Test suite for text properties.
+;;; textprop-tests.el --- Test suite for text properties. -*- lexical-binding: t -*-
;; Copyright (C) 2015-2021 Free Software Foundation, Inc.
diff --git a/test/src/thread-tests.el b/test/src/thread-tests.el
index 4aba36c2011..f14d2426ef0 100644
--- a/test/src/thread-tests.el
+++ b/test/src/thread-tests.el
@@ -1,4 +1,4 @@
-;;; threads.el --- tests for threads.
+;;; threads.el --- tests for threads. -*- lexical-binding: t -*-
;; Copyright (C) 2012-2021 Free Software Foundation, Inc.
diff --git a/test/src/timefns-tests.el b/test/src/timefns-tests.el
index ab3ed2ceddf..e55bd1eb4ee 100644
--- a/test/src/timefns-tests.el
+++ b/test/src/timefns-tests.el
@@ -1,21 +1,23 @@
-;;; timefns-tests.el -- tests for timefns.c
+;;; timefns-tests.el -- tests for timefns.c -*- lexical-binding: t -*-
;; Copyright (C) 2016-2021 Free Software Foundation, Inc.
;; This file is part of GNU Emacs.
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
(require 'ert)
@@ -124,44 +126,44 @@
;;; Tests of format-time-string padding
(ert-deftest format-time-string-padding-minimal-deletes-unneeded-zeros ()
- (let ((ref-time (append (encode-time 0 0 0 15 2 2000) '(123450))))
+ (let ((ref-time (encode-time '((123450 . 1000000) 0 0 15 2 2000 - - t))))
(should (equal (format-time-string "%-:::z" ref-time "FJT-12") "+12"))
- (should (equal (format-time-string "%-N" ref-time) "12345"))
- (should (equal (format-time-string "%-6N" ref-time) "12345"))
- (should (equal (format-time-string "%-m" ref-time) "2")))) ;not "02"
+ (should (equal (format-time-string "%-N" ref-time t) "12345"))
+ (should (equal (format-time-string "%-6N" ref-time t) "12345"))
+ (should (equal (format-time-string "%-m" ref-time t) "2")))) ;not "02"
(ert-deftest format-time-string-padding-minimal-retains-needed-zeros ()
- (let ((ref-time (append (encode-time 0 0 0 20 10 2000) '(3450))))
+ (let ((ref-time (encode-time '((3450 . 1000000) 0 0 20 10 2000 - - t))))
(should (equal (format-time-string "%-z" ref-time "IST-5:30") "+530"))
(should (equal (format-time-string "%-4z" ref-time "IST-5:30") "+530"))
(should (equal (format-time-string "%4z" ref-time "IST-5:30") "+530"))
- (should (equal (format-time-string "%-N" ref-time) "00345"))
- (should (equal (format-time-string "%-3N" ref-time) "003"))
- (should (equal (format-time-string "%3N" ref-time) "003"))
- (should (equal (format-time-string "%-m" ref-time) "10")) ;not "1"
- (should (equal (format-time-string "%-1m" ref-time) "10")) ;not "1"
- (should (equal (format-time-string "%1m" ref-time) "10")))) ;not "1"
+ (should (equal (format-time-string "%-N" ref-time t) "00345"))
+ (should (equal (format-time-string "%-3N" ref-time t) "003"))
+ (should (equal (format-time-string "%3N" ref-time t) "003"))
+ (should (equal (format-time-string "%-m" ref-time t) "10")) ;not "1"
+ (should (equal (format-time-string "%-1m" ref-time t) "10")) ;not "1"
+ (should (equal (format-time-string "%1m" ref-time t) "10")))) ;not "1"
(ert-deftest format-time-string-padding-spaces ()
- (let ((ref-time (append (encode-time 0 0 0 10 12 2000) '(123000))))
+ (let ((ref-time (encode-time '((123000 . 1000000) 0 0 10 12 2000 - - t))))
(should (equal (format-time-string "%_7z" ref-time "CHA-12:45") " +1245"))
- (should (equal (format-time-string "%_6N" ref-time) "123 "))
- (should (equal (format-time-string "%_9N" ref-time) "123 "))
- (should (equal (format-time-string "%_12N" ref-time) "123 "))
- (should (equal (format-time-string "%_m" ref-time) "12"))
- (should (equal (format-time-string "%_2m" ref-time) "12"))
- (should (equal (format-time-string "%_3m" ref-time) " 12"))))
+ (should (equal (format-time-string "%_6N" ref-time t) "123 "))
+ (should (equal (format-time-string "%_9N" ref-time t) "123 "))
+ (should (equal (format-time-string "%_12N" ref-time t) "123 "))
+ (should (equal (format-time-string "%_m" ref-time t) "12"))
+ (should (equal (format-time-string "%_2m" ref-time t) "12"))
+ (should (equal (format-time-string "%_3m" ref-time t) " 12"))))
(ert-deftest format-time-string-padding-zeros-adds-on-insignificant-side ()
"Fractional seconds have a fixed place on the left,
and any padding must happen on the right. All other numbers have
a fixed place on the right and are padded on the left."
- (let ((ref-time (append (encode-time 0 0 0 10 12 2000) '(123000))))
- (should (equal (format-time-string "%3m" ref-time) "012"))
+ (let ((ref-time (encode-time '((123000 . 1000000) 0 0 10 12 2000 - - t))))
+ (should (equal (format-time-string "%3m" ref-time t) "012"))
(should (equal (format-time-string "%7z" ref-time "CHA-12:45") "+001245"))
- (should (equal (format-time-string "%12N" ref-time) "123000000000"))
- (should (equal (format-time-string "%9N" ref-time) "123000000"))
- (should (equal (format-time-string "%6N" ref-time) "123000"))))
+ (should (equal (format-time-string "%12N" ref-time t) "123000000000"))
+ (should (equal (format-time-string "%9N" ref-time t) "123000000"))
+ (should (equal (format-time-string "%6N" ref-time t) "123000"))))
(ert-deftest time-equal-p-nil-nil ()
@@ -220,6 +222,9 @@ a fixed place on the right and are padded on the left."
'(23752 27217))))
(ert-deftest float-time-precision ()
+ (should (= (float-time '(0 1 0 4025)) 1.000000004025))
+ (should (= (float-time '(1000000004025 . 1000000000000)) 1.000000004025))
+
(should (< 0 (float-time '(1 . 10000000000))))
(should (< (float-time '(-1 . 10000000000)) 0))
diff --git a/test/src/undo-tests.el b/test/src/undo-tests.el
index 75b6d2761f0..055bf102dfc 100644
--- a/test/src/undo-tests.el
+++ b/test/src/undo-tests.el
@@ -1,21 +1,23 @@
-;;; undo-tests.el --- Tests of primitive-undo
+;;; undo-tests.el --- Tests of primitive-undo -*- lexical-binding: t -*-
;; Copyright (C) 2012-2021 Free Software Foundation, Inc.
;; Author: Aaron S. Hawley <aaron.s.hawley@gmail.com>
-;; This program is free software: you can redistribute it and/or
+;; 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.
;;
-;; This program is distributed in the hope that it will be useful, but
+;; 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 `https://www.gnu.org/licenses/'.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
@@ -452,7 +454,7 @@ Demonstrates bug 25599."
(insert ";; aaaaaaaaa
;; bbbbbbbb")
(let ((overlay-modified
- (lambda (ov after-p _beg _end &optional length)
+ (lambda (ov after-p _beg _end &optional _length)
(unless after-p
(when (overlay-buffer ov)
(delete-overlay ov))))))
diff --git a/test/src/xdisp-tests.el b/test/src/xdisp-tests.el
new file mode 100644
index 00000000000..d13ce77a997
--- /dev/null
+++ b/test/src/xdisp-tests.el
@@ -0,0 +1,75 @@
+;;; xdisp-tests.el --- tests for xdisp.c functions -*- lexical-binding: t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert)
+
+(defmacro xdisp-tests--in-minibuffer (&rest body)
+ (declare (debug t) (indent 0))
+ `(catch 'result
+ (minibuffer-with-setup-hook
+ (lambda ()
+ (let ((redisplay-skip-initial-frame nil)
+ (executing-kbd-macro nil)) ;Don't skip redisplay
+ (throw 'result (progn . ,body))))
+ (let ((executing-kbd-macro t)) ;Force real minibuffer in `read-string'.
+ (read-string "toto: ")))))
+
+(ert-deftest xdisp-tests--minibuffer-resizing () ;; bug#43519
+ (should
+ (equal
+ t
+ (xdisp-tests--in-minibuffer
+ (insert "hello")
+ (let ((ol (make-overlay (point) (point)))
+ (max-mini-window-height 1)
+ (text "askdjfhaklsjdfhlkasjdfhklasdhflkasdhflkajsdhflkashdfkljahsdlfkjahsdlfkjhasldkfhalskdjfhalskdfhlaksdhfklasdhflkasdhflkasdhflkajsdhklajsdgh"))
+ ;; (save-excursion (insert text))
+ ;; (sit-for 2)
+ ;; (delete-region (point) (point-max))
+ (put-text-property 0 1 'cursor t text)
+ (overlay-put ol 'after-string text)
+ (redisplay 'force)
+ ;; Make sure we do the see "hello" text.
+ (prog1 (equal (window-start) (point-min))
+ ;; (list (window-start) (window-end) (window-width))
+ (delete-overlay ol)))))))
+
+(ert-deftest xdisp-tests--minibuffer-scroll () ;; bug#44070
+ (let ((posns
+ (xdisp-tests--in-minibuffer
+ (let ((max-mini-window-height 4))
+ (dotimes (_ 80) (insert "\nhello"))
+ (goto-char (point-min))
+ (redisplay 'force)
+ (goto-char (point-max))
+ ;; A simple edit like removing the last `o' shouldn't cause
+ ;; the rest of the minibuffer's text to move.
+ (list
+ (progn (redisplay 'force) (window-start))
+ (progn (delete-char -1)
+ (redisplay 'force) (window-start))
+ (progn (goto-char (point-min)) (redisplay 'force)
+ (goto-char (point-max)) (redisplay 'force)
+ (window-start)))))))
+ (should (equal (nth 0 posns) (nth 1 posns)))
+ (should (equal (nth 1 posns) (nth 2 posns)))))
+
+;;; xdisp-tests.el ends here
diff --git a/test/src/xfaces-tests.el b/test/src/xfaces-tests.el
new file mode 100644
index 00000000000..0a7ef55b2b6
--- /dev/null
+++ b/test/src/xfaces-tests.el
@@ -0,0 +1,50 @@
+;;; xfaces-tests.el --- tests for xfaces.c -*- lexical-binding: t -*-
+
+;; Copyright (C) 2020-2021 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+(require 'ert)
+
+(ert-deftest xfaces-color-distance ()
+ ;; Check symmetry (bug#41544).
+ (should (equal (color-distance "#222222" "#ffffff")
+ (color-distance "#ffffff" "#222222"))))
+
+(ert-deftest xfaces-internal-color-values-from-color-spec ()
+ (should (equal (color-values-from-color-spec "#f05")
+ '(#xffff #x0000 #x5555)))
+ (should (equal (color-values-from-color-spec "#1fb0C5")
+ '(#x1f1f #xb0b0 #xc5c5)))
+ (should (equal (color-values-from-color-spec "#1f8b0AC5e")
+ '(#x1f81 #xb0aa #xc5eb)))
+ (should (equal (color-values-from-color-spec "#1f83b0ADC5e2")
+ '(#x1f83 #xb0ad #xc5e2)))
+ (should (equal (color-values-from-color-spec "#1f83b0ADC5e2g") nil))
+ (should (equal (color-values-from-color-spec "#1f83b0ADC5e20") nil))
+ (should (equal (color-values-from-color-spec "#12345") nil))
+ (should (equal (color-values-from-color-spec "rgb:f/23/28a")
+ '(#xffff #x2323 #x28a2)))
+ (should (equal (color-values-from-color-spec "rgb:1234/5678/09ab")
+ '(#x1234 #x5678 #x09ab)))
+ (should (equal (color-values-from-color-spec "rgb:0//0") nil))
+ (should (equal (color-values-from-color-spec "rgbi:0/0.5/0.1")
+ '(0 32768 6554)))
+ (should (equal (color-values-from-color-spec "rgbi:1e-3/1.0e-2/1e0")
+ '(66 655 65535)))
+ (should (equal (color-values-from-color-spec "rgbi:0/0.5/10") nil)))
+
+(provide 'xfaces-tests)
diff --git a/test/src/xml-tests.el b/test/src/xml-tests.el
index be5fd5134f3..632cf965fa2 100644
--- a/test/src/xml-tests.el
+++ b/test/src/xml-tests.el
@@ -1,4 +1,4 @@
-;;; libxml-parse-tests.el --- Test suite for libxml parsing.
+;;; xml-tests.el --- Test suite for libxml parsing. -*- lexical-binding: t -*-
;; Copyright (C) 2014-2021 Free Software Foundation, Inc.
@@ -42,20 +42,6 @@
(comment nil "comment-b") (comment nil "comment-c"))))
"Alist of XML strings and their expected parse trees for preserved comments.")
-(defvar libxml-tests--data-comments-discarded
- `(;; simple case
- ("<?xml version=\"1.0\"?><foo baz=\"true\">bar</foo>"
- . (foo ((baz . "true")) "bar"))
- ;; toplevel comments -- first document child must not get lost
- (,(concat "<?xml version=\"1.0\"?><foo>bar</foo><!--comment-1-->"
- "<!--comment-2-->")
- . (foo nil "bar"))
- (,(concat "<?xml version=\"1.0\"?><!--comment-a--><foo a=\"b\">"
- "<bar>blub</bar></foo><!--comment-b--><!--comment-c-->")
- . (foo ((a . "b")) (bar nil "blub"))))
- "Alist of XML strings and their expected parse trees for discarded comments.")
-
-
(ert-deftest libxml-tests ()
"Test libxml."
(when (fboundp 'libxml-parse-xml-region)
@@ -64,11 +50,6 @@
(erase-buffer)
(insert (car test))
(should (equal (cdr test)
- (libxml-parse-xml-region (point-min) (point-max)))))
- (dolist (test libxml-tests--data-comments-discarded)
- (erase-buffer)
- (insert (car test))
- (should (equal (cdr test)
- (libxml-parse-xml-region (point-min) (point-max) nil t)))))))
+ (libxml-parse-xml-region (point-min) (point-max))))))))
;;; libxml-tests.el ends here