1 ;;;; testcover-ses.el -- Example use of `testcover' to test "SES"
3 ;; Copyright (C) 2002-2011 Free Software Foundation, Inc.
5 ;; Author: Jonathan Yavner <jyavner@engineer.com>
6 ;; Maintainer: Jonathan Yavner <jyavner@engineer.com>
7 ;; Keywords: spreadsheet lisp utility
10 ;; GNU Emacs is free software: you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation, either version 3 of the License, or
13 ;; (at your option) any later version.
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
25 (defvar ses-initial-global-parameters)
28 (declare-function ses-set-curcell "ses")
29 (declare-function ses-update-cells "ses")
30 (declare-function ses-load "ses")
31 (declare-function ses-vector-delete "ses")
32 (declare-function ses-create-header-string "ses")
33 (declare-function ses-read-cell "ses")
34 (declare-function ses-read-symbol "ses")
35 (declare-function ses-command-hook "ses")
36 (declare-function ses-jump "ses")
39 ;;;Here are some macros that exercise SES. Set `pause' to t if you want the
40 ;;;macros to pause after each step.
42 (x (if pause "
\18q" ""))
43 (y "
\18\ 6ses-test.ses\r
\e<"))
44 ;;Fiddle with the existing spreadsheet
45 (fset 'ses-exercise-example
46 (concat "
\18\ 6" data-directory "ses-example.ses\r
\e<"
50 x "
\10\10\ 6pses-center\r"
61 x "(+
\18o
\ e\ e\ 6\0
\ 6\ 6"
62 x "
\15-1
\18o
\ 3\12 \ 3\13\r
\ 2"
65 ;;Create a new spreadsheet
66 (fset 'ses-exercise-new
84 (fset 'ses-exercise-display
85 (concat y "
\e:(revert-buffer t t)\r"
111 x "
\ 2\ 2\ 2\"1234567-1234567-1234567\r
\ 2"
114 x "
\ e\"1234567-1234567-1234567\r
\ 2"
117 x "
\ 2\ 2\"1234567\r"
121 (fset 'ses-exercise-formulas
122 (concat y "
\e:(revert-buffer t t)\r"
127 x "
\ e(apply '+ (ses-range B1 B3)\r
\ 2"
128 x "(apply 'ses+ (ses-range B1 B3)\r
\ 2"
129 x "
\ e(apply 'ses+ (ses-range A2 A3)\r
\ 2"
130 x "
\ e(mapconcat'number-to-string(ses-range B2 B4) \"-\"\r
\ 2"
131 x "
\ 2(apply 'concat (reverse (ses-range A3 D3))\r
\ 2"
132 x "
\ 2(* (+ A2 A3) (ses+ B2 B3)\r
\ 2"
136 x "
\10(apply 'ses+ (ses-range E1 E2)\r
\ 2"
137 x "
\10(apply 'ses+ (ses-range A5 B5)\r
\ 2"
138 x "
\10(apply 'ses+ (ses-range E1 F1)\r
\ 2"
139 x "
\10(apply 'ses+ (ses-range D1 E1)\r
\ 2"
141 x "(ses-average (ses-range A2 A5)\r
\ 2"
142 x "
\ e(apply 'ses+ (ses-range A5 A6)\r
\ 2"
151 x "
\ 6(ses-average (ses-range B3 E3)\r
\ 2"
153 x "
\ e\1012345678\r
\ 2"
155 ;;Recalculating and reconstructing
156 (fset 'ses-exercise-recalc
157 (concat y "
\e:(revert-buffer t t)\r"
167 x "
\e>
\18nw
\ 6\ 6\ 6"
168 x "\0
\e>
\exdelete-region\r"
171 x "\0
\e>
\exdelete-region\r"
182 x "
\ 2\ 2\"Very long2\r"
186 x "
\ e\r
\7f\7f\7fC2\r"
187 x "
\10\0
\ e\ 6\ 3\ 3"
189 x "
\ e\ e\r
\7f\7f\7fC2\r"
197 (fset 'ses-exercise-header-row
198 (concat y "
\e:(revert-buffer t t)\r"
213 ;;Detecting unsafe formulas and printers
214 (fset 'ses-exercise-unsafe
215 (concat y "
\e:(revert-buffer t t)\r"
216 x "p(lambda (x) (delete-file x))\rn"
217 x "p(lambda (x) (delete-file \"ses-nothing\"))\ry"
219 x "
\ e(delete-file \"x\"\rn"
220 x "(delete-file \"ses-nothing\"\ry
\ 2"
222 x "(open-network-stream \"x\" nil \"localhost\" \"smtp\"\ry
\ 2"
225 ;;Inserting and deleting rows
226 (fset 'ses-exercise-rows
227 (concat y "
\e:(revert-buffer t t)\r"
237 x "
\10\10(not B25\r
\ 2"
242 x "
\15100
\ f" ;Make this approx your CPU speed in MHz
244 ;;Inserting and deleting columns
245 (fset 'ses-exercise-columns
246 (concat y "
\e:(revert-buffer t t)\r"
267 x "\0
\ e\ e\ 6\ 6\ 3\e\13D"
269 (fset 'ses-exercise-editing
270 (concat y "
\e:(revert-buffer t t)\r"
272 x "
\ 6(
\ 2'
\ 6x\r
\ 2"
287 x "
\ 2\"Very long\r
\ 2"
300 x "\"Also very long\r
\ 2"
304 x "
\ e\ 2'qwerty\r
\ 2"
305 x "
\ 6(concat
\18o
\e<\0
\ e\ e"
306 x "
\15-1
\18o
\ 3\12\r
\ 2"
307 x "(apply '+
\18o
\e<\0
\ e\ 6\15-1
\18o
\ 3\13\r
\ 2"
315 x "\"Another long one\r
\ 2"
324 (fset 'ses-exercise-sort-column
325 (concat y "
\e:(revert-buffer t t)\r"
331 x "\0
\10\10\10\ 3\e\13A\r"
332 x "
\ e\0
\10\10\10\ 3\e\13B\r"
333 x "
\10\10\ 6\0
\ e\ e\ 6\ 6\ 3\e\13C\r"
335 x "
\ 2\0
\ e\ e\ e\15\ 3\e\13C\r"
337 ;;Simple cell printers
338 (fset 'ses-exercise-cell-printers
339 (concat y "
\e:(revert-buffer t t)\r"
340 x "
\ 6\"4
\11\t76\r
\ 2"
354 x "
\ 2\0
\ 6\ 6pnil\r"
362 x "
\ 3\10\"%.6g#\"\r"
363 x "
\ 3\10\"%.6g.\"\r"
364 x "
\ 3\10\"%.6g.\"\r"
370 x "p(lambda
\11 (x)
\11 '(\"Hi\"))\r"
371 x "p(lambda
\11 (x)
\11 '(\"Bye\"))\r"
373 ;;Spanning cell printers
374 (fset 'ses-exercise-spanning-printers
375 (concat y "
\e:(revert-buffer t t)\r"
377 x "pses-dashfill-span\r"
379 x "pses-tildefill-span\r"
385 x "\t\"12345678\r
\ 2"
386 x "pses-dashfill-span\r"
401 ;;Cut/copy/paste - within same buffer
402 (fset 'ses-exercise-paste-1buf
403 (concat y "
\e:(revert-buffer t t)\r"
422 x "
\ 6pses-dashfill\r"
423 x "
\ 2\0
\ 6\ 6\ 6\ e\ e\ e"
429 x "
\153
\10(+ G2 H1\r"
433 x "
\ 2\158
\10(ses-average (ses-range G2 H2)\r
\ 2"
437 x "
\10\ 2(ses-average (ses-range E7 E9)\r
\ 2"
440 x "
\ 2\ 2\10(ses-average (ses-range E7 F7)\r
\ 2"
443 x "
\ 2\ 2\10(ses-average (ses-range D6 E6)\r
\ 2"
448 x "pses-tildefill-span\r"
449 x "
\ e\ 6\"Subline A(1)\r
\ 2"
450 x "pses-dashfill-span\r"
451 x "
\ 2\10\0
\ e\ e\ e\ew
\ 3\ 3"
452 x "
\ 1\10\10\10\10\10\10"
454 x "\0
\ e\ 6\ 6\ew
\ 3\ 3"
457 ;;Cut/copy/paste - between two buffers
458 (fset 'ses-exercise-paste-2buf
459 (concat y "
\e:(revert-buffer t t)\r"
460 x "
\ 6\ e\eo\"middle\r
\ 2\0
\ 6\ e\ 6"
462 x "
\184bses-test.txt\r"
464 x "
\ 5\"xxx\0
\ 2\ 2\ 2\ 2"
468 x "
\18o
\ 5\"\0
\ 2\ 2\ 2\ 2\ 2"
470 x "
\18o123.45\0
\ 2\ 2\ 2\ 2\ 2\ 2"
472 x "
\18o1
\ 2\ 2\0
\ 6\ 6\ 6\ 6\ 6\ 6\ 6"
475 x "
\ 6\18o symb\0
\ 2\ 2\ 2\ 2"
476 x "
\17\18o
\15\19\ey
\152
\ey"
479 x "w9\n
\ep\"<%s>\"\n"
480 x "
\18o\n2\t\"3\nxxx\t5\n\0
\10\10"
483 ;;Export text, import it back
484 (fset 'ses-exercise-import-export
485 (concat y "
\e:(revert-buffer t t)\r"
487 x "
\184bses-test.txt\r"
489 x "xT
\18o
\19\15-1
\18o"
490 x "
\ 3\ 3\ 6'crunch\r
\ 2"
491 x "
\10\10\10pses-center-span\r"
493 x "
\18o\n
\19\15-1
\18o"
502 (defun ses-exercise-macros ()
503 "Executes all SES coverage-test macros."
504 (dolist (x '(ses-exercise-example
507 ses-exercise-formulas
509 ses-exercise-header-row
514 ses-exercise-sort-column
515 ses-exercise-cell-printers
516 ses-exercise-spanning-printers
517 ses-exercise-paste-1buf
518 ses-exercise-paste-2buf
519 ses-exercise-import-export))
520 (message "<Testing %s>" x)
521 (execute-kbd-macro x)))
523 (defun ses-exercise-signals ()
524 "Exercise code paths that lead to error signals, other than those for
525 spreadsheet files with invalid formatting."
526 (message "<Checking for expected errors>")
527 (switch-to-buffer "ses-test.ses")
531 (dolist (x '((ses-column-widths 14)
532 (ses-column-printers "%s")
533 (ses-column-printers ["%s" "%s" "%s"]) ;Should be two
534 (ses-column-widths [14])
535 (ses-delete-column -99)
536 (ses-delete-column 2)
538 (ses-goto-data 'hogwash)
541 (ses-insert-column -14)
543 (ses-jump 'B8) ;Covered by preceding cell
544 (ses-printer-validate '("%s" t))
545 (ses-printer-validate '([47]))
546 (ses-read-header-row -1)
547 (ses-read-header-row 32767)
548 (ses-relocate-all 0 0 -1 1)
549 (ses-relocate-all 0 0 1 -1)
550 (ses-select (ses-range A1 A2) 'x (ses-range B1 B1))
551 (ses-set-cell 0 0 'hogwash nil)
552 (ses-set-column-width 0 0)
553 (ses-yank-cells #("a\nb"
554 0 1 (ses (A1 nil nil))
555 2 3 (ses (A3 nil nil)))
557 (ses-yank-cells #("ab"
558 0 1 (ses (A1 nil nil))
559 1 2 (ses (A2 nil nil)))
562 (ses-yank-tsf "1\t2\n3" nil)
563 (let ((curcell nil)) (ses-check-curcell))
564 (let ((curcell 'A1)) (ses-check-curcell 'needrange))
565 (let ((curcell '(A1 . A2))) (ses-check-curcell 'end))
566 (let ((curcell '(A1 . A2))) (ses-sort-column "B"))
567 (let ((curcell '(C1 . D2))) (ses-sort-column "B"))
568 (execute-kbd-macro "jB10\n
\152
\ 4")
569 (execute-kbd-macro [?j ?B ?9 ?\n ?\C-@ ?\C-f ?\C-f cut])
570 (progn (kill-new "x") (execute-kbd-macro "
\e>
\19n"))
571 (execute-kbd-macro "
\ 2\0
\ew")))
575 (signal 'singularity-error nil)) ;Shouldn't get here
576 (singularity-error (error "No error from %s?" x))
578 ;;Test quit-handling in ses-update-cells. Cant' use `eval' here.
579 (let ((inhibit-quit t))
583 (ses-update-cells '(A1))
584 (signal 'singularity-error nil))
585 (singularity-error (error "Quit failure in ses-update-cells"))
587 (setq quit-flag nil)))
589 (defun ses-exercise-invalid-spreadsheets ()
590 "Execute code paths that detect invalid spreadsheet files."
591 ;;Detect invalid spreadsheets
592 (let ((p&d "\n\n
\f\n(ses-cell A1 nil nil nil nil)\n\n")
593 (cw "(ses-column-widths [7])\n")
594 (cp "(ses-column-printers [ses-center])\n")
595 (dp "(ses-default-printer \"%.7g\")\n")
596 (hr "(ses-header-row 0)\n")
598 (igp ses-initial-global-parameters))
599 (dolist (x (list "(1)"
607 "\n\n
\f\n(ses-cell)(2 1 1)"
608 "\n\n
\f\n(x)\n(2 1 1)"
609 "\n\n\n
\f\n(ses-cell A2)\n(2 2 2)"
610 "\n\n\n
\f\n(ses-cell B1)\n(2 2 2)"
611 "\n\n
\f\n(ses-cell A1 nil nil nil nil)\n(2 1 1)"
612 (concat p&d "(x)\n(x)\n(x)\n(x)\n" p11)
613 (concat p&d "(ses-column-widths)(x)\n(x)\n(x)\n" p11)
614 (concat p&d cw "(x)\n(x)\n(x)\n(2 1 1)")
615 (concat p&d cw "(ses-column-printers)(x)\n(x)\n" p11)
616 (concat p&d cw cp "(x)\n(x)\n" p11)
617 (concat p&d cw cp "(ses-default-printer)(x)\n" p11)
618 (concat p&d cw cp dp "(x)\n" p11)
619 (concat p&d cw cp dp "(ses-header-row)" p11)
620 (concat p&d cw cp dp hr p11)
621 (concat p&d cw cp dp "\n" hr igp)))
626 (signal 'singularity-error nil)) ;Shouldn't get here
627 (singularity-error (error "%S is an invalid spreadsheet!" x))
630 (defun ses-exercise-startup ()
631 "Prepare for coverage tests"
632 ;;Clean up from any previous runs
633 (condition-case nil (kill-buffer "ses-example.ses") (error nil))
634 (condition-case nil (kill-buffer "ses-test.ses") (error nil))
635 (condition-case nil (delete-file "ses-test.ses") (file-error nil))
636 (delete-other-windows) ;Needed for "\C-xo" in ses-exercise-editing
637 (setq ses-mode-map nil) ;Force rebuild
638 (testcover-unmark-all "ses.el")
640 (let ((testcover-1value-functions
641 ;;forward-line always returns 0, for us.
642 ;;remove-text-properties always returns t for us.
643 ;;ses-recalculate-cell returns the same " " any time curcell is a cons
644 ;;Macros ses-dorange and ses-dotimes-msg generate code that always
646 (append '(forward-line remove-text-properties ses-recalculate-cell
647 ses-dorange ses-dotimes-msg)
648 testcover-1value-functions))
650 ;;These maps get initialized, then never changed again
651 (append '(ses-mode-map ses-mode-print-map ses-mode-edit-map)
652 testcover-constants)))
653 (testcover-start "ses.el" t))
654 (require 'unsafep)) ;In case user has safe-functions = t!
657 ;;;#########################################################################
658 (defun ses-exercise ()
659 "Executes all SES coverage tests and displays the results."
661 (ses-exercise-startup)
662 ;;Run the keyboard-macro tests
663 (let ((safe-functions nil)
664 (ses-initial-size '(1 . 1))
665 (ses-initial-column-width 7)
666 (ses-initial-default-printer "%.7g")
667 (ses-after-entry-functions '(forward-char))
669 (ses-exercise-macros)
670 (ses-exercise-signals)
671 (ses-exercise-invalid-spreadsheets)
672 ;;Upgrade of old-style spreadsheet
674 (insert " \n\n
\f\n(ses-cell A1 nil nil nil nil)\n\n(ses-column-widths [7])\n(ses-column-printers [nil])\n(ses-default-printer \"%.7g\")\n\n( ;Global parameters (these are read first)\n 1 ;SES file-format\n 1 ;numrows\n 1 ;numcols\n)\n\n")
676 ;;ses-vector-delete is always called from buffer-undo-list with the same
677 ;;symbol as argument. We'll give it a different one here.
679 (ses-vector-delete 'x 0 0))
680 ;;ses-create-header-string behaves differently in a non-window environment
681 ;;but we always test under windows.
682 (let ((window-system (not window-system)))
684 (ses-create-header-string))
685 ;;Test for nonstandard after-entry functions
686 (let ((ses-after-entry-functions '(forward-line))
688 (ses-read-cell 0 0 1)
689 (ses-read-symbol 0 0 t)))
690 ;;Tests with unsafep disabled
691 (let ((safe-functions t)
693 (message "<Checking safe-functions = t>")
694 (kill-buffer "ses-example.ses")
695 (find-file "ses-example.ses"))
696 ;;Checks for nonstandard default values for new spreadsheets
698 (dolist (x '(("%.6g" 8 (2 . 2))
700 (let ((ses-initial-size (nth 2 x))
701 (ses-initial-column-width (nth 1 x))
702 (ses-initial-default-printer (nth 0 x)))
704 (set-buffer-modified-p t)
706 ;;Test error-handling in command hook, outside a macro.
707 ;;This will ring the bell.
708 (let (curcell-overlay)
710 ;;Due to use of run-with-timer, ses-command-hook sometimes gets called
711 ;;after we switch to another buffer.
712 (switch-to-buffer "*scratch*")
715 (message "<Marking source code>")
716 (testcover-mark-all "ses.el")
717 (testcover-next-mark)
719 (delete-other-windows)
720 (kill-buffer "ses-test.txt")
721 ;;Could do this here: (testcover-end "ses.el")
724 ;; testcover-ses.el ends here.