(load #P"../src/unified-matcher.lisp")
(load #P"../src/utils.lisp")
(load #P"../src/delay-operator.lisp")
(use-package :utils)

; tests for 'delay' and 'force'
(let* ((exp '(let (?gval ?gevaled)
               (lambda ()
                 (if ?gevaled
                   ?gval
                   (progn
                     (setq ?gevaled t)
                     (setq ?gval a))))))
       (val (macroexpand-1 '(dly:delay a))))
  (assert (um:if-match val exp
             (not (eql ?gval ?gevaled)))
          nil
          "delay test  exp: ~A, val: ~A" exp val))

(let* ((dly (dly:delay 'a))
       (val (dly:force dly))
       (exp 'a))
  (assert (eql val exp)
          nil
          "delay/force test  exp: ~A, val: ~A" exp val))

; tests for 'cons', 'car' and 'cdr'
(let* ((z (dly:cons 'a 'b))
       (x (dly:car z))
       (y (dly:cdr z))
       (val (list x y))
       (exp '(a b)))
  (assert (equal exp val)
          nil
          "cons/car/cdr test  exp: ~A, val: ~A" exp val))

; tests for 'enum' and 'to-list'
(let* ((exp '(2 5 8 11))
       (val (dly:to-list (dly:enum 2 3 11))))
  (assert (equal val exp)
          nil
          "enum/to-list test  exp: ~A, val: ~A" exp val))

; tests for 'enum' and 'nth'
(let* ((s (dly:enum))
       (val (mapcar (lambda (n) (dly:nth n s))
                    '(0 1 2 3 4)))
       (exp '(0 1 2 3 4)))
  (assert (equal val exp)
          nil
          "enum/nth test  exp: ~A, val: ~A" exp val))

(let* ((s (dly:enum 2 -3))
       (val (mapcar (lambda (n) (dly:nth n s))
                    '(0 1 2 3 4)))
       (exp '(2 -1 -4 -7 -10)))
  (assert (equal val exp)
          nil
          "enum/nth test  exp: ~A, val: ~A" exp val))

(let* ((s (dly:enum 1 2 6))
       (val (mapcar (lambda (n) (dly:nth n s))
                    '(0 1 2 3 4)))
       (exp '(1 3 5 nil nil)))
  (assert (equal val exp)
          nil
          "enum/nth test  exp: ~A, val: ~A" exp val))

(let* ((s (dly:enum 1 -2 -6))
       (val (mapcar (lambda (n) (dly:nth n s))
                    '(0 1 2 3 4)))
       (exp '(1 -1 -3 -5 nil)))
  (assert (equal val exp)
          nil
          "enum/nth test  exp: ~A, val: ~A" exp val))

; tests for 'mapcar'
(let* ((exp '(1 2 3))
       (val (dly:to-list
              (dly:mapcar #'1+ (dly:enum 0 1 2)))))
  (assert (equal val exp)
          nil
          "mapcar test  exp: ~A, val: ~A" exp val))

(let* ((exp '(6 12 18 24))
       (val (dly:to-list
              (dly:mapcar #'+ (dly:enum 1 1 4)
                              (dly:enum 2 2 8)
                              (dly:enum 3 3 12)))))
  (assert (equal val exp)
          nil
          "mapcar test  exp: ~A, val: ~A" exp val))

(in-package dly)

; tests for 'def-car-cdrs'
(let ((exp '(progn
              (shadow 'car) (export 'car)
              (defun car (z) (car z))
              (shadow 'cdr) (export 'cdr)
              (defun cdr (z) (cdr z))
              (shadow 'caar) (export 'caar)
              (defun caar (z) (car (car z)))
              (shadow 'cadr) (export 'cadr)
              (defun cadr (z) (car (cdr z)))
              (shadow 'cdar) (export 'cdar)
              (defun cdar (z) (cdr (car z)))
              (shadow 'cddr) (export 'cddr)
              (defun cddr (z) (cdr (cdr z)))))
      (val (macroexpand-1 '(def-car-cdrs 1 2))))
  (assert (equal exp val)
          nil
          "def-car-cdrs test  exp: ~A, val: ~A" exp val))
