Files
clojure-tui/test/tui/ansi_test.clj
2026-01-21 10:30:07 -05:00

200 lines
6.4 KiB
Clojure

(ns tui.ansi-test
"Unit tests for ANSI escape codes and string utilities."
(:require [clojure.test :refer [deftest testing is]]
[clojure.string :as str]
[tui.ansi :as ansi]))
;; === Style Tests ===
(deftest style-foreground-test
(testing "applies foreground colors"
(let [result (ansi/style "text" :fg :red)]
(is (str/includes? result "31m"))
(is (str/includes? result "text"))
(is (str/ends-with? result ansi/reset))))
(testing "applies bright foreground colors"
(let [result (ansi/style "text" :fg :bright-red)]
(is (str/includes? result "91m"))))
(testing "applies gray/grey alias"
(let [gray (ansi/style "text" :fg :gray)
grey (ansi/style "text" :fg :grey)]
(is (= gray grey))
(is (str/includes? gray "90m")))))
(deftest style-background-test
(testing "applies background colors"
(let [result (ansi/style "text" :bg :blue)]
(is (str/includes? result "44m"))
(is (str/includes? result "text")))))
(deftest style-attributes-test
(testing "applies bold"
(let [result (ansi/style "text" :bold true)]
(is (str/includes? result "1m"))))
(testing "applies dim"
(let [result (ansi/style "text" :dim true)]
(is (str/includes? result "2m"))))
(testing "applies italic"
(let [result (ansi/style "text" :italic true)]
(is (str/includes? result "3m"))))
(testing "applies underline"
(let [result (ansi/style "text" :underline true)]
(is (str/includes? result "4m"))))
(testing "applies inverse"
(let [result (ansi/style "text" :inverse true)]
(is (str/includes? result "7m"))))
(testing "applies strikethrough"
(let [result (ansi/style "text" :strike true)]
(is (str/includes? result "9m")))))
(deftest style-combined-test
(testing "combines multiple styles"
(let [result (ansi/style "text" :fg :red :bold true :underline true)]
(is (str/includes? result "31")) ; Red
(is (str/includes? result "1")) ; Bold
(is (str/includes? result "4"))))) ; Underline
(deftest style-no-styles-test
(testing "returns plain text when no styles"
(is (= "text" (ansi/style "text")))))
;; === Color Helper Tests ===
(deftest fg-helper-test
(testing "fg helper applies foreground color"
(let [result (ansi/fg :green "text")]
(is (str/includes? result "32m"))
(is (str/includes? result "text")))))
(deftest bg-helper-test
(testing "bg helper applies background color"
(let [result (ansi/bg :yellow "text")]
(is (str/includes? result "43m"))
(is (str/includes? result "text")))))
;; === 256 Color Tests ===
(deftest fg-256-test
(testing "applies 256-color foreground"
(let [result (ansi/fg-256 196 "text")]
(is (str/includes? result "38;5;196m"))
(is (str/includes? result "text")))))
(deftest bg-256-test
(testing "applies 256-color background"
(let [result (ansi/bg-256 21 "text")]
(is (str/includes? result "48;5;21m"))
(is (str/includes? result "text")))))
;; === True Color Tests ===
(deftest fg-rgb-test
(testing "applies RGB foreground"
(let [result (ansi/fg-rgb 255 128 64 "text")]
(is (str/includes? result "38;2;255;128;64m"))
(is (str/includes? result "text")))))
(deftest bg-rgb-test
(testing "applies RGB background"
(let [result (ansi/bg-rgb 0 128 255 "text")]
(is (str/includes? result "48;2;0;128;255m"))
(is (str/includes? result "text")))))
;; === String Utility Tests ===
(deftest visible-length-test
(testing "returns length of plain text"
(is (= 5 (ansi/visible-length "hello")))
(is (= 0 (ansi/visible-length ""))))
(testing "excludes ANSI codes from length"
(let [styled (ansi/style "hello" :fg :red :bold true)]
(is (= 5 (ansi/visible-length styled)))))
(testing "handles multiple ANSI sequences"
(let [text (str (ansi/fg :red "red") (ansi/fg :blue "blue"))]
(is (= 7 (ansi/visible-length text))))))
(deftest pad-right-test
(testing "pads string to width"
(is (= "hi " (ansi/pad-right "hi" 5)))
(is (= "hello" (ansi/pad-right "hello" 5))))
(testing "does not truncate if longer"
(is (= "hello" (ansi/pad-right "hello" 3))))
(testing "handles styled text"
(let [styled (ansi/style "hi" :fg :red)
padded (ansi/pad-right styled 5)]
(is (= 5 (ansi/visible-length padded))))))
(deftest pad-left-test
(testing "pads string on left"
(is (= " hi" (ansi/pad-left "hi" 5)))
(is (= "hello" (ansi/pad-left "hello" 5))))
(testing "does not truncate if longer"
(is (= "hello" (ansi/pad-left "hello" 3)))))
(deftest pad-center-test
(testing "centers string"
(is (= " hi " (ansi/pad-center "hi" 5)))
(is (= " hi " (ansi/pad-center "hi" 6))))
(testing "handles odd padding"
(is (= " x " (ansi/pad-center "x" 3)))))
(deftest truncate-test
(testing "truncates long strings"
(is (= "hel\u2026" (ansi/truncate "hello" 4)))
(is (= "h\u2026" (ansi/truncate "hello" 2))))
(testing "does not truncate short strings"
(is (= "hi" (ansi/truncate "hi" 5)))
(is (= "hello" (ansi/truncate "hello" 5)))))
;; === Box Characters Tests ===
(deftest box-chars-test
(testing "all border styles have required characters"
(doseq [[style chars] ansi/box-chars]
(is (contains? chars :tl) (str style " missing :tl"))
(is (contains? chars :tr) (str style " missing :tr"))
(is (contains? chars :bl) (str style " missing :bl"))
(is (contains? chars :br) (str style " missing :br"))
(is (contains? chars :h) (str style " missing :h"))
(is (contains? chars :v) (str style " missing :v")))))
;; === Escape Sequence Constants Tests ===
(deftest escape-sequences-test
(testing "escape sequences are strings"
(is (string? ansi/clear-screen))
(is (string? ansi/clear-line))
(is (string? ansi/cursor-home))
(is (string? ansi/hide-cursor))
(is (string? ansi/show-cursor))
(is (string? ansi/enter-alt-screen))
(is (string? ansi/exit-alt-screen)))
(testing "escape sequences start with ESC"
(is (str/starts-with? ansi/clear-screen "\u001b"))
(is (str/starts-with? ansi/cursor-home "\u001b"))))
(deftest cursor-movement-test
(testing "cursor-to generates correct sequence"
(is (= "\u001b[5;10H" (ansi/cursor-to 5 10))))
(testing "cursor movement functions"
(is (= "\u001b[3A" (ansi/cursor-up 3)))
(is (= "\u001b[2B" (ansi/cursor-down 2)))
(is (= "\u001b[4C" (ansi/cursor-forward 4)))
(is (= "\u001b[1D" (ansi/cursor-back 1)))))