;;; data-tests.el --- tests for src/data.c -*- lexical-binding:t -*- ;; Copyright (C) 2013-2024 Free Software Foundation, Inc. ;; This file is part of GNU Emacs. ;; GNU Emacs is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . ;;; Commentary: ;;; Code: (require 'cl-lib) (defconst data-tests--float-greater-than-fixnums (+ 1.0 most-positive-fixnum) "A floating-point value that is greater than all fixnums. It is also as small as conveniently possible, to make the tests sharper. Adding 1.0 to `most-positive-fixnum' should suffice on all practical Emacs platforms, since the result is a power of 2 and this is exactly representable and is greater than `most-positive-fixnum', which is just less than a power of 2.") (ert-deftest data-tests-= () (should-error (=)) (should (= 1)) (should (= 2 2)) (should (= 9 9 9 9 9 9 9 9 9)) (should (= most-negative-fixnum (float most-negative-fixnum))) (should-not (= most-positive-fixnum data-tests--float-greater-than-fixnums)) (should-not (apply #'= '(3 8 3))) (should-error (= 9 9 'foo)) ;; Short circuits before getting to bad arg (should-not (= 9 8 'foo))) (ert-deftest data-tests-< () (should-error (<)) (should (< 1)) (should (< 2 3)) (should (< -6 -1 0 2 3 4 8 9 999)) (should (< 0.5 most-positive-fixnum data-tests--float-greater-than-fixnums)) (should-not (apply #'< '(3 8 3))) (should-error (< 9 10 'foo)) ;; Short circuits before getting to bad arg (should-not (< 9 8 'foo))) (ert-deftest data-tests-> () (should-error (>)) (should (> 1)) (should (> 3 2)) (should (> 6 1 0 -2 -3 -4 -8 -9 -999)) (should (> data-tests--float-greater-than-fixnums most-positive-fixnum 0.5)) (should-not (apply #'> '(3 8 3))) (should-error (> 9 8 'foo)) ;; Short circuits before getting to bad arg (should-not (> 8 9 'foo))) (ert-deftest data-tests-<= () (should-error (<=)) (should (<= 1)) (should (<= 2 3)) (should (<= -6 -1 -1 0 0 0 2 3 4 8 999)) (should (<= 0.5 most-positive-fixnum data-tests--float-greater-than-fixnums)) (should-not (apply #'<= '(3 8 3 3))) (should-error (<= 9 10 'foo)) ;; Short circuits before getting to bad arg (should-not (<= 9 8 'foo))) (ert-deftest data-tests->= () (should-error (>=)) (should (>= 1)) (should (>= 3 2)) (should (>= 666 1 0 0 -2 -3 -3 -3 -4 -8 -8 -9 -999)) (should (>= data-tests--float-greater-than-fixnums most-positive-fixnum)) (should-not (apply #'>= '(3 8 3))) (should-error (>= 9 8 'foo)) ;; Short circuits before getting to bad arg (should-not (>= 8 9 'foo))) (ert-deftest data-tests-max () (should-error (max)) (should (= 1 (max 1))) (should (= 3 (max 3 2))) (should (= 666 (max 666 1 0 0 -2 -3 -3 -3 -4 -8 -8 -9 -999))) (should (= (1+ most-negative-fixnum) (max (float most-negative-fixnum) (1+ most-negative-fixnum)))) (should (= 8 (apply #'max '(3 8 3)))) (should-error (max 9 8 'foo)) (should-error (max (make-marker))) (should (eql 1 (max (point-min-marker) 1)))) (ert-deftest data-tests-min () (should-error (min)) (should (= 1 (min 1))) (should (= 2 (min 3 2))) (should (= -999 (min 666 1 0 0 -2 -3 -3 -3 -4 -8 -8 -9 -999))) (should (= most-positive-fixnum (min data-tests--float-greater-than-fixnums most-positive-fixnum))) (should (= 3 (apply #'min '(3 8 3)))) (should-error (min 9 8 'foo)) (should-error (min (make-marker))) (should (eql 1 (min (point-min-marker) 1))) (should (isnan (min 0.0e+NaN))) (should (isnan (min 0.0e+NaN 1 2))) (should (isnan (min 1.0 0.0e+NaN))) (should (isnan (min 1.0 0.0e+NaN 1.1))) (should (isnan (min 1.0 0.0e+NaN 1.1 (1+ most-positive-fixnum)))) (should (isnan (max 1.0 0.0e+NaN 1.1 (1+ most-positive-fixnum))))) (defun data-tests-popcnt (byte) "Calculate the Hamming weight of BYTE." (if (< byte 0) (setq byte (lognot byte))) (if (zerop byte) 0 (+ (logand byte 1) (data-tests-popcnt (ash byte -1))))) (ert-deftest data-tests-logcount () (should (cl-loop for n in (number-sequence -255 255) always (= (logcount n) (data-tests-popcnt n)))) ;; https://oeis.org/A000120 (should (= 11 (logcount 9727))) (should (= 8 (logcount 9999)))) ;; Bool vector tests. Compactly represent bool vectors as hex ;; strings. (ert-deftest bool-vector-count-population-all-0-nil () (cl-loop for sz in '(0 45 1 64 9 344) do (let* ((bv (make-bool-vector sz nil))) (should (zerop (bool-vector-count-population bv)))))) (ert-deftest bool-vector-count-population-all-1-t () (cl-loop for sz in '(0 45 1 64 9 344) do (let* ((bv (make-bool-vector sz t))) (should (eql (bool-vector-count-population bv) sz))))) (ert-deftest bool-vector-count-population-1-nil () (let* ((bv (make-bool-vector 45 nil))) (aset bv 40 t) (aset bv 0 t) (should (eql (bool-vector-count-population bv) 2)))) (ert-deftest bool-vector-count-population-1-t () (let* ((bv (make-bool-vector 45 t))) (aset bv 40 nil) (aset bv 0 nil) (should (eql (bool-vector-count-population bv) 43)))) (defun mock-bool-vector-count-consecutive (a b i) (cl-loop for i from i below (length a) while (eq (aref a i) b) sum 1)) (defun test-bool-vector-bv-from-hex-string (desc) (let (bv nibbles) (dolist (c (string-to-list desc)) (push (string-to-number (char-to-string c) 16) nibbles)) (setf bv (make-bool-vector (* 4 (length nibbles)) nil)) (let ((i 0)) (dolist (n (nreverse nibbles)) (dotimes (_ 4) (aset bv i (> (logand 1 n) 0)) (cl-incf i) (setf n (ash n -1))))) bv)) (defun test-bool-vector-to-hex-string (bv) (let (nibbles (v (cl-coerce bv 'list))) (while v (push (logior (ash (if (nth 0 v) 1 0) 0) (ash (if (nth 1 v) 1 0) 1) (ash (if (nth 2 v) 1 0) 2) (ash (if (nth 3 v) 1 0) 3)) nibbles) (setf v (nthcdr 4 v))) (mapconcat (lambda (n) (format "%X" n)) (nreverse nibbles)))) (defun test-bool-vector-count-consecutive-tc (desc) "Run a test case for `bool-vector-count-consecutive'. DESC is a string describing the test. It is a sequence of hexadecimal digits describing the bool vector. We exhaustively test all counts at all possible positions in the vector by comparing the subr with a much slower Lisp implementation." (let ((bv (test-bool-vector-bv-from-hex-string desc))) (cl-loop for lf in '(nil t) do (cl-loop for pos from 0 upto (length bv) for cnt = (mock-bool-vector-count-consecutive bv lf pos) for rcnt = (bool-vector-count-consecutive bv lf pos) unless (eql cnt rcnt) do (error "FAILED testcase %S %3S %3S %3S" pos lf cnt rcnt))))) (defconst bool-vector-test-vectors '("" "0" "F" "0F" "F0" "00000000000000000000000000000FFFFF0000000" "44a50234053fba3340000023444a50234053fba33400000234" "12341234123456123412346001234123412345612341234600" "44a50234053fba33400000234" "1234123412345612341234600" "44a50234053fba33400000234" "1234123412345612341234600" "44a502340" "123412341" "0000000000000000000000000" "FFFFFFFFFFFFFFFF1")) (ert-deftest bool-vector-count-consecutive () (mapc #'test-bool-vector-count-consecutive-tc bool-vector-test-vectors)) (defun test-bool-vector-apply-mock-op (mock a b c) "Compute (slowly) the correct result of a bool-vector set operation." (let (changed) (cl-assert (eql (length b) (length c))) (unless a (setf a (make-bool-vector (length b) nil)) (setf changed t)) (cl-loop for i below (length b) for mockr = (funcall mock (if (aref b i) 1 0) (if (aref c i) 1 0)) for r = (not (= 0 mockr)) do (progn (unless (eq (aref a i) r) (setf changed t)) (setf (aref a i) r))) (if changed a))) (defun test-bool-vector-binop (mock real) "Test a binary set operation." (cl-loop for s1 in bool-vector-test-vectors for bv1 = (test-bool-vector-bv-from-hex-string s1) for vecs2 = (cl-remove-if-not (lambda (x) (eql (length x) (length s1))) bool-vector-test-vectors) do (cl-loop for s2 in vecs2 for bv2 = (test-bool-vector-bv-from-hex-string s2) for mock-result = (test-bool-vector-apply-mock-op mock nil bv1 bv2) for real-result = (funcall real bv1 bv2) do (progn (should (equal mock-result real-result)))))) (ert-deftest bool-vector-intersection-op () (test-bool-vector-binop #'logand #'bool-vector-intersection)) (ert-deftest bool-vector-union-op () (test-bool-vector-binop #'logior #'bool-vector-union)) (ert-deftest bool-vector-xor-op () (test-bool-vector-binop #'logxor #'bool-vector-exclusive-or)) (ert-deftest bool-vector-set-difference-op () (test-bool-vector-binop (lambda (a b) (logand a (lognot b))) #'bool-vector-set-difference)) (ert-deftest bool-vector-change-detection () (let* ((vc1 (test-bool-vector-bv-from-hex-string "abcdef")) (vc2 (test-bool-vector-bv-from-hex-string "012345")) (vc3 (make-bool-vector (length vc1) nil)) (c1 (bool-vector-union vc1 vc2 vc3)) (c2 (bool-vector-union vc1 vc2 vc3))) (should (equal c1 (test-bool-vector-apply-mock-op #'logior nil vc1 vc2))) (should (not c2)))) (ert-deftest bool-vector-not () (let* ((v1 (test-bool-vector-bv-from-hex-string "FFFF3")) (v2 (test-bool-vector-bv-from-hex-string "0000C")) (v3 (bool-vector-not v1))) (should (equal v2 v3)))) ;; Tests for variable bindings (defvar binding-test-buffer-A (get-buffer-create "A")) (defvar binding-test-buffer-B (get-buffer-create "B")) (defvar binding-test-always-local 'always) (make-variable-buffer-local 'binding-test-always-local) (defvar binding-test-some-local 'some) (with-current-buffer binding-test-buffer-A (setq-local binding-test-some-local 'local)) (ert-deftest binding-test-manual () "A test case from the elisp manual." (with-current-buffer binding-test-buffer-A (let ((binding-test-some-local 'something-else)) (should (eq binding-test-some-local 'something-else)) (set-buffer binding-test-buffer-B) (should (eq binding-test-some-local 'some))) (should (eq binding-test-some-local 'some)) (set-buffer binding-test-buffer-A) (should (eq binding-test-some-local 'local)))) (ert-deftest binding-test-setq-default () "Test that a `setq-default' has no effect when there is a local binding." (with-current-buffer binding-test-buffer-B ;; This variable is not local in this buffer. (let ((binding-test-some-local 'something-else)) (setq-default binding-test-some-local 'new-default)) (should (eq binding-test-some-local 'some)))) (ert-deftest data-tests--let-buffer-local () (let ((blvar (make-symbol "blvar"))) (set-default blvar nil) (make-variable-buffer-local blvar) (dolist (var (list blvar 'left-margin)) (let ((def (default-value var))) (with-temp-buffer (should (equal def (symbol-value var))) (cl-progv (list var) (list 42) (should (equal (symbol-value var) 42)) (should (equal (default-value var) (symbol-value var))) (set var 123) (should (not (local-variable-p var))) (should (equal (symbol-value var) 123)) (should (equal (default-value var) (symbol-value var)))) ;bug#44733 (should (equal (symbol-value var) def)) (should (equal (default-value var) (symbol-value var)))) (should (equal (default-value var) def)))))) (ert-deftest data-tests--let-buffer-local-no-unwind-other-buffers () "Test that a let-binding for a buffer-local unwinds only current-buffer." (let ((blvar (make-symbol "blvar"))) (set-default blvar 0) (make-variable-buffer-local blvar) (dolist (var (list blvar 'left-margin)) (let* ((def (default-value var)) (newdef (+ def 1)) (otherbuf (generate-new-buffer "otherbuf"))) (with-temp-buffer (cl-progv (list var) (list newdef) (with-current-buffer otherbuf (set var 123) (should (local-variable-p var)) (should (equal (symbol-value var) 123)) (should (equal (default-value var) newdef)))) (with-current-buffer otherbuf (should (local-variable-p var)) (should (equal (symbol-value var) 123)) (should (equal (default-value var) def))) ))))) (ert-deftest binding-test-makunbound () "Tests of makunbound, from the manual." (with-current-buffer binding-test-buffer-B (should (boundp 'binding-test-some-local)) (let ((binding-test-some-local 'outer)) (let ((binding-test-some-local 'inner)) (makunbound 'binding-test-some-local) (should (not (boundp 'binding-test-some-local)))) (should (and (boundp 'binding-test-some-local) (eq binding-test-some-local 'outer)))))) (ert-deftest binding-test-defvar-bool () "Test DEFVAR_BOOL." (let ((display-hourglass 5)) (should (eq display-hourglass t)))) (ert-deftest binding-test-defvar-int () "Test DEFVAR_INT." (should-error (setq gc-cons-threshold 5.0) :type 'wrong-type-argument)) (ert-deftest binding-test-set-constant-t () "Test setting the constant t." (with-no-warnings (should-error (setq t 'bob) :type 'setting-constant))) (ert-deftest binding-test-set-constant-nil () "Test setting the constant nil." (with-no-warnings (should-error (setq nil 'bob) :type 'setting-constant))) (ert-deftest binding-test-set-constant-keyword () "Test setting a keyword constant." (with-no-warnings (should-error (setq :keyword 'bob) :type 'setting-constant))) (ert-deftest binding-test-set-constant-itself () "Test setting a keyword to itself." (with-no-warnings (should (setq :keyword :keyword)))) (ert-deftest data-tests--set-default-per-buffer () :expected-result t ;; Not fixed yet! ;; FIXME: Performance tests are inherently unreliable. ;; Using wall-clock time makes it even worse, so don't bother unless ;; we have the primitive to measure cpu-time. (skip-unless (fboundp 'current-cpu-time)) ;; Test performance of set-default on DEFVAR_PER_BUFFER variables. ;; More specifically, test the problem seen in bug#41029 where setting ;; the default value of a variable takes time proportional to the ;; number of buffers. (when (fboundp 'current-cpu-time) ; silence byte-compiler (let* ((fun #'error) (test (lambda () (with-temp-buffer (let ((st (car (current-cpu-time)))) (dotimes (_ 1000) (let ((case-fold-search 'data-test)) ;; Use an indirection through a mutable var ;; to try and make sure the byte-compiler ;; doesn't optimize away the let bindings. (funcall fun))) ;; FIXME: Handle the wraparound, if any. (- (car (current-cpu-time)) st))))) (_ (setq fun #'ignore)) (time1 (funcall test)) (bufs (mapcar (lambda (_) (generate-new-buffer " data-test")) (make-list 1000 nil))) (time2 (funcall test))) (mapc #'kill-buffer bufs) ;; Don't divide one time by the other since they may be 0. (should (< time2 (* time1 5)))))) ;; More tests to write - ;; kill-local-variable ;; defconst; can modify ;; defvar and defconst modify the local binding [ doesn't matter for us ] ;; various kinds of special internal forwarding objects ;; a couple examples in manual, not enough ;; variable aliases ;; Tests for watchpoints (ert-deftest data-tests-variable-watchers () (defvar data-tests-var 0) (let* ((watch-data nil) (collect-watch-data (lambda (&rest args) (push args watch-data)))) (cl-flet ((should-have-watch-data (data) (should (equal (pop watch-data) data)) (should (null watch-data)))) (add-variable-watcher 'data-tests-var collect-watch-data) (setq data-tests-var 1) (should-have-watch-data '(data-tests-var 1 set nil)) (let ((data-tests-var 2)) (should-have-watch-data '(data-tests-var 2 let nil)) (setq data-tests-var 3) (should-have-watch-data '(data-tests-var 3 set nil))) (should-have-watch-data '(data-tests-var 1 unlet nil)) ;; `setq-default' on non-local variable is same as `setq'. (setq-default data-tests-var 4) (should-have-watch-data '(data-tests-var 4 set nil)) (makunbound 'data-tests-var) (should-have-watch-data '(data-tests-var nil makunbound nil)) (setq data-tests-var 5) (should-have-watch-data '(data-tests-var 5 set nil)) (remove-variable-watcher 'data-tests-var collect-watch-data) (setq data-tests-var 6) (should (null watch-data))))) (ert-deftest data-tests-varalias-watchers () (defvar data-tests-var0 0) (defvar data-tests-var1 0) (defvar data-tests-var2 0) (defvar data-tests-var3 0) (let* ((watch-data nil) (collect-watch-data (lambda (&rest args) (push args watch-data)))) (cl-flet ((should-have-watch-data (data) (should (equal (pop watch-data) data)) (should (null watch-data)))) ;; Watch var0, then alias it. (add-variable-watcher 'data-tests-var0 collect-watch-data) (defvar data-tests-var0-alias) (defvaralias 'data-tests-var0-alias 'data-tests-var0) (setq data-tests-var0 1) (should-have-watch-data '(data-tests-var0 1 set nil)) (setq data-tests-var0-alias 2) (should-have-watch-data '(data-tests-var0 2 set nil)) ;; Alias var1, then watch var1-alias. (defvar data-tests-var1-alias) (defvaralias 'data-tests-var1-alias 'data-tests-var1) (add-variable-watcher 'data-tests-var1-alias collect-watch-data) (setq data-tests-var1 1) (should-have-watch-data '(data-tests-var1 1 set nil)) (setq data-tests-var1-alias 2) (should-have-watch-data '(data-tests-var1 2 set nil)) ;; Alias var2, then watch it. (defvar data-tests-var2-alias) (defvaralias 'data-tests-var2-alias 'data-tests-var2) (add-variable-watcher 'data-tests-var2 collect-watch-data) (setq data-tests-var2 1) (should-have-watch-data '(data-tests-var2 1 set nil)) (setq data-tests-var2-alias 2) (should-have-watch-data '(data-tests-var2 2 set nil)) ;; Watch var3-alias, then make it alias var3 (this removes the ;; watcher flag). (defvar data-tests-var3-alias 0) (add-variable-watcher 'data-tests-var3-alias collect-watch-data) (defvaralias 'data-tests-var3-alias 'data-tests-var3) (should-have-watch-data '(data-tests-var3-alias data-tests-var3 defvaralias nil)) (setq data-tests-var3 1) (setq data-tests-var3-alias 2) (should (null watch-data))))) (ert-deftest data-tests-local-variable-watchers () (with-no-warnings (defvar-local data-tests-lvar 0)) (let* ((buf1 (current-buffer)) (buf2 nil) (watch-data nil) (collect-watch-data (lambda (&rest args) (push args watch-data)))) (cl-flet ((should-have-watch-data (data) (should (equal (pop watch-data) data)) (should (null watch-data)))) (add-variable-watcher 'data-tests-lvar collect-watch-data) (setq data-tests-lvar 1) (should-have-watch-data `(data-tests-lvar 1 set ,buf1)) (let ((data-tests-lvar 2)) (should-have-watch-data `(data-tests-lvar 2 let ,buf1)) (setq data-tests-lvar 3) (should-have-watch-data `(data-tests-lvar 3 set ,buf1))) (should-have-watch-data `(data-tests-lvar 1 unlet ,buf1)) (setq-default data-tests-lvar 4) (should-have-watch-data '(data-tests-lvar 4 set nil)) (with-temp-buffer (setq buf2 (current-buffer)) (setq data-tests-lvar 1) (should-have-watch-data `(data-tests-lvar 1 set ,buf2)) (let ((data-tests-lvar 2)) (should-have-watch-data `(data-tests-lvar 2 let ,buf2)) (setq data-tests-lvar 3) (should-have-watch-data `(data-tests-lvar 3 set ,buf2))) (should-have-watch-data `(data-tests-lvar 1 unlet ,buf2)) (kill-local-variable 'data-tests-lvar) (should-have-watch-data `(data-tests-lvar nil makunbound ,buf2)) (setq data-tests-lvar 3.5) (should-have-watch-data `(data-tests-lvar 3.5 set ,buf2)) (kill-all-local-variables) (should-have-watch-data `(data-tests-lvar nil makunbound ,buf2))) (setq-default data-tests-lvar 4) (should-have-watch-data '(data-tests-lvar 4 set nil)) (makunbound 'data-tests-lvar) (should-have-watch-data '(data-tests-lvar nil makunbound nil)) (setq data-tests-lvar 5) (should-have-watch-data `(data-tests-lvar 5 set ,buf1)) (remove-variable-watcher 'data-tests-lvar collect-watch-data) (setq data-tests-lvar 6) (should (null watch-data))))) (ert-deftest data-tests-kill-all-local-variables () ;bug#30846 (with-temp-buffer (setq-local data-tests-foo1 1) (setq-local data-tests-foo2 2) (setq-local data-tests-foo3 3) (let ((oldfoo2 nil)) (add-variable-watcher 'data-tests-foo2 (lambda (&rest _) (setq oldfoo2 (bound-and-true-p data-tests-foo2)))) (kill-all-local-variables) (should (equal oldfoo2 '2)) ;Watcher is run before changing the var. (should (not (or (bound-and-true-p data-tests-foo1) (bound-and-true-p data-tests-foo2) (bound-and-true-p data-tests-foo3))))))) (ert-deftest data-tests-bignum () (should (bignump (+ most-positive-fixnum 1))) (let ((f0 (+ (float most-positive-fixnum) 1)) (f-1 (- (float most-negative-fixnum) 1)) (b0 (+ most-positive-fixnum 1)) (b-1 (- most-negative-fixnum 1))) (should (> b0 -1)) (should (> b0 f-1)) (should (> b0 b-1)) (should (>= b0 -1)) (should (>= b0 f-1)) (should (>= b0 b-1)) (should (>= b-1 b-1)) (should (< -1 b0)) (should (< f-1 b0)) (should (< b-1 b0)) (should (<= -1 b0)) (should (<= f-1 b0)) (should (<= b-1 b0)) (should (<= b-1 b-1)) (should (= (+ f0 b0) (+ b0 f0))) (should (= (+ f0 b-1) (+ b-1 f0))) (should (= (+ f-1 b0) (+ b0 f-1))) (should (= (+ f-1 b-1) (+ b-1 f-1))) (should (= (* f0 b0) (* b0 f0))) (should (= (* f0 b-1) (* b-1 f0))) (should (= (* f-1 b0) (* b0 f-1))) (should (= (* f-1 b-1) (* b-1 f-1))) (should (= b0 f0)) (should (= b0 b0)) (should (/= b0 f-1)) (should (/= b0 b-1)) (should (/= b0 0.0e+NaN)) (should (/= b-1 0.0e+NaN)))) (ert-deftest data-tests-+ () (should-not (fixnump (+ most-positive-fixnum most-positive-fixnum))) (should (> (+ most-positive-fixnum most-positive-fixnum) most-positive-fixnum)) (should (eq (- (+ most-positive-fixnum most-positive-fixnum) (+ most-positive-fixnum most-positive-fixnum)) 0))) (ert-deftest data-tests-/ () (let* ((x (* most-positive-fixnum 8)) (y (* most-negative-fixnum 8)) (z (- y))) (should (= most-positive-fixnum (/ x 8))) (should (= most-negative-fixnum (/ y 8))) (should (= -1 (/ y z))) (should (= -1 (/ z y))) (should (= 0 (/ x (* 2 x)))) (should (= 0 (/ y (* 2 y)))) (should (= 0 (/ z (* 2 z)))))) (ert-deftest data-tests-number-predicates () (should (fixnump 0)) (should (fixnump most-negative-fixnum)) (should (fixnump most-positive-fixnum)) (should (integerp (+ most-positive-fixnum 1))) (should (integer-or-marker-p (+ most-positive-fixnum 1))) (should (numberp (+ most-positive-fixnum 1))) (should (number-or-marker-p (+ most-positive-fixnum 1))) (should (natnump (+ most-positive-fixnum 1))) (should-not (fixnump (+ most-positive-fixnum 1))) (should (bignump (+ most-positive-fixnum 1)))) (ert-deftest data-tests-number-to-string () (let* ((s "99999999999999999999999999999") (v (read s))) (should (equal (number-to-string v) s)))) (ert-deftest data-tests-1+ () (should (> (1+ most-positive-fixnum) most-positive-fixnum)) (should (fixnump (1+ (1- most-negative-fixnum))))) (ert-deftest data-tests-1- () (should (< (1- most-negative-fixnum) most-negative-fixnum)) (should (fixnump (1- (1+ most-positive-fixnum))))) (ert-deftest data-tests-logand () (should (= -1 (logand) (logand -1) (logand -1 -1))) (let ((n (1+ most-positive-fixnum))) (should (= (logand -1 n) n))) (let ((n (* 2 most-negative-fixnum))) (should (= (logand -1 n) n)))) (ert-deftest data-tests-logcount-2 () (should (= (logcount (read "#xffffffffffffffffffffffffffffffff")) 128))) (ert-deftest data-tests-logior () (should (= -1 (logior -1) (logior -1 -1))) (should (= -1 (logior most-positive-fixnum most-negative-fixnum)))) (ert-deftest data-tests-logxor () (should (= -1 (logxor -1) (logxor -1 -1 -1))) (let ((n (1+ most-positive-fixnum))) (should (= (logxor -1 n) (lognot n))))) (ert-deftest data-tests-minmax () (let ((a (- most-negative-fixnum 1)) (b (+ most-positive-fixnum 1)) (c 0)) (should (= (min a b c) a)) (should (= (max a b c) b)))) (defun data-tests-check-sign (x y) (should (eq (cl-signum x) (cl-signum y)))) (ert-deftest data-tests-%-mod () (let* ((b1 (+ most-positive-fixnum 1)) (nb1 (- b1)) (b3 (+ most-positive-fixnum 3)) (nb3 (- b3))) (data-tests-check-sign (% 1 3) (% b1 b3)) (data-tests-check-sign (mod 1 3) (mod b1 b3)) (data-tests-check-sign (% 1 -3) (% b1 nb3)) (data-tests-check-sign (mod 1 -3) (mod b1 nb3)) (data-tests-check-sign (% -1 3) (% nb1 b3)) (data-tests-check-sign (mod -1 3) (mod nb1 b3)) (data-tests-check-sign (% -1 -3) (% nb1 nb3)) (data-tests-check-sign (mod -1 -3) (mod nb1 nb3)))) (ert-deftest data-tests-mod-0 () (dolist (num (list (1- most-negative-fixnum) -1 0 1 (1+ most-positive-fixnum))) (should-error (mod num 0))) (when (ignore-errors (/ 0.0 0)) (should (equal (abs (mod 0.0 0)) (abs (- 0.0 (/ 0.0 0))))))) (ert-deftest data-tests-ash-lsh () (should (= (ash most-negative-fixnum 1) (* most-negative-fixnum 2))) (should (= (ash 0 (* 2 most-positive-fixnum)) 0)) (should (= (ash 1000 (* 2 most-negative-fixnum)) 0)) (should (= (ash -1000 (* 2 most-negative-fixnum)) -1)) (should (= (ash (* 2 most-negative-fixnum) (* 2 most-negative-fixnum)) -1)) (should (= (ash (* 2 most-negative-fixnum) -1) most-negative-fixnum)) (with-suppressed-warnings ((suspicious lsh)) (should (= (lsh most-negative-fixnum 1) (* most-negative-fixnum 2))) (should (= (lsh most-positive-fixnum -1) (/ most-positive-fixnum 2))) (should (= (lsh most-negative-fixnum -1) (lsh (- most-negative-fixnum) -1))) (should (= (lsh -1 -1) most-positive-fixnum)) (should-error (lsh (1- most-negative-fixnum) -1)))) (ert-deftest data-tests-make-local-forwarded-var () ;bug#34318 ;; Boy, this bug is tricky to trigger. You need to: ;; - call make-local-variable on a forwarded var (i.e. one that ;; has a corresponding C var linked via DEFVAR_(LISP|INT|BOOL)) ;; - cause the C code to modify this variable from the C side of the ;; forwarding, but this needs to happen before the var is accessed ;; from the Lisp side and before we switch to another buffer. ;; The trigger in bug#34318 doesn't exist any more because the C code has ;; changed. Instead I found the trigger below. (with-temp-buffer (setq last-coding-system-used 'bug34318) (make-local-variable 'last-coding-system-used) ;; This should set last-coding-system-used to `no-conversion'. (decode-coding-string "hello" nil) (should (equal (list last-coding-system-used (default-value 'last-coding-system-used)) '(no-conversion bug34318))))) (defvar-local data-tests--bug65209 :default-value) (ert-deftest data-tests-make-local-bug65209 () (dolist (sym '(data-tests--bug65209 ;A normal always-local Lisp var. cursor-in-non-selected-windows)) ;Same but DEFVAR_PER_BUFFER. ;; Note: For vars like `mode-name' that are *really* always buffer-local, ;; this test isn't right because the `cl-progv' only binds the ;; buffer-local value! (let ((default (default-value sym)) vli vlo vgi vgo) (with-temp-buffer (cl-progv (list sym) '(:let-bound-value) ;; While `setq' would not make the var buffer-local ;; (because we'd be setq-ing the let-binding instead), ;; `setq-local' definitely should. (set (make-local-variable sym) :buffer-local-value) (setq vgi (with-temp-buffer (symbol-value sym))) (setq vli (symbol-value sym))) (setq vgo (with-temp-buffer (symbol-value sym))) (setq vlo (symbol-value sym))) (should (equal (list vgo vgi vlo vli) (cons default '(:let-bound-value :buffer-local-value :buffer-local-value))))))) (ert-deftest data-tests-make_symbol_constant () "Can't set variable marked with 'make_symbol_constant'." (should-error (setq most-positive-fixnum 1) :type 'setting-constant)) (ert-deftest data-tests-fset () (fset 'data-tests--fs-fun (lambda () 'moo)) (declare-function data-tests--fs-fun nil) (should (equal (data-tests--fs-fun) 'moo)) (fset 'data-tests--fs-fun1 'data-tests--fs-fun) (declare-function data-tests--fs-fun1 nil) (should (equal (data-tests--fs-fun1) 'moo)) (fset 'data-tests--fs-a 'data-tests--fs-b) (fset 'data-tests--fs-b 'data-tests--fs-c) (should-error (fset 'data-tests--fs-c 'data-tests--fs-c) :type 'cyclic-function-indirection) (fset 'data-tests--fs-d 'data-tests--fs-a) (should-error (fset 'data-tests--fs-c 'data-tests--fs-d) :type 'cyclic-function-indirection)) (ert-deftest data-tests-defalias () (defalias 'data-tests--da-fun (lambda () 'baa)) (declare-function data-tests--da-fun nil) (should (equal (data-tests--da-fun) 'baa)) (defalias 'data-tests--da-fun1 'data-tests--da-fun) (declare-function data-tests--da-fun1 nil) (should (equal (data-tests--da-fun1) 'baa)) (defalias 'data-tests--da-a 'data-tests--da-b) (defalias 'data-tests--da-b 'data-tests--da-c) (should-error (defalias 'data-tests--da-c 'data-tests--da-c) :type 'cyclic-function-indirection) (defalias 'data-tests--da-d 'data-tests--da-a) (should-error (defalias 'data-tests--da-c 'data-tests--da-d) :type 'cyclic-function-indirection)) (ert-deftest data-tests-bare-symbol () (dolist (symbols-with-pos-enabled '(nil t)) (dolist (sym (list nil t 'xyzzy (make-symbol ""))) (should (eq sym (bare-symbol (position-symbol sym 0))))))) ;;; data-tests.el ends here