changelog shortlog graph tags branches changeset files revisions annotate raw help

Mercurial > core / lisp/lib/rt/util.lisp

changeset 632: bbd9024f2fe2
parent: 2a4f11c0e8c8
author: Richard Westhaver <ellis@rwest.io>
date: Sat, 31 Aug 2024 22:34:56 -0400
permissions: -rw-r--r--
description: lib/rt upgrades and refactoring
1 ;;; rt/util.lisp --- Test Utilities
2 
3 ;;
4 
5 ;;; Commentary:
6 
7 ;; some of these are taken from the TEST-UTIL package of SBCL
8 ;; (tests/test-util.lisp)
9 
10 ;;; Code:
11 (in-package :rt)
12 
13 ;;; tmp
14 (defmacro with-tmp-directory ((&optional (name (string (gensym "tmp")))
15  (defaults *default-tmp-directory*))
16  &body body)
17  `(let ((*tmp* (directory-path (merge-pathnames ,name ,defaults))))
18  (ensure-directories-exist *tmp*)
19  (unwind-protect (progn ,@body)
20  (sb-ext:delete-directory *tmp* :recursive t))))
21 
22 (defmacro with-tmp-file ((stream-var &key (name (string (gensym "tmp")))
23  type
24  (directory *default-tmp-directory*)
25  (direction :output)
26  (if-exists :supersede)
27  (element-type ''character))
28  &body body)
29  `(let ((*tmp* (make-pathname :name ,name :type ,type :directory ,(namestring directory))))
30  (with-open-file (,stream-var *tmp* :direction ,direction :element-type ,element-type
31  :if-exists ,if-exists)
32  (unwind-protect (progn ,@body)
33  (delete-file *tmp*)))))
34 
35 ;;; random
36 (defvar *simple-charset* "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
37 
38 (defun random-elt (seq)
39  (elt seq (random (length seq))))
40 
41 (defun random-ref (vec)
42  (aref vec (random (length vec))))
43 
44 (defun random-char ()
45  (random-ref *simple-charset*))
46 
47 (defun random-chars (dim)
48  (let ((r (make-array dim :element-type 'character)))
49  (dotimes (i (array-total-size r) r)
50  (setf (row-major-aref r i) (random-char)))))
51 
52 (defun random-byte () (random 255))
53 
54 (defun random-bytes (dim)
55  (let ((r (make-array dim :element-type 'octet)))
56  (dotimes (i (array-total-size r) r)
57  (setf (row-major-aref r i) (random-byte)))))
58 
59 (eval-when (:compile-toplevel :load-toplevel :execute)
60  (defun make-test (&rest slots)
61  (apply #'make-instance 'test slots))
62  (defun make-suite (&rest slots)
63  (apply #'make-instance 'test-suite slots)))
64 
65 ;; TODO 2023-09-04: optimize
66 ;;(declaim (inline do-tests))
67 (defun do-tests (&optional (suite *test-suite*) force (output *standard-output*))
68  (if (pathnamep output)
69  (with-open-file (stream output :direction :output)
70  (do-suite (ensure-suite suite) :stream stream :force force))
71  (do-suite (ensure-suite suite) :stream output :force force)))
72 
73 (defvar *test-output-mutex* (sb-thread:make-mutex :name "tests-output"))
74 
75 ;; TODO
76 (defun do-tests-concurrently (&optional (suite *test-suite*) force (output *standard-output*))
77  (declare (ignore suite force))
78  (sb-thread:with-mutex (*test-output-mutex*)
79  (let ((stream (make-synonym-stream output)))
80  (let ((*standard-output* stream)
81  (*error-output* stream))
82  (nyi!)))))
83 
84 (defun reset-tests ()
85  (setq *testing* nil
86  *test-suite* nil
87  *test-suite-list* nil
88  *test-input* nil))
89 
90 ;; this assumes that *test-suite* is re-initialized correctly to the
91 ;; correct test-suite object.
92 (defun continue-testing ()
93  (if-let ((test *testing*))
94  (throw '%in-test test)
95  (do-suite *test-suite*)))
96 
97 ;; NOTE 2023-09-01: `pushnew' does not return an indication of whether
98 ;; place is changed - it returns place. This is functionally sound but
99 ;; means that if we want to do something else in the event that place
100 ;; is unchanged, we run into some friction,
101 ;; https://stackoverflow.com/questions/56228832/adapting-common-lisp-pushnew-to-return-success-failure
102 (defun spush (item lst &key (test #'equal))
103  "Substituting `push'"
104  (declare (type function test))
105  (cond
106  ((null lst) (push item lst))
107  ((list lst)
108  (if-let ((found (member item lst
109  :test test)))
110  (progn
111  (rplaca found item)
112  lst)
113  (push item lst)))
114  #|(or nil '(t (cons item lst)))|#))
115 
116 ;; FIX 2023-08-31: spush, replace with `add-test' method.
117 ;; (declaim (inline normalize-test-name))
118 (defun normalize-test-name (a)
119  "Return the normalized `test-suite-designator' of A."
120  (etypecase a
121  (string (string-upcase a))
122  (symbol (symbol-name a))
123  (test-object (normalize-test-name (test-name a)))
124  (t (format nil "~A" a))))
125 
126 (defun test-name= (a b)
127  "Return t if A and B are similar `test-suite-designator's."
128  (let ((a (normalize-test-name a))
129  (b (normalize-test-name b)))
130  (string= a b)))
131 
132 ;; (declaim (inline assert-suite ensure-suite))
133 (defun ensure-suite (name)
134  (if-let ((ok (member name *test-suite-list* :test #'test-name=)))
135  (car ok)
136  (when (or (eq name t) (null name)) (make-suite :name *default-test-suite-name*))))
137 
138 (defun check-suite-designator (suite) (check-type suite test-suite-designator))
139 
140 (defun assert-suite (name)
141  (check-suite-designator name)
142  (assert (ensure-suite name)))
143 
144 (declaim (inline test-opt-key-p test-opt-valid-p))
145 (defun test-opt-key-p (k)
146  "Test if K is a `test-opt-key'."
147  (member k '(:profile :save :stream)))
148 
149 (defun test-opt-valid-p (f)
150  "Test if F is a valid `test-opt' form. If so, return F else nil."
151  (when (test-opt-key-p (car f))
152  f))