(in-package #:cl-user)

(defpackage #:cl-colors2-tests
  (:use
   #:alexandria
   #:common-lisp
   #:cl-colors2
   #:clunit)
  (:export #:run))

(in-package #:cl-colors2-tests)

(defsuite cl-colors-suite ())

(defmacro first-value (a)
  `(first (multiple-value-list ,a)))

(defun run (&key (use-debugger nil))
  "Run all the tests for CL-COLORS2-TESTS."
  (clunit:run-suite 'cl-colors-suite :use-debugger use-debugger))

(defun rgb= (rgb1 rgb2 &optional (epsilon 1e-10))
  "Compare RGB colors for (numerical) equality."
  (color-equals rgb1 rgb2 :tolerance epsilon))

(defun random-rgb ()
  (rgb (random 1d0) (random 1d0) (random 1d0)))

(deftest rgb<->hsv-test (cl-colors-suite)
  (loop repeat 100 do
    (let ((rgb (random-rgb)))
      (assert-true (rgb= rgb (as-rgb (as-hsv rgb))))
      (assert-true (color-equals (as-hsv rgb) rgb))
      (assert-true (rgb= rgb (as-rgb (as-hsv* rgb))))
      (assert-true (color-equals (as-hsv* rgb) (as-hsv rgb))))))

(deftest rgb<->hsl-test (cl-colors-suite)
  (loop repeat 100 do
    (let ((rgb (random-rgb)))
      (assert-true (rgb= rgb (as-rgb (as-hsl rgb))))
      (assert-true (color-equals (as-hsl rgb) rgb))
      (assert-true (rgb= rgb (as-rgb (as-hsl rgb))))
      (assert-true (color-equals (as-hsl rgb) (as-hsl rgb))))))

(deftest conversions-tests (cl-colors-suite)
  (let ((*clunit-equality-test*  #'color-equals))
    (assert-equality* (rgb 169/256 0.40710938 27/128)
        (as-rgb (as-hsv (rgb (/ 169 256) (/ 104.22 256) (/ 54 256)))))
    (assert-equality* (rgb 169/256 0.40710938 27/128)
        (as-rgb (as-hsl (as-hsv (rgb (/ 169 256) (/ 104.22 256) (/ 54 256))))))
    (assert-equality* (rgb 53/128 27/32 97/256)
        (as-hsl (as-hsv (rgb (/ 106 256) (/ 216 256) (/ 97 256)))))))

(deftest parse-name (cl-colors-suite)
  (assert-true (as-rgb "snow"))
  (assert-condition error (as-rgb "foo-bar"))
  (assert-true (as-rgb "teal"))
  (assert-condition error (as-rgb "teal" :colors-list *x11-colors-list*))
  (assert-false (as-rgb "teal" :colors-list *x11-colors-list* :errorp nil)))

;; (defun test-hue-combination (from to positivep)
;;   (dotimes (i 21)
;;     (format t "~a " (hue-combination from to (/ i 20) positivep))))

(deftest print-hex-rgb-test (cl-colors-suite)
  (let ((rgb (rgb 0.070 0.203 0.337)))
    (assert-equalp "#123456" (print-hex-rgb rgb))
    (assert-equalp "123456" (print-hex-rgb rgb :hash nil))
    (assert-equalp "#135" (print-hex-rgb rgb :short t))
    (assert-equalp "135" (print-hex-rgb rgb :hash nil :short t))
    (assert-equalp "#12345678" (print-hex-rgb rgb :alpha 0.47))
    (assert-equalp "12345678" (print-hex-rgb rgb :alpha 0.47 :hash nil))
    (assert-equalp "#1357" (print-hex-rgb rgb :alpha 0.47 :short t))
    (assert-equalp "1357" (print-hex-rgb rgb :alpha 0.47 :hash nil :short t))))

(deftest parse-hex-rgb-test (cl-colors-suite)
  (let ((rgb                     (rgb 0.070 0.203 0.337))
        (*clunit-equality-test*  (rcurry #'rgb= 0.01)))
    (assert-equality* rgb (first-value (parse-hex-rgb "#123456")))
    (assert-equality* rgb (first-value (parse-hex-rgb "123456")))
    (assert-equality* rgb (first-value (parse-hex-rgb "#135")))
    (assert-equality* rgb (first-value (parse-hex-rgb "135")))
    (let ((*clunit-equality-test* #'(lambda (list1 list2)
                                      (and (rgb= (car list1) (car list2) 0.01)
                                           (cl-colors2::eps= (cadr list1) (cadr list2)
                                                             0.01)))))
      (assert-equality* (list rgb 0.47) (multiple-value-list (parse-hex-rgb "#12345678")))
      (assert-equality* (list rgb 0.47) (multiple-value-list (parse-hex-rgb "12345678")))
      (assert-equality* (list rgb 0.47) (multiple-value-list (parse-hex-rgb "#1357")))
      (assert-equality* (list rgb 0.47) (multiple-value-list (parse-hex-rgb "1357")))
      (assert-equality* (list (rgb 1 1 0) 2/3)
          (multiple-value-list (parse-hex-rgb "FF0A")))
      (assert-equality* (list (rgb 1 1 0) 2/3)
          (multiple-value-list (parse-hex-rgb "#FF0A")))
      (assert-equality* (list (RGB 50/51 251/255 84/85) 1/255)
          (multiple-value-list (parse-hex-rgb "#FAFBFC01"))))))

(deftest print-hex-rgb/format-test (cl-colors-suite)
  (assert-equalp "#123456" (with-output-to-string (*standard-output*)
                             (print-hex-rgb (rgb 0.070 0.203 0.337)
                                            :destination T))))

(deftest hex<->rgb-test (cl-colors-suite)
  (loop repeat 100 do
       (let ((rgb                     (random-rgb))
             (*clunit-equality-test*  (rcurry #'rgb= 0.01)))
         (assert-equality* rgb (first-value (parse-hex-rgb (print-hex-rgb rgb)))))))

(deftest parse-hex-rgb-ranges-test (cl-colors-suite)
  (let ((*clunit-equality-test* (rcurry #'rgb= 0.001)))
    (assert-equality* (rgb 0.070 0.203 0.337)
        (first-value (parse-hex-rgb "foo#123456zzz" :start 3 :end 10)))))

(deftest print-css-test (cl-colors-suite)
  (flet ((color->string (r g b alpha)
           (with-output-to-string (*standard-output*)
             (print-css-rgb/a (rgb r g b)
                              :alpha       alpha
                              :destination *standard-output*))))
    (assert-equalp "rgb(18, 52, 86)"
        (color->string 0.070 0.203 0.337 nil))
    (assert-equalp "rgba(255, 170, 102, 204)"
        (let ((rgb (hex-to-rgb "FFAA66")))
          (color->string (rgb-red   rgb)
                         (rgb-green rgb)
                         (rgb-blue  rgb)
                         .8)))))

(run)
