;;; math-preview-test.el  -*- lexical-binding: t -*-

;; This file is not part of GNU Emacs

;; This file 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.

;; 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.

;; For a full copy of the GNU General Public License
;; see <http://www.gnu.org/licenses/>.

(require 'math-preview)

;;; Code:

(defmacro with-test-file (file &rest body)
  "Run BODY in a temporary buffer with test FILE loaded."
  (declare (indent 1))
  `(with-temp-buffer
     (insert-file-contents ,file)
     ,@body))

(defun compare-cons (pair1 pair2)
  "Helper function to compare PAIR1 to PAIR2."
  (and (= (car pair1) (car pair2)) (= (cdr pair1) (cdr pair2))))

(ert-deftest math-preview-test/math-preview--json-bool ()
  "Test `math-preview--json-bool' function."
  (should (eq (math-preview--json-bool t) t))
  (should (eq (math-preview--json-bool nil) json-false)))

(ert-deftest math-preview-test/math-preview--number-or-function ()
  "Test `math-preview--number-or-function' function."
  (should (= (math-preview--number-or-function 10) 10))
  (should (= (math-preview--number-or-function (lambda () 15)) 15)))

(ert-deftest math-preview-test/math-preview--create-mark-list ()
  "Test `math-preview--create-mark-list' function."
  (let ((math-preview-tex-marks '(("1" "1" 3 nil nil)))
	(math-preview-tex-marks-inline '(("1" "1" 2 nil nil)))
	(math-preview-mathml-marks '(("1" "1" 5 nil nil)))
	(math-preview-mathml-marks-inline '(("1" "1" 1 nil nil)))
	(math-preview-asciimath-marks '(("1" "1" 4 nil nil)))
	(math-preview-asciimath-marks-inline '(("1" "1" 6 nil nil))))
    (should (string-equal (nth 0 (nth 0 (math-preview--create-mark-list))) "asciimath"))
    (should (string-equal (nth 0 (nth 1 (math-preview--create-mark-list))) "mathml"))
    (should (string-equal (nth 0 (nth 2 (math-preview--create-mark-list))) "asciimath"))
    (should (string-equal (nth 0 (nth 3 (math-preview--create-mark-list))) "tex"))
    (should (string-equal (nth 0 (nth 4 (math-preview--create-mark-list))) "tex"))
    (should (string-equal (nth 0 (nth 5 (math-preview--create-mark-list))) "mathml"))
    (should (eq (nth 3 (nth 0 (math-preview--create-mark-list))) t))
    (should (eq (nth 3 (nth 1 (math-preview--create-mark-list))) nil))
    (should (eq (nth 3 (nth 2 (math-preview--create-mark-list))) nil))
    (should (eq (nth 3 (nth 3 (math-preview--create-mark-list))) nil))
    (should (eq (nth 3 (nth 4 (math-preview--create-mark-list))) t))
    (should (eq (nth 3 (nth 5 (math-preview--create-mark-list))) t))
    (should (= (nth 4 (nth 0 (math-preview--create-mark-list))) 6))
    (should (= (nth 4 (nth 1 (math-preview--create-mark-list))) 5))
    (should (= (nth 4 (nth 2 (math-preview--create-mark-list))) 4))
    (should (= (nth 4 (nth 3 (math-preview--create-mark-list))) 3))
    (should (= (nth 4 (nth 4 (math-preview--create-mark-list))) 2))
    (should (= (nth 4 (nth 5 (math-preview--create-mark-list))) 1)))
  (let ((math-preview-tex-marks '(("11" "2" 0 nil nil)
                                  ("1" "2" 0 nil nil)
                                  ("111" "22" 0 nil nil)
                                  ("1111" "2" 0 nil nil)
                                  ("111" "2" 0 nil nil)))
	(math-preview-tex-marks-inline '())
	(math-preview-mathml-marks '())
	(math-preview-mathml-marks-inline '())
	(math-preview-asciimath-marks '())
	(math-preview-asciimath-marks-inline '()))
    (should (string-equal (nth 1 (nth 0 (math-preview--create-mark-list))) "1111"))
    (should (string-equal (nth 1 (nth 1 (math-preview--create-mark-list))) "111"))
    (should (string-equal (nth 1 (nth 2 (math-preview--create-mark-list))) "111"))
    (should (string-equal (nth 1 (nth 3 (math-preview--create-mark-list))) "11"))
    (should (string-equal (nth 1 (nth 4 (math-preview--create-mark-list))) "1"))
    (should (string-equal (nth 2 (nth 0 (math-preview--create-mark-list))) "2"))
    (should (string-equal (nth 2 (nth 1 (math-preview--create-mark-list))) "22"))
    (should (string-equal (nth 2 (nth 2 (math-preview--create-mark-list))) "2"))
    (should (string-equal (nth 2 (nth 3 (math-preview--create-mark-list))) "2"))
    (should (string-equal (nth 2 (nth 4 (math-preview--create-mark-list))) "2"))))

(ert-deftest math-preview-test/math-preview--search ()
  "Test `math-preview--search' function."
  (with-test-file
   "tests/001.txt"
   (let ((math-preview-tex-marks '(("$$" "$$" 0 nil nil)
                                   ("\\[" "\\]" 0 nil nil)))
	 (math-preview-tex-marks-inline '(("$" "$" 0 nil nil)
                                          ("\\(" "\\)" 0 nil nil)))
	 (math-preview-mathml-marks '())
	 (math-preview-mathml-marks-inline '())
	 (math-preview-asciimath-marks '())
	 (math-preview-asciimath-marks-inline '()))
     (should (compare-cons (nth 0 (math-preview--search (point-min) (point-max))) '(7 . 12)))
     (should (compare-cons (nth 1 (math-preview--search (point-min) (point-max))) '(12 . 17)))
     (should (compare-cons (nth 2 (math-preview--search (point-min) (point-max))) '(87 . 94)))
     (should (compare-cons (nth 3 (math-preview--search (point-min) (point-max))) '(186 . 193)))
     (should (compare-cons (nth 4 (math-preview--search (point-min) (point-max))) '(207 . 214)))
     (should (compare-cons (nth 5 (math-preview--search (point-min) (point-max))) '(362 . 369)))
     (should (compare-cons (nth 6 (math-preview--search (point-min) (point-max))) '(566 . 574)))
     (should (compare-cons (nth 7 (math-preview--search (point-min) (point-max))) '(681 . 690)))))
  (with-test-file
   "tests/002.txt"
   (let ((math-preview-tex-marks '(("\\\\begin{equation\\*?}" "\\\\end{equation\\*?}" 0 t t)))
	 (math-preview-tex-marks-inline '())
	 (math-preview-mathml-marks '())
	 (math-preview-mathml-marks-inline '())
	 (math-preview-asciimath-marks '())
	 (math-preview-asciimath-marks-inline '()))
     (should (compare-cons (nth 0 (math-preview--search (point-min) (point-max))) '(545 . 580)))
     (should (compare-cons (nth 1 (math-preview--search (point-min) (point-max))) '(1143 . 1180)))
     (should (compare-cons (nth 2 (math-preview--search (point-min) (point-max))) '(1702 . 1737))))))

(ert-deftest math-preview-test/math-preview--extract-match/extract ()
  "Test `math-preview--extract-match' function hash values."
  (let ((math-preview-tex-marks '(("$l" "$r" 0 nil nil)))
        (math-preview-tex-marks-inline '())
        (string "$lx^2$r"))
    (should (string-equal (gethash 'match (math-preview--extract-match string)) "$lx^2$r"))
    (should (string-equal (gethash 'string (math-preview--extract-match string)) "x^2"))
    (should (string-equal (gethash 'type (math-preview--extract-match string)) "tex"))
    (should-not (gethash 'inline (math-preview--extract-match string)))
    (should (= (gethash 'priority (math-preview--extract-match string)) 0))
    (should (string-equal (gethash 'lmark (math-preview--extract-match string)) "$l"))
    (should (string-equal (gethash 'rmark (math-preview--extract-match string)) "$r"))
    (should (string-equal (car (gethash 'marks (math-preview--extract-match string))) "$l"))
    (should (string-equal (cdr (gethash 'marks (math-preview--extract-match string))) "$r"))
    (should-not (gethash 'lregexp (math-preview--extract-match string)))
    (should-not (gethash 'rregexp (math-preview--extract-match string)))
    (should-not (car (gethash 'regexp (math-preview--extract-match string))))
    (should-not (cdr (gethash 'regexp (math-preview--extract-match string))))
    (should (string-equal (gethash 'prefix (math-preview--extract-match string)) "$l"))
    (should (string-equal (gethash 'suffix (math-preview--extract-match string)) "$r")))
  (let ((math-preview-tex-marks-inline '(("$l" "$r" 0 nil nil)))
        (math-preview-tex-marks '())
        (string "$lx^2$r"))
    (should (gethash 'inline (math-preview--extract-match string))))
  (let ((math-preview-tex-marks-inline '(("$l" "$r" 0 nil nil)))
        (math-preview-tex-marks '(("$l" "$r" 0 nil nil)))
        (string "$lx^2$r"))
    (should-not (gethash 'inline (math-preview--extract-match string))))
  (let ((math-preview-tex-marks-inline '(("$l" "$r" 1 nil nil)))
        (math-preview-tex-marks '(("$l" "$r" 0 nil nil)))
        (string "$lx^2$r"))
    (should (gethash 'inline (math-preview--extract-match string)))))

(ert-deftest math-preview-test/math-preview--extract-match/priority ()
  "Test `math-preview--extract-match' function mark priorities."
  (let ((math-preview-tex-marks-inline '(("$" "$" 0 nil nil)))
        (math-preview-tex-marks '(("$$" "$$" 0 nil nil)))
        (string "$$x^2$$"))
    (should-not (gethash 'inline (math-preview--extract-match string)))
    (should (string-equal (gethash 'lmark (math-preview--extract-match string)) "$$"))
    (should (string-equal (gethash 'rmark (math-preview--extract-match string)) "$$")))
  (let ((math-preview-tex-marks-inline '(("$" "$$" 0 nil nil)))
        (math-preview-tex-marks '(("$" "$" 0 nil nil)))
        (string "$x^2$$"))
    (should (gethash 'inline (math-preview--extract-match string)))
    (should (string-equal (gethash 'lmark (math-preview--extract-match string)) "$"))
    (should (string-equal (gethash 'rmark (math-preview--extract-match string)) "$$")))
  (let ((math-preview-tex-marks-inline '(("$$" "$$" 0 nil nil)))
        (math-preview-tex-marks '(("$$" "$$" 0 nil nil)))
        (math-preview-asciimath-marks-inline '(("$$" "$$" 0 nil nil)))
        (math-preview-asciimath-marks '(("$$" "$$" 0 nil nil)))
        (math-preview-mathml-marks-inline '(("$$" "$$" 0 nil nil)))
        (math-preview-mathml-marks '(("$$" "$$" 0 nil nil)))
        (string "$$x^2$$"))
    (should (string-equal (gethash 'type (math-preview--extract-match string)) "tex"))
    (should-not (gethash 'inline (math-preview--extract-match string))))
  (let ((math-preview-tex-marks-inline '(("$$" "$$" 0 nil nil)))
        (math-preview-tex-marks '())
        (math-preview-asciimath-marks-inline '(("$$" "$$" 0 nil nil)))
        (math-preview-asciimath-marks '(("$$" "$$" 0 nil nil)))
        (math-preview-mathml-marks-inline '(("$$" "$$" 0 nil nil)))
        (math-preview-mathml-marks '(("$$" "$$" 0 nil nil)))
        (string "$$x^2$$"))
    (should (string-equal (gethash 'type (math-preview--extract-match string)) "tex"))
    (should (gethash 'inline (math-preview--extract-match string))))
  (let ((math-preview-tex-marks-inline '())
        (math-preview-tex-marks '())
        (math-preview-asciimath-marks-inline '(("$$" "$$" 0 nil nil)))
        (math-preview-asciimath-marks '(("$$" "$$" 0 nil nil)))
        (math-preview-mathml-marks-inline '(("$$" "$$" 0 nil nil)))
        (math-preview-mathml-marks '(("$$" "$$" 0 nil nil)))
        (string "$$x^2$$"))
    (should (string-equal (gethash 'type (math-preview--extract-match string)) "mathml"))
    (should-not (gethash 'inline (math-preview--extract-match string))))
  (let ((math-preview-tex-marks-inline '())
        (math-preview-tex-marks '())
        (math-preview-asciimath-marks-inline '(("$$" "$$" 0 nil nil)))
        (math-preview-asciimath-marks '(("$$" "$$" 0 nil nil)))
        (math-preview-mathml-marks-inline '(("$$" "$$" 0 nil nil)))
        (math-preview-mathml-marks '())
        (string "$$x^2$$"))
    (should (string-equal (gethash 'type (math-preview--extract-match string)) "mathml"))
    (should (gethash 'inline (math-preview--extract-match string))))
  (let ((math-preview-tex-marks-inline '())
        (math-preview-tex-marks '())
        (math-preview-asciimath-marks-inline '(("$$" "$$" 0 nil nil)))
        (math-preview-asciimath-marks '(("$$" "$$" 0 nil nil)))
        (math-preview-mathml-marks-inline '())
        (math-preview-mathml-marks '())
        (string "$$x^2$$"))
    (should (string-equal (gethash 'type (math-preview--extract-match string)) "asciimath"))
    (should-not (gethash 'inline (math-preview--extract-match string))))
  (let ((math-preview-tex-marks-inline '())
        (math-preview-tex-marks '())
        (math-preview-asciimath-marks-inline '(("$$" "$$" 0 nil nil)))
        (math-preview-asciimath-marks '())
        (math-preview-mathml-marks-inline '())
        (math-preview-mathml-marks '())
        (string "$$x^2$$"))
    (should (string-equal (gethash 'type (math-preview--extract-match string)) "asciimath"))
    (should (gethash 'inline (math-preview--extract-match string))))
  (let ((math-preview-tex-marks-inline '(("$$" "$$" 0 nil nil)))
        (math-preview-tex-marks '(("$$" "$$" 1 nil nil)))
        (math-preview-asciimath-marks-inline '(("$$" "$$" 5 nil nil)))
        (math-preview-asciimath-marks '(("$$" "$$" 4 nil nil)))
        (math-preview-mathml-marks-inline '(("$$" "$$" 2 nil nil)))
        (math-preview-mathml-marks '(("$$" "$$" 3 nil nil)))
        (string "$$x^2$$"))
    (should (= (gethash 'priority (math-preview--extract-match string)) 5))
    (should (string-equal (gethash 'type (math-preview--extract-match string)) "asciimath"))
    (should (gethash 'inline (math-preview--extract-match string))))
  (let ((math-preview-tex-marks-inline '(("$$" "$$" 0 nil nil)))
        (math-preview-tex-marks '(("$$" "$$" 1 nil nil)))
        (math-preview-asciimath-marks-inline '())
        (math-preview-asciimath-marks '(("$$" "$$" 4 nil nil)))
        (math-preview-mathml-marks-inline '(("$$" "$$" 2 nil nil)))
        (math-preview-mathml-marks '(("$$" "$$" 3 nil nil)))
        (string "$$x^2$$"))
    (should (= (gethash 'priority (math-preview--extract-match string)) 4))
    (should (string-equal (gethash 'type (math-preview--extract-match string)) "asciimath"))
    (should-not (gethash 'inline (math-preview--extract-match string))))
  (let ((math-preview-tex-marks-inline '(("$$" "$$" 0 nil nil)))
        (math-preview-tex-marks '(("$$" "$$" 1 nil nil)))
        (math-preview-asciimath-marks-inline '())
        (math-preview-asciimath-marks '())
        (math-preview-mathml-marks-inline '(("$$" "$$" 2 nil nil)))
        (math-preview-mathml-marks '(("$$" "$$" 3 nil nil)))
        (string "$$x^2$$"))
    (should (= (gethash 'priority (math-preview--extract-match string)) 3))
    (should (string-equal (gethash 'type (math-preview--extract-match string)) "mathml"))
    (should-not (gethash 'inline (math-preview--extract-match string))))
  (let ((math-preview-tex-marks-inline '(("$$" "$$" 0 nil nil)))
        (math-preview-tex-marks '(("$$" "$$" 1 nil nil)))
        (math-preview-asciimath-marks-inline '())
        (math-preview-asciimath-marks '())
        (math-preview-mathml-marks-inline '(("$$" "$$" 2 nil nil)))
        (math-preview-mathml-marks '())
        (string "$$x^2$$"))
    (should (= (gethash 'priority (math-preview--extract-match string)) 2))
    (should (string-equal (gethash 'type (math-preview--extract-match string)) "mathml"))
    (should (gethash 'inline (math-preview--extract-match string))))
  (let ((math-preview-tex-marks-inline '(("$$" "$$" 0 nil nil)))
        (math-preview-tex-marks '(("$$" "$$" 1 nil nil)))
        (math-preview-asciimath-marks-inline '())
        (math-preview-asciimath-marks '())
        (math-preview-mathml-marks-inline '())
        (math-preview-mathml-marks '())
        (string "$$x^2$$"))
    (should (= (gethash 'priority (math-preview--extract-match string)) 1))
    (should (string-equal (gethash 'type (math-preview--extract-match string)) "tex"))
    (should-not (gethash 'inline (math-preview--extract-match string))))
  (let ((math-preview-tex-marks-inline '(("$$" "$$" 0 nil nil)))
        (math-preview-tex-marks '())
        (math-preview-asciimath-marks-inline '())
        (math-preview-asciimath-marks '())
        (math-preview-mathml-marks-inline '())
        (math-preview-mathml-marks '())
        (string "$$x^2$$"))
    (should (= (gethash 'priority (math-preview--extract-match string)) 0))
    (should (string-equal (gethash 'type (math-preview--extract-match string)) "tex"))
    (should (gethash 'inline (math-preview--extract-match string)))))

(ert-deftest math-preview-test/math-preview--extract-match/regexp ()
  "Test `math-preview--extract-match' function regexp option."
  (let ((math-preview-tex-marks '(("$$$" "$$" 0 nil nil)))
        (string "$$$x^2$$"))
    (should-not (gethash 'lregexp (math-preview--extract-match string)))
    (should-not (gethash 'rregexp (math-preview--extract-match string)))
    (should (string-equal (gethash 'prefix (math-preview--extract-match string)) "$$$"))
    (should (string-equal (gethash 'suffix (math-preview--extract-match string)) "$$"))
    (should (string-equal (gethash 'string (math-preview--extract-match string)) "x^2")))
  (let ((math-preview-tex-marks '(("\\$\\{3\\}" "$$" 0 t nil)))
        (string "$$$x^2$$"))
    (should (gethash 'lregexp (math-preview--extract-match string)))
    (should-not (gethash 'rregexp (math-preview--extract-match string)))
    (should (string-equal (gethash 'lmark (math-preview--extract-match string)) "\\$\\{3\\}"))
    (should (string-equal (gethash 'prefix (math-preview--extract-match string)) "$$$"))
    (should (string-equal (gethash 'rmark (math-preview--extract-match string)) "$$"))
    (should (string-equal (gethash 'suffix (math-preview--extract-match string)) "$$"))
    (should (string-equal (gethash 'string (math-preview--extract-match string)) "x^2")))
  (let ((math-preview-tex-marks '(("$$" "\\$\\{3\\}" 0 nil t)))
        (string "$$x^2$$$"))
    (should-not (gethash 'lregexp (math-preview--extract-match string)))
    (should (gethash 'rregexp (math-preview--extract-match string)))
    (should (string-equal (gethash 'lmark (math-preview--extract-match string)) "$$"))
    (should (string-equal (gethash 'prefix (math-preview--extract-match string)) "$$"))
    (should (string-equal (gethash 'rmark (math-preview--extract-match string)) "\\$\\{3\\}"))
    (should (string-equal (gethash 'suffix (math-preview--extract-match string)) "$$$"))
    (should (string-equal (gethash 'string (math-preview--extract-match string)) "x^2")))
  (let ((math-preview-tex-marks '(("\\$\\{3\\}" "\\$\\{3\\}" 0 t t)))
        (string "$$$x^2$$$"))
    (should (gethash 'lregexp (math-preview--extract-match string)))
    (should (gethash 'rregexp (math-preview--extract-match string)))
    (should (string-equal (gethash 'lmark (math-preview--extract-match string)) "\\$\\{3\\}"))
    (should (string-equal (gethash 'prefix (math-preview--extract-match string)) "$$$"))
    (should (string-equal (gethash 'rmark (math-preview--extract-match string)) "\\$\\{3\\}"))
    (should (string-equal (gethash 'suffix (math-preview--extract-match string)) "$$$"))
    (should (string-equal (gethash 'string (math-preview--extract-match string)) "x^2")))
  (let ((math-preview-tex-marks '(("\\$\\{3\\}" "\\$\\{3\\}" 0 t t)))
        (math-preview-tex-marks-inline '(("\\$\\{4\\}" "\\$\\{4\\}" 0 t t)))
        (string "$$$x^2$$$"))
    (should (gethash 'lregexp (math-preview--extract-match string)))
    (should (gethash 'rregexp (math-preview--extract-match string)))
    (should (string-equal (gethash 'lmark (math-preview--extract-match string)) "\\$\\{3\\}"))
    (should (string-equal (gethash 'prefix (math-preview--extract-match string)) "$$$"))
    (should (string-equal (gethash 'rmark (math-preview--extract-match string)) "\\$\\{3\\}"))
    (should (string-equal (gethash 'suffix (math-preview--extract-match string)) "$$$"))
    (should (string-equal (gethash 'string (math-preview--extract-match string)) "x^2"))
    (should-not (gethash 'inline (math-preview--extract-match string))))
  (let ((math-preview-tex-marks '(("\\$\\{3\\}" "\\$\\{3\\}" 0 t t)))
        (math-preview-tex-marks-inline '(("\\$\\{4\\}" "\\$\\{4\\}" 0 t t)))
        (string "$$$$x^2$$$$"))
    (should (gethash 'lregexp (math-preview--extract-match string)))
    (should (gethash 'rregexp (math-preview--extract-match string)))
    (should (string-equal (gethash 'lmark (math-preview--extract-match string)) "\\$\\{3\\}"))
    (should (string-equal (gethash 'prefix (math-preview--extract-match string)) "$$$"))
    (should (string-equal (gethash 'rmark (math-preview--extract-match string)) "\\$\\{3\\}"))
    (should (string-equal (gethash 'suffix (math-preview--extract-match string)) "$$$"))
    (should (string-equal (gethash 'string (math-preview--extract-match string)) "$x^2$"))
    (should-not (gethash 'inline (math-preview--extract-match string))))
  (let ((math-preview-tex-marks '(("\\$\\{3\\}" "\\$\\{3\\}" 0 t t)))
        (math-preview-tex-marks-inline '(("\\$\\{4\\}" "\\$\\{4\\}" 1 t t)))
        (string "$$$$x^2$$$$"))
    (should (gethash 'lregexp (math-preview--extract-match string)))
    (should (gethash 'rregexp (math-preview--extract-match string)))
    (should (string-equal (gethash 'lmark (math-preview--extract-match string)) "\\$\\{4\\}"))
    (should (string-equal (gethash 'prefix (math-preview--extract-match string)) "$$$$"))
    (should (string-equal (gethash 'rmark (math-preview--extract-match string)) "\\$\\{4\\}"))
    (should (string-equal (gethash 'suffix (math-preview--extract-match string)) "$$$$"))
    (should (string-equal (gethash 'string (math-preview--extract-match string)) "x^2"))
    (should (gethash 'inline (math-preview--extract-match string))))
  (let ((math-preview-tex-marks '(("\\$\\{3\\}" "\\$\\{3\\}" 0 t t)))
        (math-preview-tex-marks-inline '(("\\$\\{4\\}" "\\$\\{4\\}" 1 t t)))
        (string "$$$x^2$$$"))
    (should (gethash 'lregexp (math-preview--extract-match string)))
    (should (gethash 'rregexp (math-preview--extract-match string)))
    (should (string-equal (gethash 'lmark (math-preview--extract-match string)) "\\$\\{3\\}"))
    (should (string-equal (gethash 'prefix (math-preview--extract-match string)) "$$$"))
    (should (string-equal (gethash 'rmark (math-preview--extract-match string)) "\\$\\{3\\}"))
    (should (string-equal (gethash 'suffix (math-preview--extract-match string)) "$$$"))
    (should (string-equal (gethash 'string (math-preview--extract-match string)) "x^2"))))

;;; math-preview-test.el ends here