1;;;; testcover-ses.el -- Example use of `testcover' to test "SES" 2 3;; Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. 4 5;; Author: Jonathan Yavner <jyavner@engineer.com> 6;; Maintainer: Jonathan Yavner <jyavner@engineer.com> 7;; Keywords: spreadsheet lisp utility 8 9;; GNU Emacs is free software; you can redistribute it and/or modify 10;; it under the terms of the GNU General Public License as published by 11;; the Free Software Foundation; either version 2, or (at your option) 12;; any later version. 13 14;; GNU Emacs is distributed in the hope that it will be useful, 15;; but WITHOUT ANY WARRANTY; without even the implied warranty of 16;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17;; GNU General Public License for more details. 18 19;; You should have received a copy of the GNU General Public License 20;; along with GNU Emacs; see the file COPYING. If not, write to the 21;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 22;; Boston, MA 02110-1301, USA. 23 24(require 'testcover) 25 26(defvar ses-initial-global-parameters) 27(defvar ses-mode-map) 28 29;;;Here are some macros that exercise SES. Set `pause' to t if you want the 30;;;macros to pause after each step. 31(let* ((pause nil) 32 (x (if pause "q" "")) 33 (y "ses-test.ses\r<")) 34 ;;Fiddle with the existing spreadsheet 35 (fset 'ses-exercise-example 36 (concat "" data-directory "ses-example.ses\r<" 37 x "10" 38 x "" 39 x "" 40 x "pses-center\r" 41 x "p\r" 42 x "\t\t" 43 x "\r A9 B9\r" 44 x "" 45 x "\r2\r" 46 x "" 47 x "50\r" 48 x "4" 49 x "" 50 x "" 51 x "(+ o\0" 52 x "-1o \r" 53 x "" 54 x)) 55 ;;Create a new spreadsheet 56 (fset 'ses-exercise-new 57 (concat y 58 x "\"%.8g\"\r" 59 x "2\r" 60 x "" 61 x "" 62 x "2" 63 x "\"Header\r" 64 x "(sqrt 1\r" 65 x "pses-center\r" 66 x "\t" 67 x "(+ A2 A3\r" 68 x "(* B2 A3\r" 69 x "2" 70 x "\rB3\r" 71 x "" 72 x)) 73 ;;Basic cell display 74 (fset 'ses-exercise-display 75 (concat y ":(revert-buffer t t)\r" 76 x "" 77 x "\"Very long\r" 78 x "w3\r" 79 x "w3\r" 80 x "(/ 1 0\r" 81 x "234567\r" 82 x "5w" 83 x "\t1\r" 84 x "" 85 x "234567\r" 86 x "\t" 87 x "" 88 x "345678\r" 89 x "3w" 90 x "\0>" 91 x "" 92 x "" 93 x "" 94 x "" 95 x "" 96 x "" 97 x "" 98 x "1\r" 99 x "" 100 x "" 101 x "\"1234567-1234567-1234567\r" 102 x "123\r" 103 x "2" 104 x "\"1234567-1234567-1234567\r" 105 x "123\r" 106 x "w8\r" 107 x "\"1234567\r" 108 x "w5\r" 109 x)) 110 ;;Cell formulas 111 (fset 'ses-exercise-formulas 112 (concat y ":(revert-buffer t t)\r" 113 x "\t\t" 114 x "\t" 115 x "(* B1 B2 D1\r" 116 x "(* B2 B3\r" 117 x "(apply '+ (ses-range B1 B3)\r" 118 x "(apply 'ses+ (ses-range B1 B3)\r" 119 x "(apply 'ses+ (ses-range A2 A3)\r" 120 x "(mapconcat'number-to-string(ses-range B2 B4) \"-\"\r" 121 x "(apply 'concat (reverse (ses-range A3 D3))\r" 122 x "(* (+ A2 A3) (ses+ B2 B3)\r" 123 x "" 124 x "2" 125 x "5\t" 126 x "(apply 'ses+ (ses-range E1 E2)\r" 127 x "(apply 'ses+ (ses-range A5 B5)\r" 128 x "(apply 'ses+ (ses-range E1 F1)\r" 129 x "(apply 'ses+ (ses-range D1 E1)\r" 130 x "\t" 131 x "(ses-average (ses-range A2 A5)\r" 132 x "(apply 'ses+ (ses-range A5 A6)\r" 133 x "k" 134 x "" 135 x "" 136 x "2" 137 x "3" 138 x "o" 139 x "2o" 140 x "3k" 141 x "(ses-average (ses-range B3 E3)\r" 142 x "k" 143 x "12345678\r" 144 x)) 145 ;;Recalculating and reconstructing 146 (fset 'ses-exercise-recalc 147 (concat y ":(revert-buffer t t)\r" 148 x "" 149 x "\t\t" 150 x "" 151 x "(/ 1 0\r" 152 x "" 153 x "\n" 154 x "" 155 x "\"%.6g\"\r" 156 x "" 157 x ">nw" 158 x "\0>xdelete-region\r" 159 x "" 160 x "8" 161 x "\0>xdelete-region\r" 162 x "" 163 x "" 164 x "k" 165 x "" 166 x "\"Very long\r" 167 x "" 168 x "\r\r" 169 x "" 170 x "o" 171 x "" 172 x "\"Very long2\r" 173 x "o" 174 x "" 175 x "\rC3\r" 176 x "\rC2\r" 177 x "\0" 178 x "\rC4\r" 179 x "\rC2\r" 180 x "\0" 181 x "" 182 x "xses-mode\r" 183 x "<" 184 x "2k" 185 x)) 186 ;;Header line 187 (fset 'ses-exercise-header-row 188 (concat y ":(revert-buffer t t)\r" 189 x "<" 190 x ">" 191 x "6<" 192 x ">" 193 x "7<" 194 x ">" 195 x "8<" 196 x "2<" 197 x ">" 198 x "3w" 199 x "10<" 200 x ">" 201 x "2" 202 x)) 203 ;;Detecting unsafe formulas and printers 204 (fset 'ses-exercise-unsafe 205 (concat y ":(revert-buffer t t)\r" 206 x "p(lambda (x) (delete-file x))\rn" 207 x "p(lambda (x) (delete-file \"ses-nothing\"))\ry" 208 x "\0n" 209 x "(delete-file \"x\"\rn" 210 x "(delete-file \"ses-nothing\"\ry" 211 x "\0n" 212 x "(open-network-stream \"x\" nil \"localhost\" \"smtp\"\ry" 213 x "\0n" 214 x)) 215 ;;Inserting and deleting rows 216 (fset 'ses-exercise-rows 217 (concat y ":(revert-buffer t t)\r" 218 x "" 219 x "\"%s=\"\r" 220 x "20" 221 x "p\"%s+\"\r" 222 x "" 223 x "123456789\r" 224 x "\021" 225 x "" 226 x "" 227 x "(not B25\r" 228 x "k" 229 x "jA3\r" 230 x "19" 231 x "" 232 x "100" ;Make this approx your CPU speed in MHz 233 x)) 234 ;;Inserting and deleting columns 235 (fset 'ses-exercise-columns 236 (concat y ":(revert-buffer t t)\r" 237 x "\"%s@\"\r" 238 x "o" 239 x "" 240 x "o" 241 x "" 242 x "k" 243 x "w8\r" 244 x "p\"%.7s*\"\r" 245 x "o" 246 x "" 247 x "2o" 248 x "3k" 249 x "\"%.6g\"\r" 250 x "26o" 251 x "\026\t" 252 x "26o" 253 x "0\r" 254 x "26\t" 255 x "400" 256 x "50k" 257 x "\0D" 258 x)) 259 (fset 'ses-exercise-editing 260 (concat y ":(revert-buffer t t)\r" 261 x "1\r" 262 x "('x\r" 263 x "" 264 x "" 265 x "\r\r" 266 x "w9\r" 267 x "\r.5\r" 268 x "\r 10\r" 269 x "w12\r" 270 x "\r'\r" 271 x "\r\r" 272 x "jA4\r" 273 x "(+ A2 100\r" 274 x "3\r" 275 x "jB1\r" 276 x "(not A1\r" 277 x "\"Very long\r" 278 x "" 279 x "h" 280 x "H" 281 x "" 282 x ">\t" 283 x "" 284 x "" 285 x "2" 286 x "" 287 x "o" 288 x "h" 289 x "\0" 290 x "\"Also very long\r" 291 x "H" 292 x "\0'\r" 293 x "'Trial\r" 294 x "'qwerty\r" 295 x "(concat o<\0" 296 x "-1o\r" 297 x "(apply '+ o<\0-1o\r" 298 x "2" 299 x "-2" 300 x "-2" 301 x "2" 302 x "" 303 x "H" 304 x "\0" 305 x "\"Another long one\r" 306 x "H" 307 x "" 308 x "<" 309 x "" 310 x ">" 311 x "\0" 312 x)) 313 ;;Sorting of columns 314 (fset 'ses-exercise-sort-column 315 (concat y ":(revert-buffer t t)\r" 316 x "\"Very long\r" 317 x "99\r" 318 x "o13\r" 319 x "(+ A3 B3\r" 320 x "7\r8\r(* A4 B4\r" 321 x "\0A\r" 322 x "\0B\r" 323 x "\0C\r" 324 x "o" 325 x "\0C\r" 326 x)) 327 ;;Simple cell printers 328 (fset 'ses-exercise-cell-printers 329 (concat y ":(revert-buffer t t)\r" 330 x "\"4\t76\r" 331 x "\"4\n7\r" 332 x "p\"{%S}\"\r" 333 x "p(\"[%s]\")\r" 334 x "p(\"<%s>\")\r" 335 x "\0" 336 x "p\r" 337 x "pnil\r" 338 x "pses-dashfill\r" 339 x "48\r" 340 x "\t" 341 x "\0p\r" 342 x "p\r" 343 x "pses-dashfill\r" 344 x "\0pnil\r" 345 x "5\r" 346 x "pses-center\r" 347 x "\"%s\"\r" 348 x "w8\r" 349 x "p\r" 350 x "p\"%.7g@\"\r" 351 x "\r" 352 x "\"%.6g#\"\r" 353 x "\"%.6g.\"\r" 354 x "\"%.6g.\"\r" 355 x "pidentity\r" 356 x "6\r" 357 x "\"UPCASE\r" 358 x "pdowncase\r" 359 x "(* 3 4\r" 360 x "p(lambda (x) '(\"Hi\"))\r" 361 x "p(lambda (x) '(\"Bye\"))\r" 362 x)) 363 ;;Spanning cell printers 364 (fset 'ses-exercise-spanning-printers 365 (concat y ":(revert-buffer t t)\r" 366 x "p\"%.6g*\"\r" 367 x "pses-dashfill-span\r" 368 x "5\r" 369 x "pses-tildefill-span\r" 370 x "\"4\r" 371 x "p\"$%s\"\r" 372 x "p(\"$%s\")\r" 373 x "8\r" 374 x "p(\"!%s!\")\r" 375 x "\t\"12345678\r" 376 x "pses-dashfill-span\r" 377 x "\"23456789\r" 378 x "\t" 379 x "(not t\r" 380 x "w6\r" 381 x "\"5\r" 382 x "o" 383 x "k" 384 x "k" 385 x "\t" 386 x "" 387 x "o" 388 x "2k" 389 x "k" 390 x)) 391 ;;Cut/copy/paste - within same buffer 392 (fset 'ses-exercise-paste-1buf 393 (concat y ":(revert-buffer t t)\r" 394 x "\0w" 395 x "" 396 x "o" 397 x "\"middle\r" 398 x "\0" 399 x "w" 400 x "\0" 401 x "w" 402 x "" 403 x "" 404 x "2y" 405 x "y" 406 x "y" 407 x ">" 408 x "y" 409 x ">y" 410 x "<" 411 x "p\"<%s>\"\r" 412 x "pses-dashfill\r" 413 x "\0" 414 x "" 415 x "" 416 x "y" 417 x "\r\0w" 418 x "\r" 419 x "3(+ G2 H1\r" 420 x "\0w" 421 x ">" 422 x "" 423 x "8(ses-average (ses-range G2 H2)\r" 424 x "\0k" 425 x "7" 426 x "" 427 x "(ses-average (ses-range E7 E9)\r" 428 x "\0" 429 x "" 430 x "(ses-average (ses-range E7 F7)\r" 431 x "\0k" 432 x "" 433 x "(ses-average (ses-range D6 E6)\r" 434 x "\0k" 435 x "" 436 x "2" 437 x "\"Line A\r" 438 x "pses-tildefill-span\r" 439 x "\"Subline A(1)\r" 440 x "pses-dashfill-span\r" 441 x "\0w" 442 x "" 443 x "" 444 x "\0w" 445 x "" 446 x)) 447 ;;Cut/copy/paste - between two buffers 448 (fset 'ses-exercise-paste-2buf 449 (concat y ":(revert-buffer t t)\r" 450 x "o\"middle\r\0" 451 x "" 452 x "4bses-test.txt\r" 453 x " " 454 x "\"xxx\0" 455 x "wo" 456 x "" 457 x "" 458 x "o\"\0" 459 x "wo" 460 x "o123.45\0" 461 x "o" 462 x "o1 \0" 463 x "o" 464 x ">y" 465 x "o symb\0" 466 x "oy2y" 467 x "o1\t\0" 468 x "o" 469 x "w9\np\"<%s>\"\n" 470 x "o\n2\t\"3\nxxx\t5\n\0" 471 x "oy" 472 x)) 473 ;;Export text, import it back 474 (fset 'ses-exercise-import-export 475 (concat y ":(revert-buffer t t)\r" 476 x "\0xt" 477 x "4bses-test.txt\r" 478 x "\n-1o" 479 x "xTo-1o" 480 x "'crunch\r" 481 x "pses-center-span\r" 482 x "\0xT" 483 x "o\n-1o" 484 x "\0y" 485 x "\0xt" 486 x "\0y" 487 x "12345678\r" 488 x "'bunch\r" 489 x "\0xtxT" 490 x))) 491 492(defun ses-exercise-macros () 493 "Executes all SES coverage-test macros." 494 (dolist (x '(ses-exercise-example 495 ses-exercise-new 496 ses-exercise-display 497 ses-exercise-formulas 498 ses-exercise-recalc 499 ses-exercise-header-row 500 ses-exercise-unsafe 501 ses-exercise-rows 502 ses-exercise-columns 503 ses-exercise-editing 504 ses-exercise-sort-column 505 ses-exercise-cell-printers 506 ses-exercise-spanning-printers 507 ses-exercise-paste-1buf 508 ses-exercise-paste-2buf 509 ses-exercise-import-export)) 510 (message "<Testing %s>" x) 511 (execute-kbd-macro x))) 512 513(defun ses-exercise-signals () 514 "Exercise code paths that lead to error signals, other than those for 515spreadsheet files with invalid formatting." 516 (message "<Checking for expected errors>") 517 (switch-to-buffer "ses-test.ses") 518 (deactivate-mark) 519 (ses-jump 'A1) 520 (ses-set-curcell) 521 (dolist (x '((ses-column-widths 14) 522 (ses-column-printers "%s") 523 (ses-column-printers ["%s" "%s" "%s"]) ;Should be two 524 (ses-column-widths [14]) 525 (ses-delete-column -99) 526 (ses-delete-column 2) 527 (ses-delete-row -1) 528 (ses-goto-data 'hogwash) 529 (ses-header-row -56) 530 (ses-header-row 99) 531 (ses-insert-column -14) 532 (ses-insert-row 0) 533 (ses-jump 'B8) ;Covered by preceding cell 534 (ses-printer-validate '("%s" t)) 535 (ses-printer-validate '([47])) 536 (ses-read-header-row -1) 537 (ses-read-header-row 32767) 538 (ses-relocate-all 0 0 -1 1) 539 (ses-relocate-all 0 0 1 -1) 540 (ses-select (ses-range A1 A2) 'x (ses-range B1 B1)) 541 (ses-set-cell 0 0 'hogwash nil) 542 (ses-set-column-width 0 0) 543 (ses-yank-cells #("a\nb" 544 0 1 (ses (A1 nil nil)) 545 2 3 (ses (A3 nil nil))) 546 nil) 547 (ses-yank-cells #("ab" 548 0 1 (ses (A1 nil nil)) 549 1 2 (ses (A2 nil nil))) 550 nil) 551 (ses-yank-pop nil) 552 (ses-yank-tsf "1\t2\n3" nil) 553 (let ((curcell nil)) (ses-check-curcell)) 554 (let ((curcell 'A1)) (ses-check-curcell 'needrange)) 555 (let ((curcell '(A1 . A2))) (ses-check-curcell 'end)) 556 (let ((curcell '(A1 . A2))) (ses-sort-column "B")) 557 (let ((curcell '(C1 . D2))) (ses-sort-column "B")) 558 (execute-kbd-macro "jB10\n2") 559 (execute-kbd-macro [?j ?B ?9 ?\n ?\C-@ ?\C-f ?\C-f cut]) 560 (progn (kill-new "x") (execute-kbd-macro ">n")) 561 (execute-kbd-macro "\0w"))) 562 (condition-case nil 563 (progn 564 (eval x) 565 (signal 'singularity-error nil)) ;Shouldn't get here 566 (singularity-error (error "No error from %s?" x)) 567 (error nil))) 568 ;;Test quit-handling in ses-update-cells. Cant' use `eval' here. 569 (let ((inhibit-quit t)) 570 (setq quit-flag t) 571 (condition-case nil 572 (progn 573 (ses-update-cells '(A1)) 574 (signal 'singularity-error nil)) 575 (singularity-error (error "Quit failure in ses-update-cells")) 576 (error nil)) 577 (setq quit-flag nil))) 578 579(defun ses-exercise-invalid-spreadsheets () 580 "Execute code paths that detect invalid spreadsheet files." 581 ;;Detect invalid spreadsheets 582 (let ((p&d "\n\n\n(ses-cell A1 nil nil nil nil)\n\n") 583 (cw "(ses-column-widths [7])\n") 584 (cp "(ses-column-printers [ses-center])\n") 585 (dp "(ses-default-printer \"%.7g\")\n") 586 (hr "(ses-header-row 0)\n") 587 (p11 "(2 1 1)") 588 (igp ses-initial-global-parameters)) 589 (dolist (x (list "(1)" 590 "(x 2 3)" 591 "(1 x 3)" 592 "(1 -1 0)" 593 "(1 2 x)" 594 "(1 2 -1)" 595 "(3 1 1)" 596 "\n\n(2 1 1)" 597 "\n\n\n(ses-cell)(2 1 1)" 598 "\n\n\n(x)\n(2 1 1)" 599 "\n\n\n\n(ses-cell A2)\n(2 2 2)" 600 "\n\n\n\n(ses-cell B1)\n(2 2 2)" 601 "\n\n\n(ses-cell A1 nil nil nil nil)\n(2 1 1)" 602 (concat p&d "(x)\n(x)\n(x)\n(x)\n" p11) 603 (concat p&d "(ses-column-widths)(x)\n(x)\n(x)\n" p11) 604 (concat p&d cw "(x)\n(x)\n(x)\n(2 1 1)") 605 (concat p&d cw "(ses-column-printers)(x)\n(x)\n" p11) 606 (concat p&d cw cp "(x)\n(x)\n" p11) 607 (concat p&d cw cp "(ses-default-printer)(x)\n" p11) 608 (concat p&d cw cp dp "(x)\n" p11) 609 (concat p&d cw cp dp "(ses-header-row)" p11) 610 (concat p&d cw cp dp hr p11) 611 (concat p&d cw cp dp "\n" hr igp))) 612 (condition-case nil 613 (with-temp-buffer 614 (insert x) 615 (ses-load) 616 (signal 'singularity-error nil)) ;Shouldn't get here 617 (singularity-error (error "%S is an invalid spreadsheet!" x)) 618 (error nil))))) 619 620(defun ses-exercise-startup () 621 "Prepare for coverage tests" 622 ;;Clean up from any previous runs 623 (condition-case nil (kill-buffer "ses-example.ses") (error nil)) 624 (condition-case nil (kill-buffer "ses-test.ses") (error nil)) 625 (condition-case nil (delete-file "ses-test.ses") (file-error nil)) 626 (delete-other-windows) ;Needed for "\C-xo" in ses-exercise-editing 627 (setq ses-mode-map nil) ;Force rebuild 628 (testcover-unmark-all "ses.el") 629 ;;Enable 630 (let ((testcover-1value-functions 631 ;;forward-line always returns 0, for us. 632 ;;remove-text-properties always returns t for us. 633 ;;ses-recalculate-cell returns the same " " any time curcell is a cons 634 ;;Macros ses-dorange and ses-dotimes-msg generate code that always 635 ;; returns nil 636 (append '(forward-line remove-text-properties ses-recalculate-cell 637 ses-dorange ses-dotimes-msg) 638 testcover-1value-functions)) 639 (testcover-constants 640 ;;These maps get initialized, then never changed again 641 (append '(ses-mode-map ses-mode-print-map ses-mode-edit-map) 642 testcover-constants))) 643 (testcover-start "ses.el" t)) 644 (require 'unsafep)) ;In case user has safe-functions = t! 645 646 647;;;######################################################################### 648(defun ses-exercise () 649 "Executes all SES coverage tests and displays the results." 650 (interactive) 651 (ses-exercise-startup) 652 ;;Run the keyboard-macro tests 653 (let ((safe-functions nil) 654 (ses-initial-size '(1 . 1)) 655 (ses-initial-column-width 7) 656 (ses-initial-default-printer "%.7g") 657 (ses-after-entry-functions '(forward-char)) 658 (ses-mode-hook nil)) 659 (ses-exercise-macros) 660 (ses-exercise-signals) 661 (ses-exercise-invalid-spreadsheets) 662 ;;Upgrade of old-style spreadsheet 663 (with-temp-buffer 664 (insert " \n\n\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") 665 (ses-load)) 666 ;;ses-vector-delete is always called from buffer-undo-list with the same 667 ;;symbol as argument. We'll give it a different one here. 668 (let ((x [1 2 3])) 669 (ses-vector-delete 'x 0 0)) 670 ;;ses-create-header-string behaves differently in a non-window environment 671 ;;but we always test under windows. 672 (let ((window-system (not window-system))) 673 (scroll-left 7) 674 (ses-create-header-string)) 675 ;;Test for nonstandard after-entry functions 676 (let ((ses-after-entry-functions '(forward-line)) 677 ses-mode-hook) 678 (ses-read-cell 0 0 1) 679 (ses-read-symbol 0 0 t))) 680 ;;Tests with unsafep disabled 681 (let ((safe-functions t) 682 ses-mode-hook) 683 (message "<Checking safe-functions = t>") 684 (kill-buffer "ses-example.ses") 685 (find-file "ses-example.ses")) 686 ;;Checks for nonstandard default values for new spreadsheets 687 (let (ses-mode-hook) 688 (dolist (x '(("%.6g" 8 (2 . 2)) 689 ("%.8g" 6 (3 . 3)))) 690 (let ((ses-initial-size (nth 2 x)) 691 (ses-initial-column-width (nth 1 x)) 692 (ses-initial-default-printer (nth 0 x))) 693 (with-temp-buffer 694 (set-buffer-modified-p t) 695 (ses-mode))))) 696 ;;Test error-handling in command hook, outside a macro. 697 ;;This will ring the bell. 698 (let (curcell-overlay) 699 (ses-command-hook)) 700 ;;Due to use of run-with-timer, ses-command-hook sometimes gets called 701 ;;after we switch to another buffer. 702 (switch-to-buffer "*scratch*") 703 (ses-command-hook) 704 ;;Print results 705 (message "<Marking source code>") 706 (testcover-mark-all "ses.el") 707 (testcover-next-mark) 708 ;;Cleanup 709 (delete-other-windows) 710 (kill-buffer "ses-test.txt") 711 ;;Could do this here: (testcover-end "ses.el") 712 (message "Done")) 713 714;;; arch-tag: 87052ba4-5cf8-46cf-9375-fe245f3360b8 715;; testcover-ses.el ends here. 716