(defun err? (v) (= 'err (car v)))

(defun no-arguments () 1234)
(defun only-required (a b c) (+ a b c))
(defun only-optional (&optional a b c) (list a b c))
(defun only-rest (&rest r) (length r))
(defun required-and-optional (a b &optional c d) (list a b c d))
(defun required-and-rest (a b &rest r) (list a b r))
(defun optional-and-rest (&optional a b &rest r) (list a b r))
(defun required-and-optional-and-rest (a b &optional c d &rest r) (list a b c d r))

; no-arguments
(assert (= '(ok 1234) (eval '(no-arguments))))
(assert (err? (eval '(no-arguments 1))))
; only-required
(assert (= '(ok 6) (eval '(only-required 1 2 3))))
(assert (err? (eval '(only-required 1 2))))
; only-optional
(assert
  (=
    '(ok (nil nil nil))
    (eval '(only-optional))
    )
  )
(assert
  (=
    '(ok (1 nil nil))
    (eval '(only-optional 1))
    )
  )
(assert
  (=
    '(ok (1 2 nil))
    (eval '(only-optional 1 2))
    )
  )
(assert
  (=
    '(ok (1 2 3))
    (eval '(only-optional 1 2 3))
    )
  )
(assert (err? (eval '(only-optional 1 2 3 4))))
; only-rest
(assert (= 0 (only-rest)))
(assert (= 1 (only-rest 1)))
(assert (= 2 (only-rest 1 2)))
(assert (= 3 (only-rest 1 2 3)))

; required-and-optional
(assert (err? (eval '(required-and-optional))))
(assert (err? (eval '(required-and-optional 1))))
(assert
  (=
    '(1 2 nil nil)
    (required-and-optional 1 2)
    )
  )
(assert
  (=
    '(1 2 3 nil)
    (required-and-optional 1 2 3)
    )
  )
(assert
  (=
    '(1 2 3 4)
    (required-and-optional 1 2 3 4)
    )
  )
(assert (err? (eval '(required-and-optional 1 2 3 4 5))))

; required-and-rest
(assert (err? (eval '(required-and-rest))))
(assert (err? (eval '(required-and-rest 1))))
(assert (= '(1 2 nil) (required-and-rest 1 2)))
(assert (= '(1 2 (3)) (required-and-rest 1 2 3)))
(assert (= '(1 2 (3 4 5)) (required-and-rest 1 2 3 4 5)))

; optional-and-rest
(assert (= '(nil nil nil) (optional-and-rest)))
(assert (= '(1 nil nil) (optional-and-rest 1)))
(assert (= '(1 2 nil) (optional-and-rest 1 2)))
(assert (= '(1 2 (3)) (optional-and-rest 1 2 3)))
(assert (= '(1 2 (3 4 5)) (optional-and-rest 1 2 3 4 5)))

; required-and-optional-and-rest
(assert (err? (eval '(required-and-optional-and-rest))))
(assert (err? (eval '(required-and-optional-and-rest 1))))
(assert (= '(1 2 nil nil nil) (required-and-optional-and-rest 1 2)))
(assert (= '(1 2 3 nil nil) (required-and-optional-and-rest 1 2 3)))
(assert (= '(1 2 3 4 nil) (required-and-optional-and-rest 1 2 3 4)))
(assert (= '(1 2 3 4 (5)) (required-and-optional-and-rest 1 2 3 4 5)))
(assert (= '(1 2 3 4 (5 6 7 8)) (required-and-optional-and-rest 1 2 3 4 5 6 7 8)))
