From 09babc46d92c4a1b85d619a4935459f7d6125c03 Mon Sep 17 00:00:00 2001 From: Uko Kokņevičs Date: Sun, 19 Oct 2025 07:30:03 +0300 Subject: Add a read-write lock & a testsuite --- test/all.lisp | 28 ++++++++++++++++++++ test/rw-lock.lisp | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 test/all.lisp create mode 100644 test/rw-lock.lisp (limited to 'test') diff --git a/test/all.lisp b/test/all.lisp new file mode 100644 index 0000000..b0a731b --- /dev/null +++ b/test/all.lisp @@ -0,0 +1,28 @@ +;; SPDX-License-Identifier: EUPL-1.2 +;; SPDX-FileCopyrightText: 2025 Uko Kokņevičs +(defpackage :ukkoclot/test/all + (:documentation "Main test runner package.") + (:use :c2cl :fiveam + :ukkoclot/test/rw-lock) + (:import-from :bt2 :with-timeout) + (:import-from :uiop) + (:export #:*should-quit* #:run-tests)) +(in-package :ukkoclot/test/all) + +(defvar *should-quit* nil + "Bind as true if `run-tests' should exit the process with 0 or 1. + +Useful for CI.") + +;; TODO: Maybe I should signal on failure instead :thinking: +(defun run-tests () + "Run all tests" + (with-timeout (100) + (let ((status (run-all-tests))) + (when *should-quit* + (format t "~2&BTW Ignore the fatal ERROR condition below") + (cond + (status (format t "~&!GREAT SUCCESS!~2%") + (uiop:quit 0)) + (t (format t "~&!!! TESTS R FUCKED MATE !!!~2%") + (uiop:quit 1))))))) diff --git a/test/rw-lock.lisp b/test/rw-lock.lisp new file mode 100644 index 0000000..4460398 --- /dev/null +++ b/test/rw-lock.lisp @@ -0,0 +1,79 @@ +;; SPDX-License-Identifier: EUPL-1.2 +;; SPDX-FileCopyrightText: 2025 Uko Kokņevičs +(defpackage :ukkoclot/test/rw-lock + (:documentation "Test-suite for :ukkoclot/src/rw-lock.") + (:use :c2cl :fiveam :ukkoclot/src/rw-lock) + (:import-from :bt2 :with-timeout)) +(in-package :ukkoclot/test/rw-lock) + +(def-suite :ukkoclot/rw-lock) +(in-suite :ukkoclot/rw-lock) + +(test rw-lock.typep + (is (typep (make-rw-lock) 'rw-lock))) + +(test rw-lock-p + (is (rw-lock-p (make-rw-lock)))) + +(test acquire-read-lock.no-contention + (with-timeout (5) + (let ((lock (make-rw-lock))) + (is-true (acquire-read-lock lock :wait t)) + (is (rw-lock-p (release-read-lock lock))) + (is-true (acquire-read-lock lock :wait nil)) + (is (rw-lock-p (release-read-lock lock)))))) + +(test acquire-read-lock.multiple + (with-timeout (5) + (let ((lock (make-rw-lock))) + (is-true (acquire-read-lock lock :wait t)) + (is-true (acquire-read-lock lock :wait nil)) + (is-true (acquire-read-lock lock :wait t)) + (is (rw-lock-p (release-read-lock lock))) + (is (rw-lock-p (release-read-lock lock))) + (is (rw-lock-p (release-read-lock lock)))))) + +(test acquire-write-lock.no-contention + (let ((lock (make-rw-lock))) + (is-true (acquire-write-lock lock :wait nil)) + (is (rw-lock-p (release-write-lock lock))) + (is-true (acquire-write-lock lock :wait nil)) + (is (rw-lock-p (release-write-lock lock))))) + +(test acquire-write-lock.contention + (let ((lock (make-rw-lock))) + (is-true (acquire-write-lock lock :wait nil)) + (is-false (acquire-write-lock lock :wait nil)) + (is (rw-lock-p (release-write-lock lock))))) + +(test acquire-read&write-lock.contention + (let ((lock (make-rw-lock))) + (is-true (acquire-read-lock lock :wait nil)) + (is-true (acquire-read-lock lock :wait nil)) + (is-false (acquire-write-lock lock :wait nil)) + (is (rw-lock-p (release-read-lock lock))) + (is (rw-lock-p (release-read-lock lock))) + (is-true (acquire-write-lock lock :wait nil)) + (is-false (acquire-read-lock lock :wait nil)) + (is (rw-lock-p (release-write-lock lock))))) + +(test with-read-lock.simple + (let ((lock (make-rw-lock))) + (with-read-lock (lock) + (is-true (acquire-read-lock lock :wait nil)) + (is (rw-lock-p (release-read-lock lock))) + (is-false (acquire-write-lock lock :wait nil))) + (is-true (acquire-read-lock lock :wait nil)) + (is (rw-lock-p (release-read-lock lock))) + (is-true (acquire-write-lock lock :wait nil)) + (is (rw-lock-p (release-write-lock lock))))) + +(test with-write-lock.simple + (let ((lock (make-rw-lock))) + (with-write-lock (lock) + (is-false (acquire-read-lock lock :wait nil)) + (is-false (acquire-write-lock lock :wait nil))) + (is-true (acquire-read-lock lock :wait nil)) + (is (rw-lock-p (release-read-lock lock))) + (is-true (acquire-write-lock lock :wait nil)) + (is (rw-lock-p (release-write-lock lock))))) -- cgit v1.2.3