org-mode/testing/lisp/test-org-src.el

575 lines
18 KiB
EmacsLisp
Raw Normal View History

testing: Make all files use `lexical-binding` Mainly, add the corresponding cookie, but also add various `require`s so that the compiler knows which vars should be trated as dynbound. This does not fix all the warnings, but does try to eliminate all those about "unused" variables. For the variables truly unused, the patch usually adds an underscore to their name to silence the warning. Some of the fixes affect files which already used `lexical-binding`. Not sure why the test worked before: maybe because the tests were run without compiling them first (which could cause some of the missing `require`d packages to be autoloaded before we got to the problematic code, thus hiding the problem)? I found some suspicious code, for which I added FIXMEs. There are also a few changes to the main files. * lisp/org-protocol.el (org-protocol-check-filename-for-protocol): Don't call `server-edit` if it's not yet defined. [ Needed to get the tests to pass. ] * lisp/ob-core.el (org-babel-temporary-directory) (org-babel-temporary-stable-directory): Always define (and use nil if we don't want to create a directory for it). Simplify the code based on the fact that (defvar V E) only evaluates E if V is not yet `boundp`. (org-babel-temp-file, org-babel-temp-stable-file) (org-babel-remove-temporary-directory) (org-babel-remove-temporary-stable-directory): Adjust accordingly. * lisp/org.el (org-log-beginning): Add FIXME. * testing/org-test.el: Require `org` and `org-id`. (org-id-locations-file): Don't `defconst` it. (org-test-at-id, org-test-in-example-file, org-test-at-marker) (org-test-with-temp-text, org-test-with-temp-text-in-file): Move edebug specs into `declare` (and simplify them). (org-test-with-tramp-remote-dir--worker): Declare dynbound tramp vars. (org--compile-when): Fix quoting of `exp`. (org-test-load): Tweak regexps. * testing/org-batch-test-init.el: Tweak regexp, remove dead code and add a FIXME about it. * testing/lisp/test-ox.el: Require `ox` instead of erroring out if it's not already loaded. Also require `org-inlinetask`. (org-test-with-parsed-data): Silence warnings when `info` is not used. (test-org-export/bind-keyword): Add FIXME. * testing/lisp/test-ox-publish.el: Require `org-test` and `ox-publish`. (test-org-publish/resolve-external-link): Expose lambdas to the compiler. Remove unused var `ids`. (test-org-publish/get-project-from-filename): Remove unused var `file`. * testing/lisp/test-org.el: Require `org-macs`, `org`, `org-inlinetask`, `org-refile`, and `org-agenda`. (test-org/org-read-date): Declare `org-time-was-given` as dynbound. (test-org/set-regexps-and-options): Add FIXME. * testing/lisp/test-org-timer.el: Require `org-timer`. * testing/lisp/test-org-table.el: Require `ox`. * testing/lisp/test-org-protocol.el: Require `org-protocol` instead of erroring out if it's not already loaded. Also require `capture`, and add missing `provide` statement. * testing/lisp/test-org-pcomplete.el: Require `org`. * testing/lisp/test-org-list.el: Require `org-list` and `org`. * testing/lisp/test-org-lint.el: Require `org-footnote` and `org-lint`. * testing/lisp/test-org-footnote.el: Require `org-footnote`. * testing/lisp/test-org-element.el: Require `org-element` instead of erroring out if it's not already loaded. Also require `org` and `org-inlinetask`. * testing/lisp/test-org-duration.el: Require `org-duration`. * testing/lisp/test-org-datetree.el: Require `org-datetree`. * testing/lisp/test-org-colview.el: Require `org-colview`, `org-duration`, and `org-inlinetask`. * testing/lisp/test-org-clock.el: Require `org-duration` and `org-clock`. * testing/lisp/test-org-archive.el: Require `org-archive`. * testing/lisp/test-org-agenda.el (test-org-agenda/bulk-custom-arg-func): Add FIXME. * testing/lisp/test-ol.el: Require `ol` and `org-id`. (test-org-link/store-link): Declare `org-store-link-props` and add FIXME. * testing/lisp/test-oc.el (test-org-cite/export-capability): Add FIXME. * testing/lisp/test-ob.el: Require `ob-core`, `org-src`, `ob-ref`, and `org-table`. (test-ob/eval-header-argument): Rename `foo` to `test-ob--foo` and declare it as dynbound. (test-ob/blocks-with-spaces, test-ob/specific-colnames): Add FIXME. (test-ob/noweb-expansions-in-cache): Declare `noweb-expansions-in-cache-var` as dynbound. * testing/lisp/test-ob-tangle.el: Require `org` and `ob-tangle`. * testing/lisp/test-ob-shell.el: * testing/lisp/test-ob-python.el: Require `ob-core`. * testing/lisp/test-ob-lob.el: Require `ob-lob`. (temporary-value-for-test): Declare as dynbound. * testing/lisp/test-ob-plantuml.el: Require `ob-plantuml` instead of erroring out if it's not already loaded. * testing/lisp/test-ob-lilypond.el: Require `ob-lilypond` instead of erroring out if it's not already loaded. Use `with-current-buffer`. * testing/lisp/test-ob-julia.el: Require `ob-core`. * testing/lisp/test-ob-java.el (org-babel-temporary-directory): Remove dead code now that `org-babel-temporary-directory` is always bound. * testing/lisp/test-ob-exp.el: Require `ob-exp`, `org-src`, and `org-test`. (ob-exp/evaluate-all-executables-in-order): Declare `*evaluation-collector*` as dynbound. * testing/lisp/test-ob-emacs-lisp.el (ob-emacs-lisp/dynamic-lexical-edit) (ob-emacs-lisp/dynamic-lexical-execute): Rename dynbound var to `ob-emacs--x` and declare it as such. * testing/lisp/test-ob-R.el: Require `ob-core`. (ess-ask-for-ess-directory, ess-history-file): Declare vars.
2022-09-14 21:21:37 +00:00
;;; test-org-src.el --- tests for org-src.el -*- lexical-binding: t; -*-
2012-12-13 15:46:40 +00:00
2019-01-01 10:50:56 +00:00
;; Copyright (C) 2012-2015, 2019 Le Wang
2012-12-13 15:46:40 +00:00
;; Author: Le Wang <l26wang at gmail dot com>
2012-12-13 16:24:19 +00:00
;; This file is not part of GNU Emacs.
2012-12-13 15:46:40 +00:00
;; 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/>.
2012-12-13 15:46:40 +00:00
2012-12-13 16:24:19 +00:00
;;; Code:
2012-12-13 15:46:40 +00:00
* lisp/org-agenda.el: Use lexical-binding - Removed the global (defvar date) and (defvar entry) so as not to conflict with function arguments of that name. Instead I added such `defvar`s in the body of each of the functions where it seemed needed. - I added some FIXMEs for some issues I found along the way. - Added an `org-dlet` macro, just like I had done for `calendar-dlet`, but I also use `defvar` "manually" at some places, when splitting an existing `let` into a mix of `let`s and `dlet`s seemed too much trouble. - Removed uses of `org-let and `org-let2` not only because I consider them offensive to my sense of aesthetics but also because they're basically incompatible with lexical scoping. I replaced them with uses of `cl-progv` which are a bit more verbose. Maybe we should define some `org-progv` macro on top of `cl-progv` to make the code less verbose, but I didn't do that because I like the fact that the current code makes uses of `eval` a bit more obvious (since these behave differently with lexical scoping than with lexical binding, it seemed worthwhile). - Removed the use of `eval` in `org-store-agenda-views` which was only placed there in order to use a macro before it's defined (it would have been simpler/cleaner to just move that functions *after* the macro, but with the new code the problem doesn't occur any more anyway). - Replaced a few `(lambda...) with actual closures. Detailed changes follow: (date, entry): Don't declare as being globally dynbound. (org-agenda-format-date-aligned): Remove unused var `weekyear`. (org-agenda-mode): `run-mode-hooks` is always available nowadays. (org-agenda-undo): Remove unused var `last-undo-buffer`. (org-agenda): Rename arg to `keys` and then dyn-bind it as `org-keys`. Remove unused vars `buf` and `key`. (org-agenda): Use `pcase` and `cl-progv` instead of `org-let`. (org-let, org-let2): Mark as obsolete. (org-agenda-run-series): Use `cl-progv` instead of `org-let` and `org-let2`. (org-agenda-run-series): New function. (org--batch-agenda): New function extracted from `org-batch-agenda`. (org-batch-agenda): Use it. (org--batch-agenda-csv): New function extracted from `org-batch-agenda-csv`. (org-batch-agenda-csv): Use it. (org--batch-store-agenda-views): New function, extracted from `org-batch-store-agenda-views`. (org-store-agenda-views, org-batch-store-agenda-views): Use it. (org--batch-store-agenda-views): Use `cl-progv` instead of `org-eval-in-environment`. (org-agenda-write): Use `cl-progv` instead of `org-let`. Use `with-current-buffer`. (org-agenda-filter-any): Use `cl-some` instead of `eval`. (org-agenda-list): Remove unused var `e`. (org-search-view): η-reduce. (crm-separator): Declare var. (org-agenda-skip-if): Remove unused var `beg`. (org-agenda-list-stuck-projects): Use a closure rather than `(lambda..). (diary-modify-entry-list-string-function, diary-file-name-prefix) (diary-display-function): Declare vars. (org-diary): Declare `date` and `entry` as dynbound. (org-agenda-get-day-entries): Use `org-dlet`. (org-agenda-get-timestamps, org-agenda-get-progress) (org-agenda-get-deadlines, org-agenda-get-scheduled, org-agenda-get-blocks): Declare `date` as dynbound. (org-agenda-get-sexps, org-class): Declare `date` and `entry` as dynbound. (org-agenda-format-item): Declare the vars mentioned in `org-compile-prefix-format` as dyn-bound. Also binding `extra`, suggested by Kyle Meyer <kyle@kyleam.com>. (org-compile-prefix-format): Remove unused var `e`. Use `member` rather than or+equal. (org-set-sorting-strategy): Minor simplification. (org-entries-lessp): Use `org-dlet`. (org-agenda-redo): Declare var `org-agenda-tag-filter-while-redo`. (org-agenda-redo): Use `cl-progv` rather than `org-let`. (org-agenda-filter): Remove unused var `rpl-fn`. Use `org-pushnew-to-end` to replace `add-to-list` on lexical var. (org-agenda-filter-by-tag): Remove unused var `n`. (org-agenda-filter-apply): Use `org-dlet`. (org-agenda-compute-starting-span): Remove unused var `dg`. (org-agenda-forward-block): Remove unused var `pos`. (org-archive-from-agenda): Declare var. (org-agenda-refile): Remove unused var `pos`. (org-agenda-headline-snapshot-before-repeat): Declare var. (org-agenda-todo): Remove redundant use of `bound-and-true-p`. (org-agenda-add-note): Remove unused var `hdmarker` and unused `arg`. (org-agenda-change-all-lines): Remove unused var `pl`. (org-agenda-priority): Remove unused var `marker`. (org-agenda-set-effort): Remove unused var `newhead`. (org-agenda-schedule): Remove unused var `type`. (org-agenda-clock-cancel): Remove unused `arg`. (org-agenda-execute-calendar-command): Use `org-dlet`. (org-agenda-bulk-action): Use closures instead of `(lambda ...). (org-agenda-show-the-flagging-note): Remove unused vars `heading` and `newhead`. (org-agenda-remove-flag): Avoid `setq`. * testing/org-test.el (org--compile-when): New macro. (org-test-jump): Use it so compilation doesn't fail or generate broken code when `jump` is not available. * testing/lisp/test-org-src.el: * testing/lisp/test-org-attach.el: * testing/lisp/test-org-agenda.el: * testing/lisp/test-ob-java.el: Pass explicit filename to `require` so as not to rely on ".../testing" being in `load-path` during compilation. * lisp/org-num.el: Require` org`. * lisp/org-macs.el (org-eval-in-environment): Declare obsolete. (org-dlet, org-pushnew-to-end): New macros. * doc/Makefile (org.texi, orgguide.texi, %_letter.tex): Simplify quoting. * contrib/lisp/ob-sclang.el: Don't crash compilation when `sclang` is not available. * contrib/lisp/ob-clojure-literate.el: Don't crash compilation when `cider` is not available. * contrib/lisp/ob-arduino.el: Don't crash compilation when `arduino-mode` is not available. * .gitignore: Add files generated during `make packages/org`.
2021-02-23 20:47:29 +00:00
(require 'org-test "../testing/org-test")
2012-12-13 15:46:40 +00:00
(ert-deftest test-org-src/basic ()
"Editing regular block works, with point on source block."
2012-12-13 15:46:40 +00:00
(org-test-with-temp-text
"
<point>#+begin_src emacs-lisp
2012-12-13 15:46:40 +00:00
(message hello)
#+end_src
"
(let ((org-edit-src-content-indentation 2)
(org-src-preserve-indentation nil))
(org-edit-special)
(insert "blah")
(org-edit-src-exit)
(should (equal (buffer-string) "
2012-12-13 15:46:40 +00:00
#+begin_src emacs-lisp
blah(message hello)
#+end_src
"))
(should (looking-at-p "(message hello)")))))
2012-12-13 15:46:40 +00:00
(ert-deftest test-org-src/point-outside-block ()
"Editing with point before/after block signals expected error."
(org-test-with-temp-text
"
#+begin_src emacs-lisp
(message hello)
#+end_src
"
(goto-line 1)
(should-error (org-edit-special))
(goto-char (point-max))
(should-error (org-edit-special))))
(ert-deftest test-org-src/undo ()
"Undo-ing an edit buffer should not go back to empty state."
(org-test-with-temp-text "
#+begin_src emacs-lisp<point>
(message hello)
#+end_src
"
(org-edit-special)
(should-error (undo))
(org-edit-src-exit)))
2012-12-13 15:46:40 +00:00
(ert-deftest test-org-src/empty-block ()
"Editing empty block."
(org-test-with-temp-text
"
<point>#+begin_src emacs-lisp
2012-12-13 15:46:40 +00:00
#+end_src
"
(let ((org-edit-src-content-indentation 0)
(org-src-preserve-indentation nil))
(org-edit-special)
(insert "blah")
(org-edit-src-exit)
(should (equal (buffer-string) "
2012-12-13 15:46:40 +00:00
#+begin_src emacs-lisp
blah
2012-12-13 15:46:40 +00:00
#+end_src
"))
(should
(equal (buffer-substring (line-beginning-position) (point)) "blah")))))
2012-12-13 15:46:40 +00:00
(ert-deftest test-org-src/blank-line-block ()
"Editing block with just a blank line."
(org-test-with-temp-text-in-file
2012-12-13 15:46:40 +00:00
"
#+begin_src emacs-lisp
#+end_src
"
(let ((org-edit-src-content-indentation 2)
(org-src-preserve-indentation nil))
(goto-line 2)
(org-edit-special)
(insert "blah")
(org-edit-src-exit)
(should (equal (buffer-string) "
2012-12-13 15:46:40 +00:00
#+begin_src emacs-lisp
blah
#+end_src
")))))
2012-12-13 15:46:40 +00:00
(ert-deftest test-org-src/preserve-tabs ()
"Editing block preserve tab characters."
;; With `org-src-preserve-indentation' set to nil.
(should
(equal "
#+begin_src emacs-lisp
This is a tab:\t.
#+end_src"
(org-test-with-temp-text
"
#+begin_src emacs-lisp
<point>This is a tab:\t.
#+end_src"
(let ((org-edit-src-content-indentation 2)
(org-src-preserve-indentation nil))
(org-edit-special)
(org-edit-src-exit)
(buffer-string)))))
;; With `org-src-preserve-indentation' set to t.
(should
(equal "
#+begin_src emacs-lisp
This is a tab:\t.
#+end_src"
(org-test-with-temp-text
"
#+begin_src emacs-lisp
<point>This is a tab:\t.
#+end_src"
(let ((org-edit-src-content-indentation 2)
(org-src-preserve-indentation t))
(org-edit-special)
(org-edit-src-exit)
(buffer-string))))))
(ert-deftest test-org-src/preserve-empty-lines ()
"Editing block preserves empty lines."
(should
(equal "
#+begin_src emacs-lisp
The following line is empty
abc
#+end_src"
(org-test-with-temp-text
"
#+begin_src emacs-lisp
The following line is empty
abc<point>
#+end_src"
(let ((org-edit-src-content-indentation 2)
(org-src-preserve-indentation nil))
(org-edit-special)
(org-edit-src-exit)
(buffer-string)))))
(should
(equal "
#+begin_src emacs-lisp
The following line is empty
abc
#+end_src"
(org-test-with-temp-text
"
#+begin_src emacs-lisp
The following line is empty
<point>
abc
#+end_src"
(let ((org-edit-src-content-indentation 2)
(org-src-preserve-indentation nil))
(org-edit-special)
(org-edit-src-exit)
(buffer-string))))))
(ert-deftest test-org-src/coderef-format ()
"Test `org-src-coderef-format' specifications."
;; Regular tests in a src block, an example block and an edit
;; buffer.
(should
(equal "foo"
(let ((org-coderef-label-format "foo"))
(org-test-with-temp-text "#+BEGIN_SRC emacs-lisp\n0\n#+END_SRC"
(org-src-coderef-format)))))
(should
(equal "foo"
(let ((org-coderef-label-format "foo"))
(org-test-with-temp-text "#+BEGIN_EXAMPLE\n0\n#+END_EXAMPLE"
(org-src-coderef-format)))))
(should
(equal "foo"
(let ((org-coderef-label-format "foo") result)
(org-test-with-temp-text "#+BEGIN_SRC emacs-lisp\n0\n#+END_SRC"
(org-edit-special)
(setq result (org-src-coderef-format))
(org-edit-src-exit)
result))))
;; When a local variable in the source buffer is available, use it.
(should
(equal "bar"
(let ((org-coderef-label-format "foo"))
(org-test-with-temp-text "#+BEGIN_SRC emacs-lisp\n0\n#+END_SRC"
(setq-local org-coderef-label-format "bar")
(org-src-coderef-format)))))
(should
(equal "bar"
(let ((org-coderef-label-format "foo") result)
(org-test-with-temp-text "#+BEGIN_SRC emacs-lisp\n0\n#+END_SRC"
(setq-local org-coderef-label-format "bar")
(org-edit-special)
(setq result (org-src-coderef-format))
(org-edit-src-exit)
result))))
;; Use provided local format even if in an edit buffer.
(should
(equal "bar"
(let ((org-coderef-label-format "foo"))
(org-test-with-temp-text
"#+BEGIN_SRC emacs-lisp -l \"bar\"\n0\n#+END_SRC"
(org-src-coderef-format)))))
(should
(equal "bar"
(let ((org-coderef-label-format "foo") result)
(org-test-with-temp-text
"#+BEGIN_SRC emacs-lisp -l \"bar\"\n0\n#+END_SRC"
(org-edit-special)
(setq result (org-src-coderef-format))
(org-edit-src-exit)
result))))
;; Local format has precedence over local variables.
(should
(equal "bar"
(let ((org-coderef-label-format "foo"))
(org-test-with-temp-text
"#+BEGIN_SRC emacs-lisp -l \"bar\"\n0\n#+END_SRC"
(setq-local org-coderef-label-format "foo")
(org-src-coderef-format)))))
(should
(equal "bar"
(let ((org-coderef-label-format "foo") result)
(org-test-with-temp-text
"#+BEGIN_SRC emacs-lisp -l \"bar\"\n0\n#+END_SRC"
(setq-local org-coderef-label-format "foo")
(org-edit-special)
(setq result (org-src-coderef-format))
(org-edit-src-exit)
result))))
;; When optional argument provides a coderef format string, use it.
(should
(equal "bar"
(let ((org-coderef-label-format "foo")
(element (org-element-create 'src-block '(:label-fmt "bar"))))
(org-test-with-temp-text "#+BEGIN_SRC emacs-lisp\n0\n#+END_SRC"
(org-src-coderef-format element)))))
(should
(equal "baz"
(let ((org-coderef-label-format "foo")
(element (org-element-create 'src-block '(:label-fmt "baz"))))
(org-test-with-temp-text
"#+BEGIN_SRC emacs-lisp -l \"bar\"\n0\n#+END_SRC"
(setq-local org-coderef-label-format "foo")
(org-src-coderef-format element)))))
;; If it doesn't provide any label format string, fall back to
;; regular checks.
(should
(equal "foo"
(let ((org-coderef-label-format "foo")
(element (org-element-create 'src-block)))
(org-test-with-temp-text "#+BEGIN_SRC emacs-lisp\n0\n#+END_SRC"
(org-src-coderef-format element)))))
(should
(equal "bar"
(let ((org-coderef-label-format "foo")
(element (org-element-create 'src-block)))
(org-test-with-temp-text
"#+BEGIN_SRC emacs-lisp -l \"bar\"\n0\n#+END_SRC"
(setq-local org-coderef-label-format "foo")
(org-src-coderef-format element))))))
(ert-deftest test-org-src/coderef-regexp ()
"Test `org-src-coderef-regexp' specifications."
;; Regular test.
(should
(string-match-p (org-src-coderef-regexp "; ref:%s")
"#+BEGIN_SRC emacs-lisp\n0; ref:label\n#+END_SRC"))
;; Ignore white space around the coderef.
(should
(string-match-p (org-src-coderef-regexp "; ref:%s")
"#+BEGIN_SRC emacs-lisp\n0 ; ref:label\n#+END_SRC"))
(should
(string-match-p (org-src-coderef-regexp "; ref:%s")
"#+BEGIN_SRC emacs-lisp\n0 ; ref:label \n#+END_SRC"))
;; Only match regexp at the end of the line.
(should-not
(string-match-p (org-src-coderef-regexp "; ref:%s")
"#+BEGIN_SRC emacs-lisp\n0; ref:label (+ 1 2)\n#+END_SRC"))
;; Do not match an empty label.
(should-not
(string-match-p (org-src-coderef-regexp "; ref:%s")
"#+BEGIN_SRC emacs-lisp\n0; ref:\n#+END_SRC"))
;; When optional argument LABEL is provided, match given label only.
(should
(string-match-p (org-src-coderef-regexp "; ref:%s" "label")
"#+BEGIN_SRC emacs-lisp\n0; ref:label\n#+END_SRC"))
(should-not
(string-match-p (org-src-coderef-regexp "; ref:%s" "label2")
"#+BEGIN_SRC emacs-lisp\n0; ref:label\n#+END_SRC")))
(ert-deftest test-org-src/indented-blocks ()
"Test editing indented blocks."
;; Editing a block should preserve its global indentation, unless
;; `org-src-preserve-indentation' is non-nil.
(should
(equal
"- Item\n #+BEGIN_SRC emacs-lisp\n Foo\n #+END_SRC"
(org-test-with-temp-text
"- Item\n<point> #+BEGIN_SRC emacs-lisp\n (+ 1 1)\n #+END_SRC"
(let ((org-edit-src-content-indentation 2)
(org-src-preserve-indentation nil))
(org-edit-special)
(erase-buffer)
(insert "Foo")
(org-edit-src-exit)
(buffer-string)))))
(should
(equal
"- Item\n #+BEGIN_SRC emacs-lisp\n Foo\n #+END_SRC"
(org-test-with-temp-text
"- Item\n<point> #+BEGIN_SRC emacs-lisp\n (+ 1 1)\n #+END_SRC"
(let ((org-src-preserve-indentation t))
(org-edit-special)
(erase-buffer)
(insert " Foo")
(org-edit-src-exit)
(buffer-string)))))
;; Global indentation does not obey `indent-tabs-mode' from the
;; original buffer.
(should-not
(string-match-p
"\t"
(org-test-with-temp-text
"
- Item
#+BEGIN_SRC emacs-lisp<point>
(progn
(function argument1
argument2))
#+END_SRC"
(setq-local indent-tabs-mode t)
(let ((org-edit-src-content-indentation 2)
(org-src-preserve-indentation nil))
(org-edit-special)
(org-edit-src-exit)
(buffer-string)))))
;; Tab character is preserved
(should
(string-match-p
"\targument2"
(org-test-with-temp-text
"
- Item
#+BEGIN_SRC emacs-lisp<point>
(progn\n (function argument1\n \targument2))
#+END_SRC"
(setq-local indent-tabs-mode nil)
(let ((org-edit-src-content-indentation 2)
(org-src-preserve-indentation nil))
(org-edit-special)
(org-edit-src-exit)
(buffer-string)))))
;; Indentation does not obey `tab-width' from org buffer.
(should
(string-match-p
"^ \targument2"
(org-test-with-temp-text
"
#+BEGIN_SRC emacs-lisp
(progn
(list argument1\n \t<point>argument2))
#+END_SRC"
(setq-local indent-tabs-mode t)
(setq-local tab-width 4)
(let ((org-edit-src-content-indentation 2)
(org-src-preserve-indentation nil))
(org-edit-special)
(setq-local indent-tabs-mode t)
(setq-local tab-width 8)
(lisp-indent-line)
(org-edit-src-exit)
(buffer-string)))))
;; Tab characters are displayed with `tab-width' from the native
;; edit buffer.
(should
(equal
10
(org-test-with-temp-text
"
#+BEGIN_SRC emacs-lisp
(progn
(list argument1\n \t<point>argument2))
#+END_SRC"
(setq-local indent-tabs-mode t)
(setq-local tab-width 4)
(let ((org-edit-src-content-indentation 2)
(org-src-preserve-indentation nil))
(font-lock-ensure)
;; `current-column' will not work with older versions of emacs
;; before commit 4243747b1b8: Fix 'current-column' in the
;; presence of display strings
(if (<= emacs-major-version 28)
(+ (progn (backward-char) (length (get-text-property (point) 'display)))
(current-column))
(current-column))))))
;; The initial tab characters respect org's `tab-width'.
(should
(equal
10
(org-test-with-temp-text
"
#+BEGIN_SRC emacs-lisp
\t(progn
\t (list argument1\n\t\t<point>argument2))
#+END_SRC"
(setq-local indent-tabs-mode t)
(setq-local tab-width 2)
(let ((org-edit-src-content-indentation 2)
(org-src-preserve-indentation nil))
(font-lock-ensure)
(if (<= emacs-major-version 28)
(+ (progn (backward-char) (length (get-text-property (point) 'display)))
(current-column))
(current-column)))))))
(ert-deftest test-org-src/indented-latex-fragments ()
"Test editing multiline indented LaTeX fragment."
(should
(equal
"- Item $abc\n efg$"
(org-test-with-temp-text
"- Item $abc<point>\n efg$"
(org-edit-special)
(org-edit-src-exit)
(buffer-string)))))
(ert-deftest test-org-src/footnote-references ()
"Test editing footnote references."
;; Error when there is no definition to edit.
(should-error
(org-test-with-temp-text "A footnote<point>[fn:1]"
(org-edit-special)))
;; Error when trying to edit an anonymous footnote.
(should-error
(org-test-with-temp-text "A footnote[fn::<point>edit me!]"
(org-edit-special)))
;; Edit a regular definition.
(should
(equal "[fn:1] Definition"
(org-test-with-temp-text "A footnote<point>[fn:1]\n[fn:1] Definition"
(org-edit-special)
(prog1 (buffer-string) (org-edit-src-exit)))))
;; Label should be protected against editing.
(should
(org-test-with-temp-text "A footnote<point>[fn:1]\n[fn:1] Definition"
(org-edit-special)
(prog1 (get-text-property 0 'read-only (buffer-string))
(org-edit-src-exit))))
(should
(org-test-with-temp-text "A footnote<point>[fn:1]\n[fn:1] Definition"
(org-edit-special)
(prog1 (get-text-property 5 'read-only (buffer-string))
(org-edit-src-exit))))
;; Edit a regular definition.
(should
(equal
"A footnote[fn:1][fn:2]\n[fn:1] D1\n\n[fn:2] D2"
(org-test-with-temp-text
"A footnote<point>[fn:1][fn:2]\n[fn:1] D1\n\n[fn:2] D2"
(org-edit-special)
(org-edit-src-exit)
(buffer-string))))
;; Edit an inline definition.
(should
(equal
"[fn:1:definition]"
(org-test-with-temp-text
"An inline<point>[fn:1] footnote[fn:1:definition]"
(org-edit-special)
(prog1 (buffer-string) (org-edit-src-exit)))))
;; Label and closing square bracket should be protected against
;; editing.
(should
(org-test-with-temp-text "An inline<point>[fn:1] footnote[fn:1:definition]"
(org-edit-special)
(prog1 (get-text-property 0 'read-only (buffer-string))
(org-edit-src-exit))))
(should
(org-test-with-temp-text "An inline<point>[fn:1] footnote[fn:1:definition]"
(org-edit-special)
(prog1 (get-text-property 5 'read-only (buffer-string))
(org-edit-src-exit))))
(should
(org-test-with-temp-text "An inline<point>[fn:1] footnote[fn:1:definition]"
(org-edit-special)
(prog1 (get-text-property 16 'read-only (buffer-string))
(org-edit-src-exit))))
;; Do not include trailing white spaces when displaying the inline
;; footnote definition.
(should
(equal
"[fn:1:definition]"
(org-test-with-temp-text
"An inline<point>[fn:1] footnote[fn:1:definition] and some text"
(org-edit-special)
(prog1 (buffer-string) (org-edit-src-exit)))))
;; Preserve local variables when editing a footnote definition.
(should
(eq 'bar
(org-test-with-temp-text "A footnote<point>[fn:1]\n[fn:1] Definition"
(setq-local foo 'bar)
(org-edit-special)
(prog1 foo (org-edit-src-exit))))))
;;; Code escaping
(ert-deftest test-org-src/escape-code-in-string ()
"Test `org-escape-code-in-string' specifications."
;; Escape lines starting with "*" or "#+".
(should (equal ",*" (org-escape-code-in-string "*")))
(should (equal ",#+" (org-escape-code-in-string "#+")))
;; Escape lines starting with ",*" and ",#+". Number of leading
;; commas does not matter.
(should (equal ",,*" (org-escape-code-in-string ",*")))
(should (equal ",,#+" (org-escape-code-in-string ",#+")))
(should (equal ",,,*" (org-escape-code-in-string ",,*")))
(should (equal ",,,#+" (org-escape-code-in-string ",,#+")))
;; Indentation does not matter.
(should (equal " ,*" (org-escape-code-in-string " *")))
(should (equal " ,#+" (org-escape-code-in-string " #+")))
;; Do nothing on other cases.
(should (equal "a" (org-escape-code-in-string "a")))
(should (equal "#" (org-escape-code-in-string "#")))
(should (equal "," (org-escape-code-in-string ","))))
(ert-deftest test-org-src/unescape-code-in-string ()
"Test `org-unescape-code-in-string' specifications."
;; Unescape lines starting with ",*" or ",#+". Number of leading
;; commas does not matter.
(should (equal "*" (org-unescape-code-in-string ",*")))
(should (equal "#+" (org-unescape-code-in-string ",#+")))
(should (equal ",*" (org-unescape-code-in-string ",,*")))
(should (equal ",#+" (org-unescape-code-in-string ",,#+")))
;; Indentation does not matter.
(should (equal " *" (org-unescape-code-in-string " ,*")))
(should (equal " #+" (org-unescape-code-in-string " ,#+")))
;; Do nothing on other cases.
(should (equal "a" (org-unescape-code-in-string "a")))
(should (equal "#" (org-unescape-code-in-string "#")))
(should (equal "," (org-unescape-code-in-string ","))))
2012-12-13 15:46:40 +00:00
(provide 'test-org-src)
;;; test-org-src.el ends here