;-*- Mode:     Lisp -*-
;;;; Author:   Paul Dietz
;;;; Created:  Sun Sep 29 20:49:47 2002
;;;; Contains: Tests for REMOVE-DUPLICATES, DELETE-DUPLICATES

(in-package :cl-test)

(compile-and-load "remove-aux.lsp")
(compile-and-load "remove-duplicates-aux.lsp")

(deftest random-remove-duplicates
  (loop for result = (random-test-remove-dups (1+ (random 20)))
	repeat 1000
	unless (eq result t)
	collect result)
  nil)

(deftest random-delete-duplicates
  (loop for result = (random-test-remove-dups (1+ (random 20)) nil)
	repeat 1000
	unless (eq result t)
	collect result)
  nil)

;;; Look for :KEY NIL bugs

(deftest remove-duplicates.1
  (let* ((orig '(1 2 3 4 1 3 4 1 2 5 6 2 7))
	 (x (copy-seq orig))
	 (y (remove-duplicates x :key nil)))
    (and (equalp orig x) y))
  (3 4 1 5 6 2 7))

(deftest delete-duplicates.1
  (let* ((orig '(1 2 3 4 1 3 4 1 2 5 6 2 7))
	 (x (copy-seq orig))
	 (y (delete-duplicates x :key nil)))
    y)
  (3 4 1 5 6 2 7))

(defharmless remove-duplicates.test-and-test-not.1
  (remove-duplicates (list 'a 'b 'c 'd 'a 'e 'f 'd 'g) :test #'eql
		     :test-not #'eql))

(defharmless remove-duplicates.test-and-test-not.2
  (remove-duplicates (list 'a 'b 'c 'd 'a 'e 'f 'd 'g) :test-not #'eql
		     :test #'eql))

(defharmless delete-duplicates.test-and-test-not.1
  (delete-duplicates (list 'a 'b 'c 'd 'a 'e 'f 'd 'g) :test #'eql
		     :test-not #'eql))

(defharmless delete-duplicates.test-and-test-not.2
  (delete-duplicates (list 'a 'b 'c 'd 'a 'e 'f 'd 'g) :test-not #'eql
		     :test #'eql))

;;; Const fold tests

(def-fold-test remove-duplicates.fold.1 (remove-duplicates '(1 2 3 3)))
(def-fold-test remove-duplicates.fold.2 (remove-duplicates #(1 2 3 3)))
(def-fold-test remove-duplicates.fold.3 (remove-duplicates #*0011))
(def-fold-test remove-duplicates.fold.4 (remove-duplicates "1233"))

;;; Order of evaluation tests

(deftest remove-duplicates.order.1
  (let ((i 0) a b c d e f)
    (values
     (remove-duplicates
      (progn (setf a (incf i)) (list 1 2 3 1 3 1 2 4))
      :from-end (progn (setf b (incf i)) nil)
      :start (progn (setf c (incf i)) 0)
      :end (progn (setf d (incf i)) nil)
      :key (progn (setf e (incf i)) #'identity)
      :test (progn (setf f (incf i)) #'=)
      )
     i a b c d e f))
  (3 1 2 4) 6 1 2 3 4 5 6)

(deftest remove-duplicates.order.2
  (let ((i 0) a b c d e f)
    (values
     (remove-duplicates
      (progn (setf a (incf i)) (list 1 2 3 1 3 1 2 4))
      :test-not (progn (setf b (incf i)) #'/=)
      :key (progn (setf c (incf i)) #'identity)
      :end (progn (setf d (incf i)) nil)
      :start (progn (setf e (incf i)) 0)
      :from-end (progn (setf f (incf i)) nil)
      )
     i a b c d e f))
  (3 1 2 4) 6 1 2 3 4 5 6)
 

;;; Keyword tests

(deftest remove-duplicates.allow-other-keys.1
  (remove-duplicates '(1 2 3 4 2 7 8 1 5) :allow-other-keys t)
  (3 4 2 7 8 1 5))

(deftest remove-duplicates.allow-other-keys.2
  (remove-duplicates '(1 2 3 4 2 7 8 1 5) :allow-other-keys nil)
  (3 4 2 7 8 1 5))

(deftest remove-duplicates.allow-other-keys.3
  (remove-duplicates '(1 2 3 4 2 7 8 1 5) :bad t :allow-other-keys t)
  (3 4 2 7 8 1 5))

(deftest remove-duplicates.allow-other-keys.4
  (remove-duplicates '(1 2 3 4 2 7 8 1 5) :allow-other-keys t :bad t)
  (3 4 2 7 8 1 5))

(deftest remove-duplicates.allow-other-keys.5
  (remove-duplicates '(1 2 3 4 2 7 8 1 5) :bad t
		     :allow-other-keys t :allow-other-keys nil)
  (3 4 2 7 8 1 5))

(deftest remove-duplicates.allow-other-keys.6
  (remove-duplicates '(1 2 3 4 2 7 8 1 5)
		     :allow-other-keys t :bad t :allow-other-keys nil)
  (3 4 2 7 8 1 5))

(deftest remove-duplicates.allow-other-keys.7
  (remove-duplicates '(1 2 3 4 2 7 8 1 5)
		     :allow-other-keys t :allow-other-keys nil :bad t)
  (3 4 2 7 8 1 5))

(deftest remove-duplicates.allow-other-keys.8
  (remove-duplicates '(1 2 3 4 2 7 8 1 5)
		     :allow-other-keys t :from-end t)
  (1 2 3 4 7 8 5))

(deftest remove-duplicates.keywords.1
  (remove-duplicates '(1 2 3 4 2 7 8 1 5) :from-end t :from-end nil)
  (1 2 3 4 7 8 5))


(deftest delete-duplicates.allow-other-keys.1
  (delete-duplicates (list 1 2 3 4 2 7 8 1 5) :allow-other-keys t)
  (3 4 2 7 8 1 5))

(deftest delete-duplicates.allow-other-keys.2
  (delete-duplicates (list 1 2 3 4 2 7 8 1 5) :allow-other-keys nil)
  (3 4 2 7 8 1 5))

(deftest delete-duplicates.allow-other-keys.3
  (delete-duplicates (list 1 2 3 4 2 7 8 1 5) :bad t :allow-other-keys t)
  (3 4 2 7 8 1 5))

(deftest delete-duplicates.allow-other-keys.4
  (delete-duplicates (list 1 2 3 4 2 7 8 1 5) :allow-other-keys t :bad t)
  (3 4 2 7 8 1 5))

(deftest delete-duplicates.allow-other-keys.5
  (delete-duplicates (list 1 2 3 4 2 7 8 1 5) :bad t
		     :allow-other-keys t :allow-other-keys nil)
  (3 4 2 7 8 1 5))

(deftest delete-duplicates.allow-other-keys.6
  (delete-duplicates (list 1 2 3 4 2 7 8 1 5)
		     :allow-other-keys t :bad t :allow-other-keys nil)
  (3 4 2 7 8 1 5))

(deftest delete-duplicates.allow-other-keys.7
  (delete-duplicates (list 1 2 3 4 2 7 8 1 5)
		     :allow-other-keys t :allow-other-keys nil :bad t)
  (3 4 2 7 8 1 5))

(deftest delete-duplicates.allow-other-keys.8
  (delete-duplicates (list 1 2 3 4 2 7 8 1 5)
		     :allow-other-keys t :from-end t)
  (1 2 3 4 7 8 5))

(deftest delete-duplicates.keywords.1
  (delete-duplicates (list 1 2 3 4 2 7 8 1 5) :from-end t :from-end nil)
  (1 2 3 4 7 8 5))

;;; Order of evaluation tests

(deftest delete-duplicates.order.1
  (let ((i 0) a b c d e f)
    (values
     (delete-duplicates
      (progn (setf a (incf i)) (list 1 2 3 1 3 1 2 4))
      :from-end (progn (setf b (incf i)) nil)
      :start (progn (setf c (incf i)) 0)
      :end (progn (setf d (incf i)) nil)
      :key (progn (setf e (incf i)) #'identity)
      :test (progn (setf f (incf i)) #'=)
      )
     i a b c d e f))
  (3 1 2 4) 6 1 2 3 4 5 6)

(deftest delete-duplicates.order.2
  (let ((i 0) a b c d e f)
    (values
     (delete-duplicates
      (progn (setf a (incf i)) (list 1 2 3 1 3 1 2 4))
      :test-not (progn (setf b (incf i)) #'/=)
      :key (progn (setf c (incf i)) #'identity)
      :end (progn (setf d (incf i)) nil)
      :start (progn (setf e (incf i)) 0)
      :from-end (progn (setf f (incf i)) nil)
      )
     i a b c d e f))
  (3 1 2 4) 6 1 2 3 4 5 6)
 
;;; Error cases

(deftest remove-duplicates.error.1
  (signals-error (remove-duplicates) program-error)
  t)

(deftest remove-duplicates.error.2
  (signals-error (remove-duplicates nil :start) program-error)
  t)

(deftest remove-duplicates.error.3
  (signals-error (remove-duplicates nil 'bad t) program-error)
  t)

(deftest remove-duplicates.error.4
  (signals-error (remove-duplicates nil 'bad t :allow-other-keys nil) program-error)
  t)

(deftest remove-duplicates.error.5
  (signals-error (remove-duplicates nil 1 2) program-error)
  t)

(deftest remove-duplicates.error.6
  (signals-error (remove-duplicates (list 'a 'b 'c) :test #'identity) program-error)
  t)

(deftest remove-duplicates.error.7
  (signals-error (remove-duplicates (list 'a 'b 'c) :test-not #'identity) program-error)
  t)

(deftest remove-duplicates.error.8
  (signals-error (remove-duplicates (list 'a 'b 'c) :key #'cons) program-error)
  t)

(deftest remove-duplicates.error.9
  (signals-error (remove-duplicates (list 'a 'b 'c) :key #'car) type-error)
  t)

(deftest remove-duplicates.error.10
  (check-type-error #'remove-duplicates #'sequencep)
  nil)

;;;

(deftest delete-duplicates.error.1
  (signals-error (delete-duplicates) program-error)
  t)

(deftest delete-duplicates.error.2
  (signals-error (delete-duplicates nil :start) program-error)
  t)

(deftest delete-duplicates.error.3
  (signals-error (delete-duplicates nil 'bad t) program-error)
  t)

(deftest delete-duplicates.error.4
  (signals-error (delete-duplicates nil 'bad t :allow-other-keys nil) program-error)
  t)

(deftest delete-duplicates.error.5
  (signals-error (delete-duplicates nil 1 2) program-error)
  t)

(deftest delete-duplicates.error.6
  (signals-error (delete-duplicates (list 'a 'b 'c) :test #'identity) program-error)
  t)

(deftest delete-duplicates.error.7
  (signals-error (delete-duplicates (list 'a 'b 'c) :test-not #'identity) program-error)
  t)

(deftest delete-duplicates.error.8
  (signals-error (delete-duplicates (list 'a 'b 'c) :key #'cons) program-error)
  t)

(deftest delete-duplicates.error.9
  (signals-error (delete-duplicates (list 'a 'b 'c) :key #'car) type-error)
  t)

(deftest delete-duplicates.error.10
  (check-type-error #'delete-duplicates #'sequencep)
  nil)

;;; Specialized string tests

(deftest remove-duplicates.string.1
  (do-special-strings
   (s "abcadefabgz" nil)
   (let ((s2 (remove-duplicates s)))
     (assert (string= s "abcadefabgz"))
     (assert (equal (array-element-type s)
		    (array-element-type s2)))
     (assert (string= s2 "cdefabgz"))))
  nil)

(deftest remove-duplicates.string.2
  (do-special-strings
   (s "abcadefabgz" nil)
   (let ((s2 (remove-duplicates s :from-end t)))
     (assert (string= s "abcadefabgz"))
     (assert (equal (array-element-type s)
		    (array-element-type s2)))
     (assert (string= s2 "abcdefgz"))))
  nil)

(deftest delete-duplicates.string.1
  (do-special-strings
   (s "abcadefabgz" nil)
   (let ((aet (array-element-type s))
	 (s2 (delete-duplicates s)))
     (assert (equal aet (array-element-type s2)))
     (assert (string= s2 "cdefabgz"))))
  nil)

(deftest delete-duplicates.string.2
  (do-special-strings
   (s "abcadefabgz" nil)
   (let ((aet (array-element-type s))
	 (s2 (delete-duplicates s :from-end t)))
     (assert (equal aet (array-element-type s2)))
     (assert (string= s2 "abcdefgz"))))
  nil)

;;; Order of elements kept under EQUAL, EQUALP tests

(deftest remove-duplicates.2
  (let* ((x (list 'a))
	 (y (list 'a))
	 (result (remove-duplicates (list x y) :test 'equal)))
    (values
     result
     (notnot (eql (car result) x))
     (notnot (eql (car result) y))))
  ((a)) nil t)

(deftest remove-duplicates.2a
  (let* ((x (list 'a))
	 (y (list 'a))
	 (result (remove-duplicates (list x 'x y) :test 'equal)))
    (values
     result
     (notnot (eql (cadr result) x))
     (notnot (eql (cadr result) y))))
  (x (a)) nil t)

(deftest remove-duplicates.3
  (let* ((x (list 'a))
	 (y (list 'a))
	 (result (remove-duplicates (list x y) :test 'equal :from-end t)))
    (values
     result
     (notnot (eql (car result) x))
     (notnot (eql (car result) y))))
  ((a)) t nil)

(deftest remove-duplicates.3a
  (let* ((x (list 'a))
	 (y (list 'a))
	 (result (remove-duplicates (list x 'u 'v y) :test 'equal :from-end t)))
    (values
     result
     (notnot (eql (car result) x))
     (notnot (eql (car result) y))))
  ((a) u v) t nil)

(deftest remove-duplicates.4
  (let* ((x (list 'a))
	 (y (list 'a))
	 (result (remove-duplicates (list x y) :test 'equalp)))
    (values
     result
     (notnot (eql (car result) x))
     (notnot (eql (car result) y))))
  ((a)) nil t)

(deftest remove-duplicates.5
  (let* ((x (list 'a))
	 (y (list 'a))
	 (result (remove-duplicates (list x y) :test 'equalp :from-end t)))
    (values
     result
     (notnot (eql (car result) x))
     (notnot (eql (car result) y))))
  ((a)) t nil)

;;; Similar, but destructive

(deftest delete-duplicates.2
  (let* ((x (list 'a))
	 (y (list 'a))
	 (result (delete-duplicates (list x y) :test 'equal)))
    (values
     result
     (notnot (eql (car result) x))
     (notnot (eql (car result) y))))
  ((a)) nil t)

(deftest delete-duplicates.2a
  (let* ((x (list 'a))
	 (y (list 'a))
	 (result (delete-duplicates (list x 'x y) :test 'equal)))
    (values
     result
     (notnot (eql (cadr result) x))
     (notnot (eql (cadr result) y))))
  (x (a)) nil t)

(deftest delete-duplicates.3
  (let* ((x (list 'a))
	 (y (list 'a))
	 (result (delete-duplicates (list x y) :test 'equal :from-end t)))
    (values
     result
     (notnot (eql (car result) x))
     (notnot (eql (car result) y))))
  ((a)) t nil)

(deftest delete-duplicates.3a
  (let* ((x (list 'a))
	 (y (list 'a))
	 (result (delete-duplicates (list x 'u 'v y) :test 'equal :from-end t)))
    (values
     result
     (notnot (eql (car result) x))
     (notnot (eql (car result) y))))
  ((a) u v) t nil)

(deftest delete-duplicates.4
  (let* ((x (list 'a))
	 (y (list 'a))
	 (result (delete-duplicates (list x y) :test 'equalp)))
    (values
     result
     (notnot (eql (car result) x))
     (notnot (eql (car result) y))))
  ((a)) nil t)

(deftest delete-duplicates.5
  (let* ((x (list 'a))
	 (y (list 'a))
	 (result (delete-duplicates (list x y) :test 'equalp :from-end t)))
    (values
     result
     (notnot (eql (car result) x))
     (notnot (eql (car result) y))))
  ((a)) t nil)



    
    


		    