* sweeprolog.el (sweeprolog-format-string-as-atom): new function.
(sweeprolog-module-header-skeleton): use define-skeleton, making it a
command instead of a defconst.
(sweeprolog-plunit-testset-skeleton): new skeleton and command.
* sweeprolog-tests: test it.
* README.org ("Writing Tests"): new section.
("Using templates for creating new modules"): rename to "Creating New
Modules".
More relevant information about loading code in SWI-Prolog can be
found in [[https://www.swi-prolog.org/pldoc/man?section=consulting][Loading Prolog source files]] in the SWI-Prolog manual.
-** Using templates for creating new modules
+** Creating New Modules
:PROPERTIES:
-:CUSTOM_ID: auto-insert
+:CUSTOM_ID: creating-new-modules
:DESCRIPTION: Commands for populating new Prolog modules with predefined contents
:END:
[fn:1] see [[info:elisp#Text Properties][Text Properties in the Elisp manual]]
+** Writing Tests
+:PROPERTIES:
+:CUSTOM_ID: writing-tests
+:DESCRIPTION: Commands that facilitate writing Prolog unit tests
+:END:
+
+#+FINDEX: sweeprolog-plunit-testset-skeleton~
+#+CINDEX: plunit
+#+CINDEX: testing
+
+SWI-Prolog includes the =PlUnit= unit testing framework[fn:3], in which
+unit tests are written in special blocks of Prolog code enclosed
+within the directives ~begin_tests/1~ and ~end_tests/1~. To insert a new
+block of unit tests (also known as a /test-set/) in a Prolog buffer, use
+the command ~M-x sweeprolog-plunit-testset-skeleton~. This command
+prompts for a name to give the new test-set and inserts a template
+such as the following:
+
+#+begin_src prolog
+:- begin_tests(foo_regression_tests).
+
+test() :- TestBody.
+
+:- end_tests(foo_regression_tests).
+#+end_src
+
+The cursor is left between the parentheses in ~test()~ head term and the
+~TestBody~ variable is marked as a hole (see [[#filling-holes][Filling Holes]]). To insert
+another unit test, place point after a complete test case and type
+~C-M-m~ or ~M-RET~ to invoke ~sweeprolog-insert-term-dwim~ (see
+[[#insert-term-at-point][Context-Based Term Insertion]]).
+
+[fn:3] See [[https://www.swi-prolog.org/pldoc/doc_for?object=section(%27packages/plunit.html%27)][Prolog Unit Tests in the SWI-Prolog manual]].
+
+
* Prolog Help
:PROPERTIES:
:CUSTOM_ID: prolog-help
sweep_context_callable/2,
sweep_predicate_completion_candidates/2,
sweep_exportable_predicates/2,
- sweep_interrupt/0
+ sweep_interrupt/0,
+ sweep_string_to_atom/2
]).
:- use_module(library(pldoc)).
:- else.
sweep_interrupt :- trace.
:- endif.
+
+sweep_string_to_atom(String, AtomString) :-
+ atom_string(Atom, String),
+ format(string(AtomString),
+ "~W",
+ [Atom, [quoted(true), character_escapes(true)]]).
'(sweeprolog-undefined-default-face
sweeprolog-body-default-face)))))
+(ert-deftest plunit-testset-skeleton ()
+ "Tests inserting PlUnit test-set blocks."
+ (let ((temp (make-temp-file "sweeprolog-test"
+ nil
+ "pl"
+ "")))
+ (find-file-literally temp)
+ (sweeprolog-mode)
+ (sweeprolog-plunit-testset-skeleton "foo")
+ (should (string= (buffer-string)
+ ":- begin_tests(foo).
+
+test() :- TestBody.
+
+:- end_tests(foo).
+"
+ ))))
+
(ert-deftest auto-insert-module-header ()
"Tests inserting Prolog module header with `auto-insert'."
(find-file-literally (expand-file-name "sweeprolog_test_auto_insert.pl"
[ "Find Prolog predicate" sweeprolog-find-predicate t ]
[ "Export predicate"
sweeprolog-export-predicate
- sweeprolog--exportable-predicates ]
+ (and (eq major-mode 'sweeprolog-mode)
+ (sweeprolog-definition-at-point)) ]
+ [ "Insert test-set template"
+ sweeprolog-plunit-testset-skeleton
+ (eq major-mode 'sweeprolog-mode) ]
[ "Insert module template"
auto-insert
(eq major-mode 'sweeprolog-mode) ]
(cursor-sensor-mode 1)))
-;;;; Auto-insert Prolog module header
-
-(defconst sweeprolog-module-header-skeleton
- '((or (and (buffer-file-name)
- (file-name-sans-extension
- (file-name-base (buffer-file-name))))
- (read-string "Module name: "))
- "/*"
- "\n Author: "
- (progn user-full-name)
- "\n Email: "
- (progn user-mail-address)
- (progn sweeprolog-module-header-comment-skeleton)
- "\n*/"
- "\n\n:- module("
- str
- ", [])."
- "\n\n/** <module> "
- -
- "\n\n*/\n\n")
- "Prolog module header skeleton inserted by \\[auto-insert].")
+;;;; Skeletons and auto-insert
+
+(defun sweeprolog-format-string-as-atom (string)
+ "Return STRING formatted as a Prolog atom.
+
+Notably, the returned string is quoted if required to make it a
+valid Prolog atom."
+ (sweeprolog--query-once "sweep" "sweep_string_to_atom" string))
+
+(define-skeleton sweeprolog-plunit-testset-skeleton
+ "Insert PlUnit test-set skeleton."
+ (let* ((fn (buffer-file-name))
+ (def (when fn (file-name-base fn))))
+ (sweeprolog-format-string-as-atom
+ (read-string (concat "Test set name"
+ (when def (concat " (default " def ")"))
+ ": ")
+ nil nil def)))
+ ":- begin_tests(" str ").\n\n"
+ "test(" _ ") :- " (sweeprolog--hole "TestBody") ".\n\n"
+ ":- end_tests(" str ").\n")
+
+(define-skeleton sweeprolog-module-header-skeleton
+ "Insert SWI-Prolog module header skeleton."
+ (sweeprolog-format-string-as-atom
+ (or (and (buffer-file-name)
+ (file-name-sans-extension
+ (file-name-base (buffer-file-name))))
+ (read-string "Module name: ")))
+ "/*"
+ "\n Author: " (progn user-full-name)
+ "\n Email: " (progn user-mail-address)
+ (progn sweeprolog-module-header-comment-skeleton)
+ "\n*/\n\n:- module(" str ", []).\n\n/** <module> "
+ -
+ "\n\n*/\n\n")
(define-auto-insert
'(sweeprolog-mode . "SWI-Prolog module header")
- sweeprolog-module-header-skeleton)
+ #'sweeprolog-module-header-skeleton)
;;;; Indentation