|
| 1 | +;;; aio-tests.el --- async unit test suite for aio -*- lexical-binding: t; -*- |
| 2 | + |
| 3 | +;;; Commentary: |
| 4 | + |
| 5 | +;; emacs -Q -nw -L . -l aio-test.elc -f aio-run-tests |
| 6 | + |
| 7 | +;; Because the tests run as async functions, the test suite cannot be |
| 8 | +;; run in batch mode. The results will be written into a buffer and |
| 9 | +;; Emacs will be left running so you can see the results. |
| 10 | + |
| 11 | +;;; Code: |
| 12 | + |
| 13 | +(require 'aio) |
| 14 | +(require 'cl-lib) |
| 15 | + |
| 16 | +(defvar aio-tests ()) |
| 17 | + |
| 18 | +(defvar aio-test-total nil) |
| 19 | +(defvar aio-test-failures nil) |
| 20 | + |
| 21 | +(defun aio-run-tests () |
| 22 | + (setf aio-test-total 0 |
| 23 | + aio-test-failures 0) |
| 24 | + (let* ((buffer (get-buffer-create "*aio-results*")) |
| 25 | + (promises |
| 26 | + (cl-loop for (name . test) in (reverse aio-tests) |
| 27 | + for promise = (funcall test) |
| 28 | + for cb = |
| 29 | + (let ((test-name name)) |
| 30 | + (lambda (value) |
| 31 | + (insert (format "%S: %S\n" test-name (funcall value))))) |
| 32 | + collect promise |
| 33 | + do (aio-listen (aio-catch promise) cb))) |
| 34 | + (done (aio-all promises))) |
| 35 | + (switch-to-buffer buffer) |
| 36 | + (erase-buffer) |
| 37 | + (aio-listen done (lambda (_) |
| 38 | + (with-current-buffer buffer |
| 39 | + (insert "*** aio-run-tests complete ***\n") |
| 40 | + (insert (format "%d / %d PASS\n" |
| 41 | + (- aio-test-total aio-test-failures) |
| 42 | + aio-test-total))))))) |
| 43 | + |
| 44 | +(defun aio--should (result value-a value-b expr-a expr-b) |
| 45 | + (cl-incf aio-test-total) |
| 46 | + (unless result |
| 47 | + (cl-incf aio-test-failures) |
| 48 | + (insert (format "FAIL:\n%S\n= %S\n%S\n= %S\n" |
| 49 | + expr-a value-a expr-b value-b)))) |
| 50 | + |
| 51 | +(defmacro aio-should (cmp expr-a expr-b) |
| 52 | + (let ((value-a (make-symbol "a")) |
| 53 | + (value-b (make-symbol "b"))) |
| 54 | + `(let ((,value-a ,expr-a) |
| 55 | + (,value-b ,expr-b)) |
| 56 | + (aio--should (,cmp ,value-a ,value-b) |
| 57 | + ,value-a ,value-b ',expr-a ',expr-b)))) |
| 58 | + |
| 59 | +(defmacro aio-deftest (name _ &rest body) |
| 60 | + (declare (indent defun)) |
| 61 | + `(push (cons ',name (aio-lambda () ,@body)) aio-tests)) |
| 62 | + |
| 63 | +;; Tests: |
| 64 | + |
| 65 | +(aio-deftest sleep () |
| 66 | + (let ((start (float-time))) |
| 67 | + (dotimes (i 3) |
| 68 | + (aio-should eql i (aio-await (aio-sleep 0.5 i)))) |
| 69 | + (aio-should > (- (float-time) start) 1.4))) |
| 70 | + |
| 71 | +(aio-deftest chain () |
| 72 | + (let ((sub (aio-lambda (result) (aio-await (aio-sleep .1 result))))) |
| 73 | + (aio-should eq :a (aio-await (funcall sub :a))) |
| 74 | + (aio-should eq :b (aio-await (funcall sub :b))))) |
| 75 | + |
| 76 | +(aio-deftest timeout () |
| 77 | + (let ((sleep (aio-sleep 1 t))) |
| 78 | + (prog1 nil |
| 79 | + (aio-should equal |
| 80 | + '(:error aio-timeout . 0.5) |
| 81 | + (aio-await (aio-catch (aio-timeout sleep 0.5))))))) |
| 82 | + |
| 83 | +(defun aio-test--shuffle (values) |
| 84 | + "Return a shuffled copy of VALUES." |
| 85 | + (let ((v (vconcat values))) |
| 86 | + (cl-loop for i from (1- (length v)) downto 1 |
| 87 | + for j = (cl-random (+ i 1)) |
| 88 | + do (cl-rotatef (aref v i) (aref v j)) |
| 89 | + finally return (append v nil)))) |
| 90 | + |
| 91 | +(aio-deftest sleep-sort () |
| 92 | + (let* ((values (cl-loop for i from 5 to 60 |
| 93 | + collect (/ i 20.0) into values |
| 94 | + finally return (aio-test--shuffle values))) |
| 95 | + (promises (cl-loop for value in values |
| 96 | + collect (aio-sleep value value))) |
| 97 | + (last 0.0)) |
| 98 | + (while promises |
| 99 | + (let ((promise (aio-await (aio-select promises)))) |
| 100 | + (setf promises (delq promise promises)) |
| 101 | + (let ((result (aio-await promise))) |
| 102 | + (aio-should > result last) |
| 103 | + (setf last result)))))) |
| 104 | + |
| 105 | +(aio-deftest process-sentinel () |
| 106 | + (let ((process (start-process-shell-command "test" nil ""))) |
| 107 | + (aio-should equal |
| 108 | + "finished\n" |
| 109 | + (aio-await (aio-process-sentinel process))))) |
| 110 | + |
| 111 | +(aio-deftest process-filter () |
| 112 | + (let ((process (start-process-shell-command |
| 113 | + "test" nil "echo a b c; sleep 1; echo 1 2 3; sleep 1"))) |
| 114 | + (aio-should equal |
| 115 | + "a b c\n" |
| 116 | + (aio-await (aio-process-filter process))) |
| 117 | + (aio-should equal |
| 118 | + "1 2 3\n" |
| 119 | + (aio-await (aio-process-filter process))) |
| 120 | + (aio-should equal |
| 121 | + nil |
| 122 | + (aio-await (aio-process-filter process))))) |
0 commit comments