From 4d914ebd2975dc6ce43fb5acba7041ae588d81bb Mon Sep 17 00:00:00 2001 From: Kinneyzhang Date: Fri, 12 Dec 2025 11:17:52 +0800 Subject: [PATCH] update --- tp-ert-tests.el | 697 ------------------------------------------ tp-tests-utils.el | 59 ---- tp-tests.el | 756 +++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 683 insertions(+), 829 deletions(-) delete mode 100644 tp-ert-tests.el delete mode 100644 tp-tests-utils.el diff --git a/tp-ert-tests.el b/tp-ert-tests.el deleted file mode 100644 index e8eb804..0000000 --- a/tp-ert-tests.el +++ /dev/null @@ -1,697 +0,0 @@ -;;; tp-ert-tests.el --- ERT tests for tp.el -*- lexical-binding: t -*- - -;; Copyright (C) 2024 - -;;; Commentary: - -;; Comprehensive test suite for tp.el using ERT (Emacs Lisp Regression Testing). -;; Run with: emacs --batch -l tp.el -l tp-ert-tests.el -f ert-run-tests-batch-and-exit - -;;; Code: - -(require 'ert) -(require 'cl-lib) - -;; Load tp.el from the same directory -(let ((tp-dir (file-name-directory (or load-file-name buffer-file-name)))) - (add-to-list 'load-path tp-dir) - (require 'tp)) - -;;; ============================================================ -;;; Test Utilities -;;; ============================================================ - -(defmacro tp-test-with-temp-buffer (&rest body) - "Execute BODY in a temporary buffer with tp.el loaded." - (declare (indent 0)) - `(with-temp-buffer - (setq tp-layer-alist nil) - (setq tp-layer-groups nil) - ,@body)) - -;;; ============================================================ -;;; Basic Text Property Functions Tests -;;; ============================================================ - -(ert-deftest tp-test-put-and-get () - "Test tp-put and tp-get basic functionality." - (tp-test-with-temp-buffer - (insert "Hello World") - ;; Set a single property - (tp-put 1 6 'face 'bold) - (should (eq (tp-get 1 'face) 'bold)) - (should (eq (tp-get 3 'face) 'bold)) - (should (null (tp-get 7 'face))) - ;; Set multiple properties - (tp-put 7 12 'face 'italic 'help-echo "test") - (should (eq (tp-get 7 'face) 'italic)) - (should (equal (tp-get 7 'help-echo) "test")))) - -(ert-deftest tp-test-put-with-list () - "Test tp-put accepts properties as a list." - (tp-test-with-temp-buffer - (insert "Hello") - (tp-put 1 6 '(face bold help-echo "greeting")) - (should (eq (tp-get 1 'face) 'bold)) - (should (equal (tp-get 1 'help-echo) "greeting")))) - -(ert-deftest tp-test-put-returns-region () - "Test tp-put returns the modified region." - (tp-test-with-temp-buffer - (insert "Hello") - (let ((result (tp-put 1 6 'face 'bold))) - (should (equal result '(1 . 6)))))) - -(ert-deftest tp-test-remove () - "Test tp-remove removes a specific property." - (tp-test-with-temp-buffer - (insert "Hello") - (tp-put 1 6 'face 'bold 'help-echo "test") - (should (eq (tp-get 1 'face) 'bold)) - (tp-remove 1 6 'face) - (should (null (tp-get 1 'face))) - (should (equal (tp-get 1 'help-echo) "test")))) - -(ert-deftest tp-test-remove-list () - "Test tp-remove-list removes multiple properties." - (tp-test-with-temp-buffer - (insert "Hello") - (tp-put 1 6 'face 'bold 'help-echo "test" 'mouse-face 'highlight) - (tp-remove-list 1 6 '(face help-echo)) - (should (null (tp-get 1 'face))) - (should (null (tp-get 1 'help-echo))) - (should (eq (tp-get 1 'mouse-face) 'highlight)))) - -(ert-deftest tp-test-clear () - "Test tp-clear removes all properties." - (tp-test-with-temp-buffer - (insert "Hello World") - (tp-put 1 6 'face 'bold) - (tp-put 7 12 'face 'italic) - (tp-clear 1 12) - (should (null (tp-get 1 'face))) - (should (null (tp-get 7 'face))))) - -(ert-deftest tp-test-clear-defaults-to-buffer () - "Test tp-clear defaults to entire buffer." - (tp-test-with-temp-buffer - (insert "Hello World") - (tp-put 1 12 'face 'bold) - (tp-clear) - (should (null (tp-get 1 'face))) - (should (null (tp-get 7 'face))))) - -(ert-deftest tp-test-at () - "Test tp-at returns all properties at point." - (tp-test-with-temp-buffer - (insert "Hello") - (tp-put 1 6 'face 'bold 'help-echo "test") - (let ((props (tp-at 1))) - (should (eq (plist-get props 'face) 'bold)) - (should (equal (plist-get props 'help-echo) "test"))))) - -(ert-deftest tp-test-at-defaults-to-point () - "Test tp-at defaults to current point." - (tp-test-with-temp-buffer - (insert "Hello") - (tp-put 1 6 'face 'bold) - (goto-char 3) - (should (eq (plist-get (tp-at) 'face) 'bold)))) - -(ert-deftest tp-test-plist () - "Test tp-plist merges properties from region." - (tp-test-with-temp-buffer - (insert "Hello World") - ;; Put both properties on the same overlapping region for proper merging - (tp-put 1 12 'face 'bold) - (tp-put 1 12 'help-echo "test") - (let ((props (tp-plist 1 12))) - (should (eq (plist-get props 'face) 'bold)) - (should (equal (plist-get props 'help-echo) "test"))))) - -;;; ============================================================ -;;; Text Property Interval Tests -;;; ============================================================ - -(ert-deftest tp-test-empty-p () - "Test tp-empty-p detects empty properties." - (should (tp-empty-p "plain string")) - (should-not (tp-empty-p (propertize "styled" 'face 'bold)))) - -(ert-deftest tp-test-intervals () - "Test tp-intervals returns property intervals." - (tp-test-with-temp-buffer - (insert "Hello World") - (tp-put 1 6 'face 'bold) - (tp-put 7 12 'face 'italic) - (let ((intervals (tp-intervals 1 12))) - (should (>= (length intervals) 2))))) - -;;; ============================================================ -;;; Layer Definition Tests -;;; ============================================================ - -(ert-deftest tp-test-layer-define () - "Test tp-layer-define creates a layer." - (tp-test-with-temp-buffer - (tp-layer-define test-layer '(face bold help-echo "test")) - (should (assoc 'test-layer tp-layer-alist)) - (should (equal (cdr (assoc 'test-layer tp-layer-alist)) - '(face bold help-echo "test"))))) - -(ert-deftest tp-test-layer-define-updates-existing () - "Test tp-layer-define updates existing layer." - (tp-test-with-temp-buffer - (tp-layer-define test-layer '(face bold)) - (tp-layer-define test-layer '(face italic)) - (should (equal (cdr (assoc 'test-layer tp-layer-alist)) - '(face italic))))) - -(ert-deftest tp-test-layer-props () - "Test tp-layer-props returns properties with tp-name." - (tp-test-with-temp-buffer - (tp-layer-define my-layer '(face bold)) - (let ((props (tp-layer-props 'my-layer))) - (should (eq (plist-get props 'face) 'bold)) - (should (eq (plist-get props 'tp-name) 'my-layer))))) - -(ert-deftest tp-test-layer-props-returns-nil-for-undefined () - "Test tp-layer-props returns nil for undefined layer." - (tp-test-with-temp-buffer - (should (null (tp-layer-props 'undefined-layer))))) - -(ert-deftest tp-test-layer-undefine () - "Test tp-layer-undefine removes layer definition." - (tp-test-with-temp-buffer - (tp-layer-define test-layer '(face bold)) - (should (assoc 'test-layer tp-layer-alist)) - (tp-layer-undefine 'test-layer) - (should-not (assoc 'test-layer tp-layer-alist)))) - -;;; ============================================================ -;;; Layer Group Tests -;;; ============================================================ - -(ert-deftest tp-test-group-define () - "Test tp-group-define creates a layer group." - (tp-test-with-temp-buffer - (tp-group-define my-group - layer1 '(face bold) - layer2 '(face italic) - layer3 '(face underline)) - (should (assoc 'my-group tp-layer-groups)) - (should (assoc 'layer1 tp-layer-alist)) - (should (assoc 'layer2 tp-layer-alist)) - (should (assoc 'layer3 tp-layer-alist)) - ;; Check all layers are present in the group - (let ((layers (cdr (assoc 'my-group tp-layer-groups)))) - (should (= (length layers) 3)) - (should (memq 'layer1 layers)) - (should (memq 'layer2 layers)) - (should (memq 'layer3 layers))))) - -(ert-deftest tp-test-group-props () - "Test tp-group-props returns all layer properties." - (tp-test-with-temp-buffer - (tp-group-define my-group - layer1 '(face bold) - layer2 '(face italic)) - (let ((props-list (tp-group-props 'my-group))) - (should (= (length props-list) 2)) - ;; Check that both layers are present (order may vary) - (let ((faces (mapcar (lambda (p) (plist-get p 'face)) props-list))) - (should (or (memq 'bold faces) (memq 'italic faces))))))) - -(ert-deftest tp-test-group-undefine () - "Test tp-group-undefine removes group definition." - (tp-test-with-temp-buffer - (tp-group-define my-group - layer1 '(face bold)) - (should (assoc 'my-group tp-layer-groups)) - (tp-group-undefine 'my-group) - (should-not (assoc 'my-group tp-layer-groups)))) - -(ert-deftest tp-test-layer-reset () - "Test tp-layer-reset clears all definitions." - (tp-test-with-temp-buffer - (tp-layer-define layer1 '(face bold)) - (tp-group-define group1 layer2 '(face italic)) - (should tp-layer-alist) - (should tp-layer-groups) - (tp-layer-reset) - (should-not tp-layer-alist) - (should-not tp-layer-groups))) - -;;; ============================================================ -;;; Layer Stack Operations Tests -;;; ============================================================ - -(ert-deftest tp-test-layer-push () - "Test tp-layer-push adds layer to stack." - (tp-test-with-temp-buffer - (insert "Hello") - (tp-layer-define layer1 '(face bold)) - (tp-layer-push 1 6 'layer1) - (should (eq (tp-get 1 'face) 'bold)) - (should (eq (tp-get 1 'tp-name) 'layer1)))) - -(ert-deftest tp-test-layer-push-multiple () - "Test pushing multiple layers." - (tp-test-with-temp-buffer - (insert "Hello") - (tp-layer-define layer1 '(face bold)) - (tp-layer-define layer2 '(face italic)) - (tp-layer-push 1 6 'layer1) - (tp-layer-push 1 6 'layer2) - ;; layer2 should be on top (visible) - (should (eq (tp-get 1 'face) 'italic)) - (should (eq (tp-get 1 'tp-name) 'layer2)) - ;; layer1 should be in the stack below - (should (tp-get 1 'tp-layers)))) - -(ert-deftest tp-test-layer-push-error-on-duplicate () - "Test tp-layer-push errors on duplicate layer." - (tp-test-with-temp-buffer - (insert "Hello") - (tp-layer-define layer1 '(face bold)) - (tp-layer-push 1 6 'layer1) - (should-error (tp-layer-push 1 6 'layer1)))) - -(ert-deftest tp-test-layer-delete () - "Test tp-layer-delete removes layer from stack." - (tp-test-with-temp-buffer - (insert "Hello") - (tp-layer-define layer1 '(face bold)) - (tp-layer-define layer2 '(face italic)) - (tp-layer-push 1 6 'layer1) - (tp-layer-push 1 6 'layer2) - ;; Delete top layer - (tp-layer-delete 1 6 'layer2) - ;; layer1 should now be visible - (should (eq (tp-get 1 'face) 'bold)) - (should (eq (tp-get 1 'tp-name) 'layer1)))) - -(ert-deftest tp-test-layer-delete-from-middle () - "Test deleting layer from middle of stack." - (tp-test-with-temp-buffer - (insert "Hello") - (tp-layer-define layer1 '(face bold)) - (tp-layer-define layer2 '(face italic)) - (tp-layer-define layer3 '(face underline)) - (tp-layer-push 1 6 'layer1) - (tp-layer-push 1 6 'layer2) - (tp-layer-push 1 6 'layer3) - ;; Delete middle layer - (tp-layer-delete 1 6 'layer2) - ;; Top layer should still be visible - (should (eq (tp-get 1 'tp-name) 'layer3)) - ;; layer2 should not exist anymore - (should-not (tp-layer-exists-p 1 6 'layer2)))) - -(ert-deftest tp-test-layer-rotate () - "Test tp-layer-rotate cycles layers." - (tp-test-with-temp-buffer - (insert "Hello") - (tp-layer-define layer1 '(face bold)) - (tp-layer-define layer2 '(face italic)) - (tp-layer-define layer3 '(face underline)) - (tp-layer-push 1 6 'layer1) - (tp-layer-push 1 6 'layer2) - (tp-layer-push 1 6 'layer3) - ;; layer3 is on top - (should (eq (tp-layer-top 1 6) 'layer3)) - ;; Rotate once - layer2 should be on top - (tp-layer-rotate 1 6) - (should (eq (tp-layer-top 1 6) 'layer2)) - ;; Rotate again - layer1 should be on top - (tp-layer-rotate 1 6) - (should (eq (tp-layer-top 1 6) 'layer1)) - ;; Rotate again - layer3 should be on top (cycled back) - (tp-layer-rotate 1 6) - (should (eq (tp-layer-top 1 6) 'layer3)))) - -(ert-deftest tp-test-layer-pin () - "Test tp-layer-pin brings layer to top." - (tp-test-with-temp-buffer - (insert "Hello") - (tp-layer-define layer1 '(face bold)) - (tp-layer-define layer2 '(face italic)) - (tp-layer-define layer3 '(face underline)) - (tp-layer-push 1 6 'layer1) - (tp-layer-push 1 6 'layer2) - (tp-layer-push 1 6 'layer3) - ;; Pin layer1 to top - (tp-layer-pin 1 6 'layer1) - (should (eq (tp-layer-top 1 6) 'layer1)))) - -(ert-deftest tp-test-layer-pin-error-on-nonexistent () - "Test tp-layer-pin errors on nonexistent layer." - (tp-test-with-temp-buffer - (insert "Hello") - (tp-layer-define layer1 '(face bold)) - (tp-layer-push 1 6 'layer1) - (should-error (tp-layer-pin 1 6 'nonexistent)))) - -(ert-deftest tp-test-layer-hide () - "Test tp-layer-hide moves layer to bottom." - (tp-test-with-temp-buffer - (insert "Hello") - (tp-layer-define layer1 '(face bold)) - (tp-layer-define layer2 '(face italic)) - (tp-layer-push 1 6 'layer1) - (tp-layer-push 1 6 'layer2) - ;; layer2 is on top - (should (eq (tp-layer-top 1 6) 'layer2)) - ;; Hide layer2 - (tp-layer-hide 1 6 'layer2) - ;; layer1 should now be on top - (should (eq (tp-layer-top 1 6) 'layer1)))) - -(ert-deftest tp-test-layer-show () - "Test tp-layer-show brings layer to top." - (tp-test-with-temp-buffer - (insert "Hello") - (tp-layer-define layer1 '(face bold)) - (tp-layer-define layer2 '(face italic)) - (tp-layer-push 1 6 'layer1) - (tp-layer-push 1 6 'layer2) - ;; Hide layer2 - (tp-layer-hide 1 6 'layer2) - (should (eq (tp-layer-top 1 6) 'layer1)) - ;; Show layer2 again - (tp-layer-show 1 6 'layer2) - (should (eq (tp-layer-top 1 6) 'layer2)))) - -;;; ============================================================ -;;; Layer Query Tests -;;; ============================================================ - -(ert-deftest tp-test-layer-list () - "Test tp-layer-list returns all layer names." - (tp-test-with-temp-buffer - (insert "Hello") - (tp-layer-define layer1 '(face bold)) - (tp-layer-define layer2 '(face italic)) - (tp-layer-define layer3 '(face underline)) - (tp-layer-push 1 6 'layer1) - (tp-layer-push 1 6 'layer2) - (tp-layer-push 1 6 'layer3) - (let ((layers (tp-layer-list 1 6))) - (should (= (length layers) 3)) - (should (memq 'layer1 layers)) - (should (memq 'layer2 layers)) - (should (memq 'layer3 layers))))) - -(ert-deftest tp-test-layer-count () - "Test tp-layer-count returns correct count." - (tp-test-with-temp-buffer - (insert "Hello") - (tp-layer-define layer1 '(face bold)) - (tp-layer-define layer2 '(face italic)) - (tp-layer-push 1 6 'layer1) - (should (= (tp-layer-count 1 6) 1)) - (tp-layer-push 1 6 'layer2) - (should (= (tp-layer-count 1 6) 2)))) - -(ert-deftest tp-test-layer-exists-p () - "Test tp-layer-exists-p correctly detects layers." - (tp-test-with-temp-buffer - (insert "Hello") - (tp-layer-define layer1 '(face bold)) - (tp-layer-push 1 6 'layer1) - (should (tp-layer-exists-p 1 6 'layer1)) - (should-not (tp-layer-exists-p 1 6 'layer2)))) - -(ert-deftest tp-test-layer-top () - "Test tp-layer-top returns top layer name." - (tp-test-with-temp-buffer - (insert "Hello") - (tp-layer-define layer1 '(face bold)) - (tp-layer-define layer2 '(face italic)) - (tp-layer-push 1 6 'layer1) - (should (eq (tp-layer-top 1 6) 'layer1)) - (tp-layer-push 1 6 'layer2) - (should (eq (tp-layer-top 1 6) 'layer2)))) - -;;; ============================================================ -;;; Propertize String Tests -;;; ============================================================ - -(ert-deftest tp-test-propertize () - "Test tp-propertize adds properties to string." - (let ((str (tp-propertize "Hello" 'face 'bold))) - (should (eq (get-text-property 0 'face str) 'bold)))) - -(ert-deftest tp-test-propertize-with-list () - "Test tp-propertize accepts properties as list." - (let ((str (tp-propertize "Hello" '(face bold help-echo "test")))) - (should (eq (get-text-property 0 'face str) 'bold)) - (should (equal (get-text-property 0 'help-echo str) "test")))) - -(ert-deftest tp-test-layer-propertize () - "Test tp-layer-propertize applies layer to string." - (tp-test-with-temp-buffer - (tp-layer-define my-layer '(face bold help-echo "greeting")) - (let ((str (tp-layer-propertize "Hello" 'my-layer))) - (should (eq (get-text-property 0 'face str) 'bold)) - (should (equal (get-text-property 0 'help-echo str) "greeting"))))) - -(ert-deftest tp-test-layer-propertize-error-on-undefined () - "Test tp-layer-propertize errors on undefined layer." - (tp-test-with-temp-buffer - (should-error (tp-layer-propertize "Hello" 'undefined-layer)))) - -(ert-deftest tp-test-group-propertize () - "Test tp-group-propertize applies group to string." - (tp-test-with-temp-buffer - (tp-group-define my-group - layer1 '(face bold) - layer2 '(help-echo "test")) - (let ((str (tp-group-propertize "Hello" 'my-group))) - (should (stringp str)) - (should (= (length str) 5))))) - -(ert-deftest tp-test-group-propertize-error-on-undefined () - "Test tp-group-propertize errors on undefined group." - (tp-test-with-temp-buffer - (should-error (tp-group-propertize "Hello" 'undefined-group)))) - -;;; ============================================================ -;;; Match and Regexp Tests -;;; ============================================================ - -(ert-deftest tp-test-match () - "Test tp-match sets properties on string matches." - (tp-test-with-temp-buffer - (insert "Hello World Hello") - (let ((regions (tp-match "Hello" 'face 'bold))) - (should (= (length regions) 2)) - (should (eq (tp-get 1 'face) 'bold)) - (should (eq (tp-get 13 'face) 'bold))))) - -(ert-deftest tp-test-match-returns-regions () - "Test tp-match returns correct region pairs." - (tp-test-with-temp-buffer - (insert "Hello World Hello") - (let ((regions (tp-match "Hello"))) - (should (= (length regions) 2)) - (should (equal (car regions) '(1 . 6))) - (should (equal (cadr regions) '(13 . 18)))))) - -(ert-deftest tp-test-regexp () - "Test tp-regexp sets properties on regexp matches." - (tp-test-with-temp-buffer - (insert "abc 123 def 456") - (let ((regions (tp-regexp "[0-9]+" 'face 'bold))) - (should (= (length regions) 2)) - (should (eq (tp-get 5 'face) 'bold)) - (should (eq (tp-get 13 'face) 'bold))))) - -(ert-deftest tp-test-regexp-returns-regions () - "Test tp-regexp returns correct region pairs." - (tp-test-with-temp-buffer - (insert "abc 123 def 456") - (let ((regions (tp-regexp "[0-9]+"))) - (should (= (length regions) 2))))) - -;;; ============================================================ -;;; Search and Navigation Tests -;;; ============================================================ - -(ert-deftest tp-test-forward () - "Test tp-forward finds next property." - (tp-test-with-temp-buffer - (insert "Hello World") - (tp-put 7 12 'face 'bold) - (goto-char 1) - ;; text-property-search-forward may not exist in all Emacs versions - (skip-unless (fboundp 'text-property-search-forward)) - (let ((match (tp-forward 'face))) - (should match) - (should (= (prop-match-beginning match) 7))))) - -(ert-deftest tp-test-backward () - "Test tp-backward finds previous property." - (tp-test-with-temp-buffer - (insert "Hello World") - (tp-put 1 6 'face 'bold) - (goto-char 12) - ;; text-property-search-backward may not exist in all Emacs versions - ;; Skip test if function is not available - (skip-unless (fboundp 'text-property-search-backward)) - (let ((match (tp-backward 'face))) - (should match) - (should (= (prop-match-beginning match) 1))))) - -(ert-deftest tp-test-next () - "Test tp-next returns next position with property." - (tp-test-with-temp-buffer - (insert "Hello World") - (tp-put 7 12 'face 'bold) - (let ((pos (tp-next 1 'face))) - (should (= pos 7))))) - -(ert-deftest tp-test-prev () - "Test tp-prev returns previous position with property." - (tp-test-with-temp-buffer - (insert "Hello World") - (tp-put 1 6 'face 'bold) - (let ((pos (tp-prev 12 'face))) - (should (= pos 1))))) - -(ert-deftest tp-test-goto-next () - "Test tp-goto-next moves point." - (tp-test-with-temp-buffer - (insert "Hello World") - (tp-put 7 12 'face 'bold) - (goto-char 1) - (tp-goto-next 'face) - (should (= (point) 7)))) - -(ert-deftest tp-test-goto-prev () - "Test tp-goto-prev moves point." - (tp-test-with-temp-buffer - (insert "Hello World") - (tp-put 1 6 'face 'bold) - (goto-char 12) - (tp-goto-prev 'face) - (should (= (point) 1)))) - -;;; ============================================================ -;;; Utility Function Tests -;;; ============================================================ - -(ert-deftest tp-test-in () - "Test tp-in finds regions with property." - (tp-test-with-temp-buffer - (insert "Hello World Test") - (tp-put 1 6 'my-prop 'value1) - (tp-put 7 12 'my-prop 'value2) - (let ((regions (tp-in 'my-prop))) - (should (= (length regions) 2))))) - -(ert-deftest tp-test-in-with-value () - "Test tp-in filters by value." - (tp-test-with-temp-buffer - (insert "Hello World Test") - (tp-put 1 6 'my-prop 'value1) - (tp-put 7 12 'my-prop 'value2) - (let ((regions (tp-in 'my-prop 'value1))) - (should (= (length regions) 1)) - (should (equal (car (car regions)) 1))))) - -(ert-deftest tp-test-all () - "Test tp-all returns all regions with properties." - (tp-test-with-temp-buffer - (insert "Hello World") - (tp-put 1 6 'face 'bold) - (tp-put 7 12 'face 'italic) - (let ((regions (tp-all))) - (should (>= (length regions) 2))))) - -(ert-deftest tp-test-regions-map () - "Test tp-regions-map applies function to regions." - (tp-test-with-temp-buffer - (insert "Hello World Hello") - (tp-put 1 6 'marker t) - (tp-put 13 18 'marker t) - (let ((result nil)) - (tp-regions-map - (lambda (start end idx) - (push (list start end idx) result)) - 'marker) - (should (= (length result) 2))))) - -(ert-deftest tp-test-strings-map () - "Test tp-strings-map applies function to strings." - (tp-test-with-temp-buffer - (insert "Hello World Hello") - (tp-put 1 6 'marker t) - (tp-put 13 18 'marker t) - (let ((result nil)) - (tp-strings-map - (lambda (str idx) - (push str result)) - 'marker) - (should (= (length result) 2)) - (should (member "Hello" result))))) - -;;; ============================================================ -;;; Alias Tests -;;; ============================================================ - -(ert-deftest tp-test-aliases-exist () - "Test that all aliases are properly defined." - (should (fboundp 'tp-set)) - (should (fboundp 'tp-layer-properties)) - (should (fboundp 'tp-layer-group-define)) - (should (fboundp 'tp-layer-group-properties)) - (should (fboundp 'tp-layer-group-propertize)) - (should (fboundp 'tp-layer-group-undefine))) - -(ert-deftest tp-test-aliases-work () - "Test that aliases work correctly." - (tp-test-with-temp-buffer - ;; Test tp-set alias - (insert "Hello") - (tp-set 1 6 'face 'bold) - (should (eq (tp-get 1 'face) 'bold)))) - -;;; ============================================================ -;;; Edge Case Tests -;;; ============================================================ - -(ert-deftest tp-test-empty-region () - "Test operations on empty buffer." - (tp-test-with-temp-buffer - (should (null (tp-at 1))) - (should (null (tp-all))))) - -(ert-deftest tp-test-overlapping-regions () - "Test overlapping property regions." - (tp-test-with-temp-buffer - (insert "Hello World") - (tp-put 1 8 'prop1 'val1) - (tp-put 5 12 'prop2 'val2) - (should (eq (tp-get 1 'prop1) 'val1)) - (should (null (tp-get 1 'prop2))) - (should (eq (tp-get 6 'prop1) 'val1)) - (should (eq (tp-get 6 'prop2) 'val2)) - (should (null (tp-get 10 'prop1))) - (should (eq (tp-get 10 'prop2) 'val2)))) - -(ert-deftest tp-test-single-char-region () - "Test operations on single character." - (tp-test-with-temp-buffer - (insert "H") - (tp-put 1 2 'face 'bold) - (should (eq (tp-get 1 'face) 'bold)))) - -(ert-deftest tp-test-layer-on-string () - "Test layer operations on string object." - (let ((str (copy-sequence "Hello"))) - (set-text-properties 0 5 nil str) - (should (tp-empty-p str)))) - -(provide 'tp-ert-tests) -;;; tp-ert-tests.el ends here diff --git a/tp-tests-utils.el b/tp-tests-utils.el deleted file mode 100644 index 7c484a3..0000000 --- a/tp-tests-utils.el +++ /dev/null @@ -1,59 +0,0 @@ -(defvar pop-buffer-insert-buffer - "*pop-buffer-insert*") - -(defvar pop-buffer-win-conf nil) - -(defun my-pop-to-buffer (buffer-or-name &optional action norecord) - (declare (indent defun)) - (let ((buffer (pop-to-buffer buffer-or-name action norecord))) - (with-current-buffer buffer - (local-set-key "q" 'pop-buffer-quit)) - buffer)) - -(defun remove-from-list (list-var element) - (set list-var (delete element (symbol-value list-var)))) - -(defun pop-buffer-quit () - (interactive) - (let ((win-conf pop-buffer-win-conf)) - (local-unset-key "q") - (setq-local pop-buffer-win-conf nil) - (remove-from-list 'margin-work-modes 'quick-buffer-mode) - (set-window-configuration win-conf))) - -(defmacro with-pop-buffer (buffer-or-name height &rest body) - (declare (indent defun)) - `(let* ((win-conf (current-window-configuration)) - (height ,height) - (buffer (my-pop-to-buffer ,buffer-or-name - `(,@(if height - `(display-buffer-at-bottom - (cons window-height height)) - `(display-buffer-full-frame)))))) - (add-to-list 'margin-work-modes 'quick-buffer-mode) - (with-current-buffer buffer - (setq major-mode 'quick-buffer-mode) - (setq-local pop-buffer-win-conf win-conf) - (let ((inhibit-read-only t)) - (erase-buffer) - ,@body) - (read-only-mode 1)))) - -(defun pop-buffer-insert (height &rest body) - (declare (indent defun)) - (if (member pop-buffer-insert-buffer - (mapcar #'buffer-name (window-buffers))) - (let ((inhibit-read-only t)) - (select-window (get-buffer-window - pop-buffer-insert-buffer)) - (erase-buffer) - (apply #'insert body)) - (with-pop-buffer pop-buffer-insert-buffer height - (apply #'insert body)))) - -(defmacro pop-buffer-do (height &rest body) - (declare (indent defun)) - `(with-pop-buffer ,pop-buffer-insert-buffer ,height - ,@body)) - -(provide 'tp-tests-utils) diff --git a/tp-tests.el b/tp-tests.el index acad0fd..e8eb804 100644 --- a/tp-tests.el +++ b/tp-tests.el @@ -1,87 +1,697 @@ -(require 'tp-tests-utils) +;;; tp-ert-tests.el --- ERT tests for tp.el -*- lexical-binding: t -*- -;; tp-layer-alist -;; tp-layer-groups +;; Copyright (C) 2024 -(tp-layer-define test1 - '(face link :foreground "orange")) +;;; Commentary: -(tp-layer-define test2 - '(face link :foreground "cyan")) +;; Comprehensive test suite for tp.el using ERT (Emacs Lisp Regression Testing). +;; Run with: emacs --batch -l tp.el -l tp-ert-tests.el -f ert-run-tests-batch-and-exit -(tp-layer-group-define test-group - test1 '( display "this is top layer" - face (:background "red" :foreground "#000")) - test2 '( display "this is middle layer" - face (:background "green" :foreground "#000")) - test3 '( display "this is bottom layer" - face (:background "cyan" :foreground "#000"))) +;;; Code: -(setq tp-layer-alist nil) -(setq tp-layer-groups nil) +(require 'ert) +(require 'cl-lib) -(tp-layer-propertize "emacs" 'test1) -(tp-layer-group-propertize "emacs" 'test-group) +;; Load tp.el from the same directory +(let ((tp-dir (file-name-directory (or load-file-name buffer-file-name)))) + (add-to-list 'load-path tp-dir) + (require 'tp)) -(defun tp-tests-layer-rotate (&optional btn) - (interactive) - (let ((inhibit-read-only t)) - (save-excursion - (goto-char (point-min)) - (tp-layer-rotate (line-beginning-position) - (line-end-position))))) +;;; ============================================================ +;;; Test Utilities +;;; ============================================================ -(pop-buffer-do nil - (insert (tp-layer-group-propertize "emacs" 'test-group) - "\n\n") - (insert-text-button - " eval (tp-tests-layer-rotate) " - 'action 'tp-tests-layer-rotate - 'face '(:box t) - 'follow-link t)) +(defmacro tp-test-with-temp-buffer (&rest body) + "Execute BODY in a temporary buffer with tp.el loaded." + (declare (indent 0)) + `(with-temp-buffer + (setq tp-layer-alist nil) + (setq tp-layer-groups nil) + ,@body)) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; ============================================================ +;;; Basic Text Property Functions Tests +;;; ============================================================ -(pop-buffer-insert nil - (propertize - " " - 'display "" - 'face '(:underline (:position t :color "grey"))) - " " - (propertize - "hacking" - 'face '(:foreground "cyan")) - " " - (propertize - "emacs" - 'face '(:slant italic :background "orange"))) +(ert-deftest tp-test-put-and-get () + "Test tp-put and tp-get basic functionality." + (tp-test-with-temp-buffer + (insert "Hello World") + ;; Set a single property + (tp-put 1 6 'face 'bold) + (should (eq (tp-get 1 'face) 'bold)) + (should (eq (tp-get 3 'face) 'bold)) + (should (null (tp-get 7 'face))) + ;; Set multiple properties + (tp-put 7 12 'face 'italic 'help-echo "test") + (should (eq (tp-get 7 'face) 'italic)) + (should (equal (tp-get 7 'help-echo) "test")))) -(with-current-buffer pop-buffer-insert-buffer - (erase-buffer) - (tp-tests-run)) +(ert-deftest tp-test-put-with-list () + "Test tp-put accepts properties as a list." + (tp-test-with-temp-buffer + (insert "Hello") + (tp-put 1 6 '(face bold help-echo "greeting")) + (should (eq (tp-get 1 'face) 'bold)) + (should (equal (tp-get 1 'help-echo) "greeting")))) -(with-current-buffer pop-buffer-insert-buffer - (let ((inhibit-read-only 1)) - ;; (tp-all (point-min) (point-max)) - (tp-layer-set 'default (point-min) (point-max)) - (tp-layer-push 1 - (point-min) (point-max) - '( face (:background "green" :foreground "grey") - display (height 1.2))) - - (tp-layer-push 2 - (point-min) (point-max) - '(face (:background "orange" :foreground "#000"))) +(ert-deftest tp-test-put-returns-region () + "Test tp-put returns the modified region." + (tp-test-with-temp-buffer + (insert "Hello") + (let ((result (tp-put 1 6 'face 'bold))) + (should (equal result '(1 . 6)))))) - (tp-layer-push 3 - (point-min) (point-max) - '(face (:weight bold :background "SlateBlue2"))))) +(ert-deftest tp-test-remove () + "Test tp-remove removes a specific property." + (tp-test-with-temp-buffer + (insert "Hello") + (tp-put 1 6 'face 'bold 'help-echo "test") + (should (eq (tp-get 1 'face) 'bold)) + (tp-remove 1 6 'face) + (should (null (tp-get 1 'face))) + (should (equal (tp-get 1 'help-echo) "test")))) -(with-current-buffer pop-buffer-insert-buffer - (let ((inhibit-read-only 1)) - ;; (tp-layer-demote (point-min) (point-max)) - ;; (tp-layer-rotate (point-min) (point-max)) - ;; (tp-layer-delete 2 (point-min) (point-max)) - ;; (tp-layer-pin 1 (point-min) (point-max)) - ;; (tp-layer-pin '3 1 16) - )) +(ert-deftest tp-test-remove-list () + "Test tp-remove-list removes multiple properties." + (tp-test-with-temp-buffer + (insert "Hello") + (tp-put 1 6 'face 'bold 'help-echo "test" 'mouse-face 'highlight) + (tp-remove-list 1 6 '(face help-echo)) + (should (null (tp-get 1 'face))) + (should (null (tp-get 1 'help-echo))) + (should (eq (tp-get 1 'mouse-face) 'highlight)))) + +(ert-deftest tp-test-clear () + "Test tp-clear removes all properties." + (tp-test-with-temp-buffer + (insert "Hello World") + (tp-put 1 6 'face 'bold) + (tp-put 7 12 'face 'italic) + (tp-clear 1 12) + (should (null (tp-get 1 'face))) + (should (null (tp-get 7 'face))))) + +(ert-deftest tp-test-clear-defaults-to-buffer () + "Test tp-clear defaults to entire buffer." + (tp-test-with-temp-buffer + (insert "Hello World") + (tp-put 1 12 'face 'bold) + (tp-clear) + (should (null (tp-get 1 'face))) + (should (null (tp-get 7 'face))))) + +(ert-deftest tp-test-at () + "Test tp-at returns all properties at point." + (tp-test-with-temp-buffer + (insert "Hello") + (tp-put 1 6 'face 'bold 'help-echo "test") + (let ((props (tp-at 1))) + (should (eq (plist-get props 'face) 'bold)) + (should (equal (plist-get props 'help-echo) "test"))))) + +(ert-deftest tp-test-at-defaults-to-point () + "Test tp-at defaults to current point." + (tp-test-with-temp-buffer + (insert "Hello") + (tp-put 1 6 'face 'bold) + (goto-char 3) + (should (eq (plist-get (tp-at) 'face) 'bold)))) + +(ert-deftest tp-test-plist () + "Test tp-plist merges properties from region." + (tp-test-with-temp-buffer + (insert "Hello World") + ;; Put both properties on the same overlapping region for proper merging + (tp-put 1 12 'face 'bold) + (tp-put 1 12 'help-echo "test") + (let ((props (tp-plist 1 12))) + (should (eq (plist-get props 'face) 'bold)) + (should (equal (plist-get props 'help-echo) "test"))))) + +;;; ============================================================ +;;; Text Property Interval Tests +;;; ============================================================ + +(ert-deftest tp-test-empty-p () + "Test tp-empty-p detects empty properties." + (should (tp-empty-p "plain string")) + (should-not (tp-empty-p (propertize "styled" 'face 'bold)))) + +(ert-deftest tp-test-intervals () + "Test tp-intervals returns property intervals." + (tp-test-with-temp-buffer + (insert "Hello World") + (tp-put 1 6 'face 'bold) + (tp-put 7 12 'face 'italic) + (let ((intervals (tp-intervals 1 12))) + (should (>= (length intervals) 2))))) + +;;; ============================================================ +;;; Layer Definition Tests +;;; ============================================================ + +(ert-deftest tp-test-layer-define () + "Test tp-layer-define creates a layer." + (tp-test-with-temp-buffer + (tp-layer-define test-layer '(face bold help-echo "test")) + (should (assoc 'test-layer tp-layer-alist)) + (should (equal (cdr (assoc 'test-layer tp-layer-alist)) + '(face bold help-echo "test"))))) + +(ert-deftest tp-test-layer-define-updates-existing () + "Test tp-layer-define updates existing layer." + (tp-test-with-temp-buffer + (tp-layer-define test-layer '(face bold)) + (tp-layer-define test-layer '(face italic)) + (should (equal (cdr (assoc 'test-layer tp-layer-alist)) + '(face italic))))) + +(ert-deftest tp-test-layer-props () + "Test tp-layer-props returns properties with tp-name." + (tp-test-with-temp-buffer + (tp-layer-define my-layer '(face bold)) + (let ((props (tp-layer-props 'my-layer))) + (should (eq (plist-get props 'face) 'bold)) + (should (eq (plist-get props 'tp-name) 'my-layer))))) + +(ert-deftest tp-test-layer-props-returns-nil-for-undefined () + "Test tp-layer-props returns nil for undefined layer." + (tp-test-with-temp-buffer + (should (null (tp-layer-props 'undefined-layer))))) + +(ert-deftest tp-test-layer-undefine () + "Test tp-layer-undefine removes layer definition." + (tp-test-with-temp-buffer + (tp-layer-define test-layer '(face bold)) + (should (assoc 'test-layer tp-layer-alist)) + (tp-layer-undefine 'test-layer) + (should-not (assoc 'test-layer tp-layer-alist)))) + +;;; ============================================================ +;;; Layer Group Tests +;;; ============================================================ + +(ert-deftest tp-test-group-define () + "Test tp-group-define creates a layer group." + (tp-test-with-temp-buffer + (tp-group-define my-group + layer1 '(face bold) + layer2 '(face italic) + layer3 '(face underline)) + (should (assoc 'my-group tp-layer-groups)) + (should (assoc 'layer1 tp-layer-alist)) + (should (assoc 'layer2 tp-layer-alist)) + (should (assoc 'layer3 tp-layer-alist)) + ;; Check all layers are present in the group + (let ((layers (cdr (assoc 'my-group tp-layer-groups)))) + (should (= (length layers) 3)) + (should (memq 'layer1 layers)) + (should (memq 'layer2 layers)) + (should (memq 'layer3 layers))))) + +(ert-deftest tp-test-group-props () + "Test tp-group-props returns all layer properties." + (tp-test-with-temp-buffer + (tp-group-define my-group + layer1 '(face bold) + layer2 '(face italic)) + (let ((props-list (tp-group-props 'my-group))) + (should (= (length props-list) 2)) + ;; Check that both layers are present (order may vary) + (let ((faces (mapcar (lambda (p) (plist-get p 'face)) props-list))) + (should (or (memq 'bold faces) (memq 'italic faces))))))) + +(ert-deftest tp-test-group-undefine () + "Test tp-group-undefine removes group definition." + (tp-test-with-temp-buffer + (tp-group-define my-group + layer1 '(face bold)) + (should (assoc 'my-group tp-layer-groups)) + (tp-group-undefine 'my-group) + (should-not (assoc 'my-group tp-layer-groups)))) + +(ert-deftest tp-test-layer-reset () + "Test tp-layer-reset clears all definitions." + (tp-test-with-temp-buffer + (tp-layer-define layer1 '(face bold)) + (tp-group-define group1 layer2 '(face italic)) + (should tp-layer-alist) + (should tp-layer-groups) + (tp-layer-reset) + (should-not tp-layer-alist) + (should-not tp-layer-groups))) + +;;; ============================================================ +;;; Layer Stack Operations Tests +;;; ============================================================ + +(ert-deftest tp-test-layer-push () + "Test tp-layer-push adds layer to stack." + (tp-test-with-temp-buffer + (insert "Hello") + (tp-layer-define layer1 '(face bold)) + (tp-layer-push 1 6 'layer1) + (should (eq (tp-get 1 'face) 'bold)) + (should (eq (tp-get 1 'tp-name) 'layer1)))) + +(ert-deftest tp-test-layer-push-multiple () + "Test pushing multiple layers." + (tp-test-with-temp-buffer + (insert "Hello") + (tp-layer-define layer1 '(face bold)) + (tp-layer-define layer2 '(face italic)) + (tp-layer-push 1 6 'layer1) + (tp-layer-push 1 6 'layer2) + ;; layer2 should be on top (visible) + (should (eq (tp-get 1 'face) 'italic)) + (should (eq (tp-get 1 'tp-name) 'layer2)) + ;; layer1 should be in the stack below + (should (tp-get 1 'tp-layers)))) + +(ert-deftest tp-test-layer-push-error-on-duplicate () + "Test tp-layer-push errors on duplicate layer." + (tp-test-with-temp-buffer + (insert "Hello") + (tp-layer-define layer1 '(face bold)) + (tp-layer-push 1 6 'layer1) + (should-error (tp-layer-push 1 6 'layer1)))) + +(ert-deftest tp-test-layer-delete () + "Test tp-layer-delete removes layer from stack." + (tp-test-with-temp-buffer + (insert "Hello") + (tp-layer-define layer1 '(face bold)) + (tp-layer-define layer2 '(face italic)) + (tp-layer-push 1 6 'layer1) + (tp-layer-push 1 6 'layer2) + ;; Delete top layer + (tp-layer-delete 1 6 'layer2) + ;; layer1 should now be visible + (should (eq (tp-get 1 'face) 'bold)) + (should (eq (tp-get 1 'tp-name) 'layer1)))) + +(ert-deftest tp-test-layer-delete-from-middle () + "Test deleting layer from middle of stack." + (tp-test-with-temp-buffer + (insert "Hello") + (tp-layer-define layer1 '(face bold)) + (tp-layer-define layer2 '(face italic)) + (tp-layer-define layer3 '(face underline)) + (tp-layer-push 1 6 'layer1) + (tp-layer-push 1 6 'layer2) + (tp-layer-push 1 6 'layer3) + ;; Delete middle layer + (tp-layer-delete 1 6 'layer2) + ;; Top layer should still be visible + (should (eq (tp-get 1 'tp-name) 'layer3)) + ;; layer2 should not exist anymore + (should-not (tp-layer-exists-p 1 6 'layer2)))) + +(ert-deftest tp-test-layer-rotate () + "Test tp-layer-rotate cycles layers." + (tp-test-with-temp-buffer + (insert "Hello") + (tp-layer-define layer1 '(face bold)) + (tp-layer-define layer2 '(face italic)) + (tp-layer-define layer3 '(face underline)) + (tp-layer-push 1 6 'layer1) + (tp-layer-push 1 6 'layer2) + (tp-layer-push 1 6 'layer3) + ;; layer3 is on top + (should (eq (tp-layer-top 1 6) 'layer3)) + ;; Rotate once - layer2 should be on top + (tp-layer-rotate 1 6) + (should (eq (tp-layer-top 1 6) 'layer2)) + ;; Rotate again - layer1 should be on top + (tp-layer-rotate 1 6) + (should (eq (tp-layer-top 1 6) 'layer1)) + ;; Rotate again - layer3 should be on top (cycled back) + (tp-layer-rotate 1 6) + (should (eq (tp-layer-top 1 6) 'layer3)))) + +(ert-deftest tp-test-layer-pin () + "Test tp-layer-pin brings layer to top." + (tp-test-with-temp-buffer + (insert "Hello") + (tp-layer-define layer1 '(face bold)) + (tp-layer-define layer2 '(face italic)) + (tp-layer-define layer3 '(face underline)) + (tp-layer-push 1 6 'layer1) + (tp-layer-push 1 6 'layer2) + (tp-layer-push 1 6 'layer3) + ;; Pin layer1 to top + (tp-layer-pin 1 6 'layer1) + (should (eq (tp-layer-top 1 6) 'layer1)))) + +(ert-deftest tp-test-layer-pin-error-on-nonexistent () + "Test tp-layer-pin errors on nonexistent layer." + (tp-test-with-temp-buffer + (insert "Hello") + (tp-layer-define layer1 '(face bold)) + (tp-layer-push 1 6 'layer1) + (should-error (tp-layer-pin 1 6 'nonexistent)))) + +(ert-deftest tp-test-layer-hide () + "Test tp-layer-hide moves layer to bottom." + (tp-test-with-temp-buffer + (insert "Hello") + (tp-layer-define layer1 '(face bold)) + (tp-layer-define layer2 '(face italic)) + (tp-layer-push 1 6 'layer1) + (tp-layer-push 1 6 'layer2) + ;; layer2 is on top + (should (eq (tp-layer-top 1 6) 'layer2)) + ;; Hide layer2 + (tp-layer-hide 1 6 'layer2) + ;; layer1 should now be on top + (should (eq (tp-layer-top 1 6) 'layer1)))) + +(ert-deftest tp-test-layer-show () + "Test tp-layer-show brings layer to top." + (tp-test-with-temp-buffer + (insert "Hello") + (tp-layer-define layer1 '(face bold)) + (tp-layer-define layer2 '(face italic)) + (tp-layer-push 1 6 'layer1) + (tp-layer-push 1 6 'layer2) + ;; Hide layer2 + (tp-layer-hide 1 6 'layer2) + (should (eq (tp-layer-top 1 6) 'layer1)) + ;; Show layer2 again + (tp-layer-show 1 6 'layer2) + (should (eq (tp-layer-top 1 6) 'layer2)))) + +;;; ============================================================ +;;; Layer Query Tests +;;; ============================================================ + +(ert-deftest tp-test-layer-list () + "Test tp-layer-list returns all layer names." + (tp-test-with-temp-buffer + (insert "Hello") + (tp-layer-define layer1 '(face bold)) + (tp-layer-define layer2 '(face italic)) + (tp-layer-define layer3 '(face underline)) + (tp-layer-push 1 6 'layer1) + (tp-layer-push 1 6 'layer2) + (tp-layer-push 1 6 'layer3) + (let ((layers (tp-layer-list 1 6))) + (should (= (length layers) 3)) + (should (memq 'layer1 layers)) + (should (memq 'layer2 layers)) + (should (memq 'layer3 layers))))) + +(ert-deftest tp-test-layer-count () + "Test tp-layer-count returns correct count." + (tp-test-with-temp-buffer + (insert "Hello") + (tp-layer-define layer1 '(face bold)) + (tp-layer-define layer2 '(face italic)) + (tp-layer-push 1 6 'layer1) + (should (= (tp-layer-count 1 6) 1)) + (tp-layer-push 1 6 'layer2) + (should (= (tp-layer-count 1 6) 2)))) + +(ert-deftest tp-test-layer-exists-p () + "Test tp-layer-exists-p correctly detects layers." + (tp-test-with-temp-buffer + (insert "Hello") + (tp-layer-define layer1 '(face bold)) + (tp-layer-push 1 6 'layer1) + (should (tp-layer-exists-p 1 6 'layer1)) + (should-not (tp-layer-exists-p 1 6 'layer2)))) + +(ert-deftest tp-test-layer-top () + "Test tp-layer-top returns top layer name." + (tp-test-with-temp-buffer + (insert "Hello") + (tp-layer-define layer1 '(face bold)) + (tp-layer-define layer2 '(face italic)) + (tp-layer-push 1 6 'layer1) + (should (eq (tp-layer-top 1 6) 'layer1)) + (tp-layer-push 1 6 'layer2) + (should (eq (tp-layer-top 1 6) 'layer2)))) + +;;; ============================================================ +;;; Propertize String Tests +;;; ============================================================ + +(ert-deftest tp-test-propertize () + "Test tp-propertize adds properties to string." + (let ((str (tp-propertize "Hello" 'face 'bold))) + (should (eq (get-text-property 0 'face str) 'bold)))) + +(ert-deftest tp-test-propertize-with-list () + "Test tp-propertize accepts properties as list." + (let ((str (tp-propertize "Hello" '(face bold help-echo "test")))) + (should (eq (get-text-property 0 'face str) 'bold)) + (should (equal (get-text-property 0 'help-echo str) "test")))) + +(ert-deftest tp-test-layer-propertize () + "Test tp-layer-propertize applies layer to string." + (tp-test-with-temp-buffer + (tp-layer-define my-layer '(face bold help-echo "greeting")) + (let ((str (tp-layer-propertize "Hello" 'my-layer))) + (should (eq (get-text-property 0 'face str) 'bold)) + (should (equal (get-text-property 0 'help-echo str) "greeting"))))) + +(ert-deftest tp-test-layer-propertize-error-on-undefined () + "Test tp-layer-propertize errors on undefined layer." + (tp-test-with-temp-buffer + (should-error (tp-layer-propertize "Hello" 'undefined-layer)))) + +(ert-deftest tp-test-group-propertize () + "Test tp-group-propertize applies group to string." + (tp-test-with-temp-buffer + (tp-group-define my-group + layer1 '(face bold) + layer2 '(help-echo "test")) + (let ((str (tp-group-propertize "Hello" 'my-group))) + (should (stringp str)) + (should (= (length str) 5))))) + +(ert-deftest tp-test-group-propertize-error-on-undefined () + "Test tp-group-propertize errors on undefined group." + (tp-test-with-temp-buffer + (should-error (tp-group-propertize "Hello" 'undefined-group)))) + +;;; ============================================================ +;;; Match and Regexp Tests +;;; ============================================================ + +(ert-deftest tp-test-match () + "Test tp-match sets properties on string matches." + (tp-test-with-temp-buffer + (insert "Hello World Hello") + (let ((regions (tp-match "Hello" 'face 'bold))) + (should (= (length regions) 2)) + (should (eq (tp-get 1 'face) 'bold)) + (should (eq (tp-get 13 'face) 'bold))))) + +(ert-deftest tp-test-match-returns-regions () + "Test tp-match returns correct region pairs." + (tp-test-with-temp-buffer + (insert "Hello World Hello") + (let ((regions (tp-match "Hello"))) + (should (= (length regions) 2)) + (should (equal (car regions) '(1 . 6))) + (should (equal (cadr regions) '(13 . 18)))))) + +(ert-deftest tp-test-regexp () + "Test tp-regexp sets properties on regexp matches." + (tp-test-with-temp-buffer + (insert "abc 123 def 456") + (let ((regions (tp-regexp "[0-9]+" 'face 'bold))) + (should (= (length regions) 2)) + (should (eq (tp-get 5 'face) 'bold)) + (should (eq (tp-get 13 'face) 'bold))))) + +(ert-deftest tp-test-regexp-returns-regions () + "Test tp-regexp returns correct region pairs." + (tp-test-with-temp-buffer + (insert "abc 123 def 456") + (let ((regions (tp-regexp "[0-9]+"))) + (should (= (length regions) 2))))) + +;;; ============================================================ +;;; Search and Navigation Tests +;;; ============================================================ + +(ert-deftest tp-test-forward () + "Test tp-forward finds next property." + (tp-test-with-temp-buffer + (insert "Hello World") + (tp-put 7 12 'face 'bold) + (goto-char 1) + ;; text-property-search-forward may not exist in all Emacs versions + (skip-unless (fboundp 'text-property-search-forward)) + (let ((match (tp-forward 'face))) + (should match) + (should (= (prop-match-beginning match) 7))))) + +(ert-deftest tp-test-backward () + "Test tp-backward finds previous property." + (tp-test-with-temp-buffer + (insert "Hello World") + (tp-put 1 6 'face 'bold) + (goto-char 12) + ;; text-property-search-backward may not exist in all Emacs versions + ;; Skip test if function is not available + (skip-unless (fboundp 'text-property-search-backward)) + (let ((match (tp-backward 'face))) + (should match) + (should (= (prop-match-beginning match) 1))))) + +(ert-deftest tp-test-next () + "Test tp-next returns next position with property." + (tp-test-with-temp-buffer + (insert "Hello World") + (tp-put 7 12 'face 'bold) + (let ((pos (tp-next 1 'face))) + (should (= pos 7))))) + +(ert-deftest tp-test-prev () + "Test tp-prev returns previous position with property." + (tp-test-with-temp-buffer + (insert "Hello World") + (tp-put 1 6 'face 'bold) + (let ((pos (tp-prev 12 'face))) + (should (= pos 1))))) + +(ert-deftest tp-test-goto-next () + "Test tp-goto-next moves point." + (tp-test-with-temp-buffer + (insert "Hello World") + (tp-put 7 12 'face 'bold) + (goto-char 1) + (tp-goto-next 'face) + (should (= (point) 7)))) + +(ert-deftest tp-test-goto-prev () + "Test tp-goto-prev moves point." + (tp-test-with-temp-buffer + (insert "Hello World") + (tp-put 1 6 'face 'bold) + (goto-char 12) + (tp-goto-prev 'face) + (should (= (point) 1)))) + +;;; ============================================================ +;;; Utility Function Tests +;;; ============================================================ + +(ert-deftest tp-test-in () + "Test tp-in finds regions with property." + (tp-test-with-temp-buffer + (insert "Hello World Test") + (tp-put 1 6 'my-prop 'value1) + (tp-put 7 12 'my-prop 'value2) + (let ((regions (tp-in 'my-prop))) + (should (= (length regions) 2))))) + +(ert-deftest tp-test-in-with-value () + "Test tp-in filters by value." + (tp-test-with-temp-buffer + (insert "Hello World Test") + (tp-put 1 6 'my-prop 'value1) + (tp-put 7 12 'my-prop 'value2) + (let ((regions (tp-in 'my-prop 'value1))) + (should (= (length regions) 1)) + (should (equal (car (car regions)) 1))))) + +(ert-deftest tp-test-all () + "Test tp-all returns all regions with properties." + (tp-test-with-temp-buffer + (insert "Hello World") + (tp-put 1 6 'face 'bold) + (tp-put 7 12 'face 'italic) + (let ((regions (tp-all))) + (should (>= (length regions) 2))))) + +(ert-deftest tp-test-regions-map () + "Test tp-regions-map applies function to regions." + (tp-test-with-temp-buffer + (insert "Hello World Hello") + (tp-put 1 6 'marker t) + (tp-put 13 18 'marker t) + (let ((result nil)) + (tp-regions-map + (lambda (start end idx) + (push (list start end idx) result)) + 'marker) + (should (= (length result) 2))))) + +(ert-deftest tp-test-strings-map () + "Test tp-strings-map applies function to strings." + (tp-test-with-temp-buffer + (insert "Hello World Hello") + (tp-put 1 6 'marker t) + (tp-put 13 18 'marker t) + (let ((result nil)) + (tp-strings-map + (lambda (str idx) + (push str result)) + 'marker) + (should (= (length result) 2)) + (should (member "Hello" result))))) + +;;; ============================================================ +;;; Alias Tests +;;; ============================================================ + +(ert-deftest tp-test-aliases-exist () + "Test that all aliases are properly defined." + (should (fboundp 'tp-set)) + (should (fboundp 'tp-layer-properties)) + (should (fboundp 'tp-layer-group-define)) + (should (fboundp 'tp-layer-group-properties)) + (should (fboundp 'tp-layer-group-propertize)) + (should (fboundp 'tp-layer-group-undefine))) + +(ert-deftest tp-test-aliases-work () + "Test that aliases work correctly." + (tp-test-with-temp-buffer + ;; Test tp-set alias + (insert "Hello") + (tp-set 1 6 'face 'bold) + (should (eq (tp-get 1 'face) 'bold)))) + +;;; ============================================================ +;;; Edge Case Tests +;;; ============================================================ + +(ert-deftest tp-test-empty-region () + "Test operations on empty buffer." + (tp-test-with-temp-buffer + (should (null (tp-at 1))) + (should (null (tp-all))))) + +(ert-deftest tp-test-overlapping-regions () + "Test overlapping property regions." + (tp-test-with-temp-buffer + (insert "Hello World") + (tp-put 1 8 'prop1 'val1) + (tp-put 5 12 'prop2 'val2) + (should (eq (tp-get 1 'prop1) 'val1)) + (should (null (tp-get 1 'prop2))) + (should (eq (tp-get 6 'prop1) 'val1)) + (should (eq (tp-get 6 'prop2) 'val2)) + (should (null (tp-get 10 'prop1))) + (should (eq (tp-get 10 'prop2) 'val2)))) + +(ert-deftest tp-test-single-char-region () + "Test operations on single character." + (tp-test-with-temp-buffer + (insert "H") + (tp-put 1 2 'face 'bold) + (should (eq (tp-get 1 'face) 'bold)))) + +(ert-deftest tp-test-layer-on-string () + "Test layer operations on string object." + (let ((str (copy-sequence "Hello"))) + (set-text-properties 0 5 nil str) + (should (tp-empty-p str)))) + +(provide 'tp-ert-tests) +;;; tp-ert-tests.el ends here