;-*- Mode:     Lisp -*-
;;;; Author:   Paul Dietz
;;;; Created:  Sun Aug 18 14:08:57 2002
;;;; Contains: Tests for function REDUCE

(in-package :cl-test)

(deftest reduce-list.1
  (reduce #'cons '(a b c d e f))
  (((((a . b) . c) . d) . e) . f))

(deftest reduce-list.2
  (reduce #'cons '(a b c d e f) :from-end t)
  (a b c d e . f))

(deftest reduce-list.3
  (reduce #'cons '(a b c d e f) :initial-value 'z)
  ((((((z . a) . b) . c) . d) . e) . f))
  
(deftest reduce-list.4
  (reduce #'cons '(a b c d e f) :from-end t :initial-value 'g)
  (a b c d e f . g))

(deftest reduce-list.5
  (reduce #'cons '(a b c d e f) :from-end nil)
  (((((a . b) . c) . d) . e) . f))

(deftest reduce-list.6
  (reduce #'cons '(a b c d e f) :from-end 17)
  (a b c d e . f))

(deftest reduce-list.7
  (reduce #'cons '(a b c d e f) :end nil)
  (((((a . b) . c) . d) . e) . f))

(deftest reduce-list.8
  (reduce #'cons '(a b c d e f) :end 3)
  ((a . b) . c))

(deftest reduce-list.9
  (reduce #'cons '(a b c d e f) :start 1 :end 4)
  ((b . c) . d))

(deftest reduce-list.10
  (reduce #'cons '(a b c d e f) :start 1 :end 4 :from-end t)
  (b c . d))

(deftest reduce-list.11
  (reduce #'cons '(a b c d e f) :start 1 :end 4 :from-end t
	  :initial-value nil)
  (b c d))

(deftest reduce-list.12
  (reduce 'cons '(a b c d e f))
  (((((a . b) . c) . d) . e) . f))

(deftest reduce-list.13
  (reduce #'+ nil)
  0)

(deftest reduce-list.14
  (reduce #'+ '(1 2 3) :start 0 :end 0)
  0)

(deftest reduce-list.15
  (reduce #'+ '(1 2 3) :key '1+)
  9)

(deftest reduce-list.16
  (reduce #'cons '(1 2 3) :key '1+ :from-end t :initial-value nil)
  (2 3 4))

(deftest reduce-list.17
  (reduce #'+ '(1 2 3 4 5 6 7) :key '1+ :start 2 :end 6)
  22)

;;;;;;;

(deftest reduce-array.1
  (reduce #'cons #(a b c d e f))
  (((((a . b) . c) . d) . e) . f))

(deftest reduce-array.2
  (reduce #'cons #(a b c d e f) :from-end t)
  (a b c d e . f))

(deftest reduce-array.3
  (reduce #'cons #(a b c d e f) :initial-value 'z)
  ((((((z . a) . b) . c) . d) . e) . f))
  
(deftest reduce-array.4
  (reduce #'cons #(a b c d e f) :from-end t :initial-value 'g)
  (a b c d e f . g))

(deftest reduce-array.5
  (reduce #'cons #(a b c d e f) :from-end nil)
  (((((a . b) . c) . d) . e) . f))

(deftest reduce-array.6
  (reduce #'cons #(a b c d e f) :from-end 17)
  (a b c d e . f))

(deftest reduce-array.7
  (reduce #'cons #(a b c d e f) :end nil)
  (((((a . b) . c) . d) . e) . f))

(deftest reduce-array.8
  (reduce #'cons #(a b c d e f) :end 3)
  ((a . b) . c))

(deftest reduce-array.9
  (reduce #'cons #(a b c d e f) :start 1 :end 4)
  ((b . c) . d))

(deftest reduce-array.10
  (reduce #'cons #(a b c d e f) :start 1 :end 4 :from-end t)
  (b c . d))

(deftest reduce-array.11
  (reduce #'cons #(a b c d e f) :start 1 :end 4 :from-end t
	  :initial-value nil)
  (b c d))

(deftest reduce-array.12
  (reduce 'cons #(a b c d e f))
  (((((a . b) . c) . d) . e) . f))

(deftest reduce-array.13
  (reduce #'+ #(1 2 3) :start 0 :end 0)
  0)

(deftest reduce-array.14
  (let ((a (make-array '(8) :initial-contents '(1 2 3 4 5 6 7 8)
		       :fill-pointer 4)))
    (reduce #'+ a))
  10)

(deftest reduce-array.15
  (let ((a (make-array '(8) :initial-contents '(1 2 3 4 5 6 7 8)
		       :fill-pointer 4)))
    (reduce #'+ a :end nil))
  10)

(deftest reduce-array.16
  (let ((a (make-array '(8) :initial-contents '(1 2 3 4 5 6 7 8)
		       :fill-pointer 4)))
    (reduce #'+ a :from-end t))
  10)

(deftest reduce-array.17
  (let ((a (make-array '(8) :initial-contents '(1 2 3 4 5 6 7 8)
		       :fill-pointer 4)))
    (reduce #'+ a :initial-value 1))
  11)

(deftest reduce-array.18
  (let ((a (make-array '(8) :initial-contents '(1 2 3 4 5 6 7 8)
		       :fill-pointer 4)))
    (reduce #'+ a :initial-value 1 :start 2))
  8)

(deftest reduce-array.19
  (let ((a (make-array '(8) :initial-contents '(1 2 3 4 5 6 7 8)
		       :fill-pointer 4)))
    (reduce #'+ a :end 3))
  6)


;;;;;;;;

(deftest reduce.error.1
  (classify-error (reduce 'cons 'a))
  type-error)

(deftest reduce.error.2
  (classify-error (reduce))
  program-error)

(deftest reduce.error.3
  (classify-error (reduce #'list nil :start))
  program-error)

(deftest reduce.error.4
  (classify-error (reduce #'list nil 'bad t))
  program-error)

(deftest reduce.error.5
  (classify-error (reduce #'list nil 'bad t :allow-other-keys nil))
  program-error)

(deftest reduce.error.6
  (classify-error (reduce #'list nil 1 2))
  program-error)

(deftest reduce.error.7
  (classify-error (locally (reduce 'cons 'a) t))
  type-error)

(deftest reduce.error.8
  (classify-error (reduce #'identity '(a b c)))
  program-error)

(deftest reduce.error.9
  (classify-error (reduce #'cons '(a b c) :key #'cons))
  program-error)

(deftest reduce.error.10
  (classify-error (reduce #'cons '(a b c) :key #'car))
  type-error)


;;;;;;;;

(deftest reduce-string.1
  (reduce #'cons "abcdef")
  (((((#\a . #\b) . #\c) . #\d) . #\e) . #\f))

(deftest reduce-string.2
  (reduce #'cons "abcdef" :from-end t)
  (#\a #\b #\c #\d #\e . #\f))

(deftest reduce-string.3
  (reduce #'cons "abcdef" :initial-value 'z)
  ((((((z . #\a) . #\b) . #\c) . #\d) . #\e) . #\f))
  
(deftest reduce-string.4
  (reduce #'cons "abcdef" :from-end t :initial-value 'g)
  (#\a #\b #\c #\d #\e #\f . g))

(deftest reduce-string.5
  (reduce #'cons "abcdef" :from-end nil)
   (((((#\a . #\b) . #\c) . #\d) . #\e) . #\f))

(deftest reduce-string.6
  (reduce #'cons "abcdef" :from-end 17)
   (#\a #\b #\c #\d #\e . #\f))

(deftest reduce-string.7
  (reduce #'cons "abcdef" :end nil)
  (((((#\a . #\b) . #\c) . #\d) . #\e) . #\f))

(deftest reduce-string.8
  (reduce #'cons "abcdef" :end 3)
  ((#\a . #\b) . #\c))

(deftest reduce-string.9
  (reduce #'cons "abcdef" :start 1 :end 4)
  ((#\b . #\c) . #\d))

(deftest reduce-string.10
  (reduce #'cons "abcdef" :start 1 :end 4 :from-end t)
  (#\b #\c . #\d))

(deftest reduce-string.11
  (reduce #'cons "abcdef" :start 1 :end 4 :from-end t
	  :initial-value nil)
  (#\b #\c #\d))

(deftest reduce-string.12
  (reduce 'cons "abcdef")
  (((((#\a . #\b) . #\c) . #\d) . #\e) . #\f))

(deftest reduce-string.13
  (reduce #'+ "abc" :start 0 :end 0)
  0)

(deftest reduce-string.14
  (let ((s (make-array '(8) :initial-contents "abcdefgh"
		       :fill-pointer 6
		       :element-type 'character)))
    (coerce (reduce #'(lambda (x y) (cons y x)) s :initial-value nil)
	    'string))
  "fedcba")

(deftest reduce-string.15
  (let ((s (make-array '(8) :initial-contents "abcdefgh"
		       :fill-pointer 6
		       :element-type 'character)))
    (coerce (reduce #'(lambda (x y) (cons y x)) s :initial-value nil
		    :start 1)
	    'string))
  "fedcb")

(deftest reduce-string.16
  (let ((s (make-array '(8) :initial-contents "abcdefgh"
		       :fill-pointer 6
		       :element-type 'character)))
    (coerce (reduce #'(lambda (x y) (cons y x)) s :end nil 
		    :initial-value nil)
	    'string))
  "fedcba")

(deftest reduce-string.17
  (let ((s (make-array '(8) :initial-contents "abcdefgh"
		       :fill-pointer 6
		       :element-type 'character)))
    (coerce (reduce #'(lambda (x y) (cons y x)) s :end 4 
		    :initial-value nil)
	    'string))
  "dcba")

;;;;;;;;

(deftest reduce-bitstring.1
  (reduce #'cons #*001101)
  (((((0 . 0) . 1) . 1) . 0) . 1))

(deftest reduce-bitstring.2
  (reduce #'cons #*001101 :from-end t)
  (0 0 1 1 0 . 1))

(deftest reduce-bitstring.3
  (reduce #'cons #*001101 :initial-value 'z)
  ((((((z . 0) . 0) . 1) . 1) . 0) . 1))
  
(deftest reduce-bitstring.4
  (reduce #'cons #*001101 :from-end t :initial-value 'g)
  (0 0 1 1 0 1 . g))

(deftest reduce-bitstring.5
  (reduce #'cons #*001101 :from-end nil)
  (((((0 . 0) . 1) . 1) . 0) . 1))

(deftest reduce-bitstring.6
  (reduce #'cons #*001101 :from-end 17)
  (0 0 1 1 0 . 1))

(deftest reduce-bitstring.7
  (reduce #'cons #*001101 :end nil)
  (((((0 . 0) . 1) . 1) . 0) . 1))

(deftest reduce-bitstring.8
  (reduce #'cons #*001101 :end 3)
  ((0 . 0) . 1))

(deftest reduce-bitstring.9
  (reduce #'cons #*001101 :start 1 :end 4)
  ((0 . 1) . 1))

(deftest reduce-bitstring.10
  (reduce #'cons #*001101 :start 1 :end 4 :from-end t)
  (0 1 . 1))

(deftest reduce-bitstring.11
  (reduce #'cons #*001101 :start 1 :end 4 :from-end t
	  :initial-value nil)
  (0 1 1))

(deftest reduce-bitstring.12
  (reduce 'cons #*001101)
  (((((0 . 0) . 1) . 1) . 0) . 1))

(deftest reduce-bitstring.13
  (reduce #'+ #(1 1 1) :start 0 :end 0)
  0)

(deftest reduce-bitstring.14
  (let ((s (make-array '(8) :initial-contents '(0 0 1 0 1 1 0 1)
		       :fill-pointer 6
		       :element-type 'bit)))
    (reduce #'+ s))
  3)

(deftest reduce-bitstring.15
  (let ((s (make-array '(8) :initial-contents '(0 0 1 0 1 1 0 1)
		       :fill-pointer 6
		       :element-type 'bit)))
    (reduce #'+ s :start 3))
  2)

(deftest reduce-bitstring.16
  (let ((s (make-array '(8) :initial-contents '(0 0 1 0 1 1 0 1)
		       :fill-pointer 6
		       :element-type 'bit)))
    (reduce #'+ s :start 3 :initial-value 10))
  12)

(deftest reduce-bitstring.17
  (let ((s (make-array '(8) :initial-contents '(0 0 1 0 1 1 0 1)
		       :fill-pointer 6
		       :element-type 'bit)))
    (reduce #'+ s :end nil))
  3)

(deftest reduce-bitstring.18
  (let ((s (make-array '(8) :initial-contents '(1 1 1 1 1 1 1 1)
		       :fill-pointer 6
		       :element-type 'bit)))
    (reduce #'+ s :start 2 :end 4))
  2)

;;; Order of evaluation tests

(deftest reduce.order.1
  (let ((i 0) x y)
    (values
     (reduce (progn (setf x (incf i)) #'cons)
	     (progn (setf y (incf i)) '(a b c)))
     i x y))
   ((a . b) . c) 2 1 2)

(deftest reduce.order.2
  (let ((i 0) a b c d e f g)
    (values
     (reduce (progn (setf a (incf i)) #'cons)
	     (progn (setf b (incf i)) '(a b c d e f))
	     :from-end (progn (setf c (incf i)) t)
	     :initial-value (progn (setf d (incf i)) 'nil)
	     :start (progn (setf e (incf i)) 1)
	     :end (progn (setf f (incf i)) 4)
	     :key (progn (setf g (incf i)) #'identity)
	     )
     i a b c d e f g))
  (b c d) 7 1 2 3 4 5 6 7)

(deftest reduce.order.3
  (let ((i 0) a b c d e f g)
    (values
     (reduce (progn (setf a (incf i)) #'cons)
	     (progn (setf b (incf i)) '(a b c d e f))
	     :key (progn (setf c (incf i)) #'identity)
	     :end (progn (setf d (incf i)) 4)
	     :start (progn (setf e (incf i)) 1)
	     :initial-value (progn (setf f (incf i)) 'nil)
	     :from-end (progn (setf g (incf i)) t)
	     )
     i a b c d e f g))
  (b c d) 7 1 2 3 4 5 6 7)


;;; Keyword tests

(deftest reduce.allow-other-keys.1
  (reduce #'+ '(1 2 3) :allow-other-keys t)
  6)

(deftest reduce.allow-other-keys.2
  (reduce #'+ '(1 2 3) :allow-other-keys nil)
  6)

(deftest reduce.allow-other-keys.3
  (reduce #'+ '(1 2 3) :bad t :allow-other-keys t)
  6)

(deftest reduce.allow-other-keys.4
  (reduce #'+ '(1 2 3) :allow-other-keys t :bad t)
  6)

(deftest reduce.allow-other-keys.5
  (reduce #'+ '(1 2 3) :allow-other-keys t :allow-other-keys nil :bad t)
  6)

(deftest reduce.allow-other-keys.6
  (reduce #'+ '(1 2 3) :allow-other-keys t :bad t :allow-other-keys nil)
  6)

(deftest reduce.allow-other-keys.7
  (reduce #'+ '(1 2 3) :bad t :allow-other-keys t :allow-other-keys nil)
  6)

(deftest reduce.allow-other-keys.8
  (reduce #'cons '(1 2 3) :allow-other-keys t :from-end t :bad t
	  :initial-value nil)
  (1 2 3))

(deftest reduce.keywords.9
  (reduce #'cons '(1 2 3) :from-end t :from-end nil
	  :initial-value nil :initial-value 'a)
  (1 2 3))

