From 147ec7f878213a39c7f4c2a19979bb814122d7e8 Mon Sep 17 00:00:00 2001 From: Eshel Yaron Date: Wed, 23 Nov 2022 21:25:39 +0200 Subject: [PATCH] ADDED: PlUnit tests block skeleton and command for inserting it * 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". --- README.org | 39 +++++++++++++++++++++++++-- sweep.pl | 9 ++++++- sweeprolog-tests.el | 18 +++++++++++++ sweeprolog.el | 65 +++++++++++++++++++++++++++++---------------- 4 files changed, 105 insertions(+), 26 deletions(-) diff --git a/README.org b/README.org index bc344bb..9fdfe56 100644 --- a/README.org +++ b/README.org @@ -821,9 +821,9 @@ C-l=). 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: @@ -1105,6 +1105,41 @@ Emacs manual]]). [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 diff --git a/sweep.pl b/sweep.pl index 3314f57..dba4772 100644 --- a/sweep.pl +++ b/sweep.pl @@ -67,7 +67,8 @@ 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)). @@ -841,3 +842,9 @@ sweep_interrupt :- prolog_interrupt. :- 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)]]). diff --git a/sweeprolog-tests.el b/sweeprolog-tests.el index 9953d09..db03e45 100644 --- a/sweeprolog-tests.el +++ b/sweeprolog-tests.el @@ -177,6 +177,24 @@ foo(Foo) :- bar. '(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" diff --git a/sweeprolog.el b/sweeprolog.el index 490012d..7faf331 100644 --- a/sweeprolog.el +++ b/sweeprolog.el @@ -427,7 +427,11 @@ non-terminals)." [ "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) ] @@ -3494,31 +3498,46 @@ certain contexts to maintain conventional Prolog layout." (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/** " - - - "\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/** " + - + "\n\n*/\n\n") (define-auto-insert '(sweeprolog-mode . "SWI-Prolog module header") - sweeprolog-module-header-skeleton) + #'sweeprolog-module-header-skeleton) ;;;; Indentation -- 2.39.2