;; -*- scheme -*-
(use gauche.test)
(use srfi-1)
(use file.util)
(use srfi-13)
(test-start "scmail")

(use scmail)
(use scmail.mail)
(use scmail.mailbox)
(use scmail.config)

(test-module 'scmail)

(with-module scmail (export filter-rules
                            bayesian-filter
                            read-filter-rule))

(sys-system "rm -f test.log.mh test.log.maildir test.log.maildir2")
(sys-system "rm -rf test.Mail test.Maildir test.Maildir2")
(sys-system "cp -rp Mail test.Mail")
(sys-system "cp -rp Maildir test.Maildir")

(sys-system "cp -rp Maildir test.Maildir2")
(sys-system "mv test.Maildir2/cur/* test.Maildir2/new") ;; for testing "new"

(slot-set! (scmail-config) 'log-file 
           (build-path (current-directory) "test.log.scmail"))

(test* "filter-rules" #t
       (null? (filter-rules)))


(define valid-rules
  (list 
   '(from)
   '(from ("foo@example.org" "from.foo"))
   '(from ("foo@example.org" (copy "from.foo")))
   '(from ("foo@example.org" (remove)))
   '(from (#/foo@example.(org|com)#/ "from.foo"))
   '(from (("foo@example.org"
            #/foo@example.com/) "from.foo"))
   '(from ("foo@example.org" "from.foo")
          ("bar@example.org" "from.bar"))
   (lambda (mail)
     (and (mail 'from "foo@examle.org")
          (refile mail "from.foo")))
   (lambda (config mail)
     (if (string-contains? (scmail-mail-query mail 'from) 
                           "foo@examle.org")
         (command-refile config mail "from.foo")
         :next))
   ))

(define invalid-rules
  (list 
   'from
   '(from "foo@example.org")
   '(from ("foo@example.org"))
   '(from ("foo@example.org" "from.foo" 'extra))
   '(from ("foo@example.org" (copy "from.foo" 'extra)))
   '(from (("foo@example.org" "from.foo")))
   (lambda () #t)
   (lambda (a b c) #t)
   ))

(test* "valid-rule?" #t
       (every (lambda (rule)
                (valid-rule? rule))
              valid-rules))

(test* "valid-rule?" #t
       (every (lambda (rule)
                (not (valid-rule? rule)))
              invalid-rules))

(test "add-filter-rule!" #t
      (lambda ()
        (apply add-filter-rule! invalid-rules)
      (null? (filter-rules))))

(test "add-filter-rule!" #t
      (lambda ()
        (apply add-filter-rule! valid-rules)
        (equal? (filter-rules) valid-rules)))

(test "add-bayesian-filter-rule!" #t
      (lambda ()
        (add-bayesian-filter-rule!)
        (equal? (first (reverse (filter-rules)))
                bayesian-filter)))

(define (reset-filter-rules)
  (filter-rules '()))

(define (count-number-of-lines file)
  (if (file-exists? file)
      (let* ((iport (open-input-file file))
             (string (port->string iport)))
        (close-input-port iport)
        (string-count string #\newline))
      0))


;; borrowed from tests/mail.scm
(with-module 
 gauche.net
 (define (smtp-responses)
   (string-join (map number->string 
                     (list 220 250 250 250 354 250 221 ))
                "\n"))

 (define (call-with-client-socket socket proc)
   (call-with-input-string (smtp-responses)
                           (lambda (smtp-port)
                             (proc smtp-port
                                   (standard-output-port)))))

 (define (make-client-socket type host port)
   'dummy))

(define (number-of-files-in-directory directory)
  (length (directory-fold directory
                          (lambda (entry result)
                            (if (file-is-regular? entry)
                                (cons entry result)
                                result))
                          '())))

(define (test-mailbox task subdir)
  (let ((mailbox (make-scmail-mailbox (ref (scmail-config) 'mailbox-type)
                                      (ref (scmail-config) 'mailbox))))
    (test-section task)

    (test "scmail-command-log" #t
          (lambda ()
            (let1 before (count-number-of-lines 
                          (ref (scmail-config) 'log-file))
                  (scmail-command-log "test" "src" "dest")
                  (= (+ 1 before) 
                     (count-number-of-lines
                      (ref (scmail-config) 'log-file))))))

    (test "scmail-error-log" #t
          (lambda ()
            (let1 before (count-number-of-lines 
                          (ref (scmail-config) 'log-file))
                  (scmail-error-log "test error")
                  (= (+ 1 before) 
                     (count-number-of-lines 
                      (ref (scmail-config) 'log-file))))))

    (test "scmail-log" #t
          (lambda ()
            (let1 before (count-number-of-lines 
                          (ref (scmail-config) 'log-file))
                  (scmail-log "test log")
                  (= (+ 1 before) 
                     (count-number-of-lines 
                      (ref (scmail-config) 'log-file))))))

    (reset-filter-rules)
    (read-filter-rule "test-rules")

    (test "scmail-filter/copy/refile/forward/redirect" #t
          (lambda ()
            (let* ((mailbox-type (ref (scmail-config) 'mailbox-type))
                   (mailbox (make-scmail-mailbox 
                             mailbox-type (ref (scmail-config) 'mailbox))))
              (for-each (lambda (file)
                          (scmail-filter (make-scmail-mail 
                                          mailbox-type
                                          :mailbox mailbox
                                          :file file)))
                        (scmail-mailbox-mail-list 
                         mailbox (ref (scmail-config) 'inbox)))
              #t)))
    (test* "refile result" #t
           (every (lambda (pair)
                    (= (number-of-files-in-directory
                        (build-path (car pair)
                                    (if (eq? (ref (scmail-config) 
                                                  'mailbox-type)
                                             'maildir)
                                        subdir
                                        "")))
                       (cdr pair)))
                  (list (cons (scmail-mailbox-folder->path mailbox 
                               (ref (scmail-config) 'inbox)) 
                              1)
                        (cons (scmail-mailbox-folder->path mailbox "spam") 
                              2)
                        (cons (scmail-mailbox-folder->path mailbox "backup") 
                              8)
                        (cons (scmail-mailbox-folder->path mailbox "from.foo")
                              1)
                        (cons (scmail-mailbox-folder->path mailbox 
                                                           "to.former") 
                              1)
                        (cons (scmail-mailbox-folder->path mailbox 
                               "ml.test-ml-example-org") 1))))
    ))

(slot-set! (scmail-config) 'mailbox-type 'mh)
(slot-set! (scmail-config) 'mailbox (build-path (current-directory) 
                                                "test.Mail"))
(slot-set! (scmail-config) 'inbox "inbox")
(slot-set! (scmail-config) 'spam "spam")
(slot-set! (scmail-config) 'log-file 
           (build-path (current-directory) "test.log.mh"))
(test-mailbox "MH" "dummy")

(slot-set! (scmail-config) 'mailbox-type 'maildir)
(slot-set! (scmail-config) 'mailbox (build-path (current-directory)
                                                "test.Maildir"))
(slot-set! (scmail-config) 'inbox "")
(slot-set! (scmail-config) 'spam "spam")
(slot-set! (scmail-config) 'log-file 
           (build-path (current-directory) "test.log.maildir"))
(test-mailbox "Maildir" "cur")

(slot-set! (scmail-config) 'mailbox-type 'maildir)
(slot-set! (scmail-config) 'mailbox (build-path (current-directory)
                                                "test.Maildir2"))
(slot-set! (scmail-config) 'inbox "")
(slot-set! (scmail-config) 'spam "spam")
(slot-set! (scmail-config) 'log-file 
           (build-path (current-directory) "test.log.maildir2"))
(test-mailbox "Maildir2" "new")



(define (grep-c pattern file)
  (let1 count 0
        (call-with-input-file file
          (lambda (port)
            (port-for-each
             (lambda (line)
               (when (rxmatch pattern line)
                     (inc! count)
                     ))
             (cut read-line port))))
        count))
  
(define log-files (list "test.log.mh" "test.log.maildir" "test.log.maildir2"))

(test* "log files (number of lines)" #t
       (apply = (map count-number-of-lines log-files)))

(test* "log files (#<undef>)" #t
       (every (cut = <> 0) (map (lambda (file) (grep-c #/#<undef>/ file)) log-files)))

(test-end)

;; scmail-main
