;;; [Does the case of encrypting -zero- bytes work?  Not tested here!]

(require 'random)			; Low-quality randomness, for test data.
(require 'format)

(ssl:initialize!)

(define testfile "test-cryptfile-random")
(define max-string-length 10000)	; The longest any string may be.
(define max-string-number 100)		; The maximum number of strings we'll make.
(define data '())			; The random data we generate.

;;; These get set later.
(define key #f)
(define ec #f)
(define wcf #f)
(define dc #f)
(define rcf #f)
(define plain #f)

(define (make-random-string n)
  (define (mrs s i)
    (cond ((< i n)
	   (string-set! s i (integer->char (random 256)))
	   (mrs s (1+ i)))
	  (t s)))
  (mrs (make-string n) 0))

(define (make-random-strings)
  (define (mrs n i)
    (cond ((< i n)
	   (let ((j (random max-string-length)))
	     (set! data (append data (list (make-random-string j))))
	     (mrs n (1+ i))))))
  (let ((n (random max-string-number)))
    (format t "Making ~A random string~:P of no more than ~A byte~:P...~&"
	    n max-string-length)
    (mrs n 0)))

(define (write-data-0 x)
  (set! key (crypt:make-key (ssl:random-data 16)))
  (set! ec (crypt:make-encrypt-context key))
  (set! wcf (crypt:open-write ec x))
  (set! data '())
  (set! plain (open-output-file (string-append testfile ".plaintext")))
  (make-random-strings)
  (format t "Writing ~A string~:P.~&" (length data))
  (for-each (lambda (s)
	      (format wcf "~S" s)
	      (format plain "~S" s))
	    data)
  (close-port wcf)
  (close-port plain))

(define (write-data) (write-data-0 testfile))

(define (read-data-0 x)
  (set! dc (crypt:make-decrypt-context key))
  (set! rcf (crypt:open-read dc x))
  (set! plain (open-input-file (string-append testfile ".plaintext")))
  (format t "Reading ~A string~:P.~&" (length data))
  (for-each (lambda (original)
	      (let ((copy
		     (read rcf)
;		     (read plain)
		     ))
		(if (not (string=? original copy))
		    (format t "~&ORIG:  ~S~&COPY:  ~S~&"
			    original copy))))
	    data)
  (close-port rcf)
  (close-port plain))

(define (read-data) (read-data-0 testfile))

(define (test-data)
  (write-data)
  (read-data))

(define (test-data-string)
  (call-with-input-string (call-with-output-string write-data-0) read-data-0))

;;; Checking for bad data values, methodically.

(define (test-byte n crypt?)
  (cond (crypt?
	 (set! key (crypt:make-key (ssl:random-data 16)))
	 (set! ec (crypt:make-encrypt-context key))
	 (set! wcf (crypt:open-write ec testfile)))
	(t
	 (set! wcf (open-output-file (string-append testfile ".plaintext")))))
  (format t "~A" n)
  (force-output (current-output-port))
  ;; Surround w/"" so we can just use read.  Cheesy, but okay unless I want 1-char and not 3-char plaintexts.
  (format wcf "~S" (make-string 1 (integer->char n)))
  (close-port wcf)
  (cond (crypt?
	 (set! dc (crypt:make-decrypt-context key))
	 (set! rcf (crypt:open-read dc testfile)))
	(t
	 (set! rcf (open-input-file (string-append testfile ".plaintext")))))
  (let ((r (char->integer (string-ref (read rcf) 0))))
    (format t "~:[!~;.~]" (= n r))
    (force-output (current-output-port)))
  (close-port rcf))

(define (test-bytes crypt? from to)
  (define (tb n)
    (cond ((<= n to)
	   (test-byte n crypt?)
	   (tb (1+ n)))))
  (tb from))
  
;;; End of file.
