test/test-file-utils.rkt
#lang racket
(provide file-utils-tests test-all)

(require rackunit
         rackunit/gui
         "../file-utils.rkt")

(define file-utils-tests
  (test-suite 
   "File-Utils Library"
   (let ((testfolder (build-path "testfiles"))
         (testfile (build-path "testfiles" "testfile.txt")))
     
   (test-case
    "get-file-or-folder-name of folder"
    (check-equal? "testfiles" (get-file-or-folder-name testfolder)))
     
   (test-case
    "get-file-or-folder-name of file"
    (check-equal? (get-file-or-folder-name testfile)
                  "testfile.txt" ))
     
   (test-case
    "get-file-or-folder-name taking string"
    (check-equal? (get-file-or-folder-name (path->string (build-path "testfiles")))
                  "testfiles" ))
     
   (test-case
    "name-as-string of folder"
    (check-equal? (name-as-string testfolder) "testfiles"))
     
   (test-case
    "name-as-string of file"
    (check-equal? (name-as-string testfile) "testfile.txt"))
     
   (test-case
    "name-as-string taking string"
    (check-equal? (name-as-string testfolder)
                  "testfiles" ))
     
   (test-case
    "filename-main"
    (check-equal? (filename-main testfile)
                  "testfile"))
     
   (test-case 
    "filename-main without suffix"
    (check-equal? (filename-main testfolder)
                  "testfiles" ))
     
   (test-case
    "filename-main empty name"
    (check-equal? (filename-main (build-path "testfiles" ".mp3"))
                  ""))
                  
   (test-case
    "filename-main empty string"
    (check-equal? (filename-main "") "" ))
     
   (test-case
    "filename-suffix"
    (check-equal? (filename-suffix testfile) "txt"))
     
   (test-case
    "filename-suffix string"
    (check-equal? (filename-suffix "hello.mp3") "mp3" ))
     
   (test-case
    "filename-suffix empty suffix"
    (check-equal? "" (filename-suffix "hello")))
     
   (test-case
    "filename-suffix empty malformed suffix"
    (check-equal? (filename-suffix "hello.") ""))
     
   (test-case 
    "filename-suffix empty"
    (check-equal? (filename-suffix "")  ""))
     
   (test-case 
    "filename-suffix multiple suffixes"
    (check-equal? (filename-suffix (build-path "testfiles" "picture.tif.mp3"))
                  "mp3"))
     
   (test-case
    "compose-name"
    (check-equal? (compose-name "test" 23 "txt")
                  "test-23.txt" ))
     
   (test-case
    "compose-name no number"
    (check-equal? (compose-name "test" #f "txt")
                  "test.txt"))
     
   (test-case
    "compose-name empty suffix"
    (check-equal? (compose-name "test" 23 "")
                  "test-23"))
     
   (test-case
    "compose-name no number, empty suffix"
    (check-equal? (compose-name "test" #f "")
                  "test"))
     
   (test-case
    "compose-name empty name"
    (check-equal? (compose-name "" 23 "txt")
                  "-23.txt"))
     
   (test-case
    "compose-name everything empty"
    (check-equal? "" (compose-name "" #f "")))
     
   (test-case
    "make-unique-name"
    (check-false (file-exists? (make-unique-name "testfile.txt"
                                                 testfolder))))
     
   (test-case
    "make-unique-name nonexistent file"
    (check-equal? (make-unique-name (build-path "testfiles" "humpty.bla")
                                                 (build-path "testfiles"))
                  (build-path "testfiles" "humpty.bla")))
     
   (test-case
    "parent-directory"
    (check-equal? (parent-directory testfile) (path->complete-path testfolder)))
     
   (test-case
    "make-unique-path"
    (check-false (file-exists? (make-unique-path testfile))))
     
   (test-case
    "make-unique-path returns path"
    (check-true (path? (make-unique-path testfile))))
     
   (test-case
    "path-equal?"
    (check-true (path-equal? testfile (path->complete-path testfile))))
     
   (test-case
    "path-equal? does not depend on file existence"
    (check-true (path-equal? (build-path "testfiles" "foobar.txt") (path->complete-path (build-path "testfiles" "foobar.txt")))))
     
   (test-case
    "file=?"
    (check-true (file=? testfile testfile)))
     
   (test-case
    "file=? requires existent file"
    (check-false (file=? (build-path "testfiles" "foobar.txt") (build-path "testfiles" "foobar.txt") )))
     
   (test-case
    "move-folder-to"
    (let ((from (build-path "test-received"))
          (to (build-path "testfiles"))
          (chk (build-path "testfiles" "test-received")))
      (move-folder-to from to)
      (check-true (directory-exists? chk))))
     
   (test-case
    "move-folder-to revert changes"
    (let ((from (build-path "testfiles" "test-received"))
          (to (current-directory))
          (chk (build-path "test-received")))
      (move-folder-to from to)
      (check-true (directory-exists? chk))))
     
   (test-case
    "copy-folders/renaming"
    (let ((from (current-directory))
          (to (build-path "testfiles"))
          (chk (build-path "testfiles" "test-received")))
      (copy-folders/renaming from to (lambda (p) (equal? (filename-main p) "test-received")))
      (let ((result (directory-exists? chk)))
        (delete-directory chk)
        (check-true result))))
     
   (test-case 
    "is-visible? visible file"
    (check-true (file-is-visible? testfile)))
     
   (test-case
    "is-visible? invisible file"
    (check-false (file-is-visible? (build-path testfolder ".info"))))
     
   (test-case
    "count-lines mixed"
    (let ((in (open-input-string "\n\rhello\n\rworld\n")))
      (check-equal? (count-lines in) 3)))
     
   (test-case
    "count-lines empty"
    (let ((in (open-input-string "")))
      (check-equal? (count-lines in) 0)))
     
   (test-case
    "count-lines LF"
    (let ((in (open-input-string "\n\n\n\n")))
      (check-equal? (count-lines in) 4)))
     
   (test-case
    "count-lines one line"
    (let ((in (open-input-string "\n\rhello")))
      (check-equal? (count-lines in) 2)))
     
   (test-case
    "count-lines one line"
    (let ((in (open-input-string "\n\r\n\n\nhello")))
      (check-equal? (count-lines in) 5)))
     
   (test-case
    "move-file-to"
    (let ((source testfile)
          (target (build-path "test-received" "testfile.txt")))
                 (move-file-to source target)
      (check-true (file-exists? target))))
     
   (test-case
    "move-file-to source moved"
    (check-false (file-exists? (build-path "testfiles" "testfile.txt"))))
     
   (test-case
    "move-file-to move back"
      (let ((source (build-path "test-received" "testfile.txt"))
          (target testfile))
         (move-file-to source target)
         (check-true (file-exists? target))))
     
   (test-case
    "move-file-to original moved (2)"
    (check-false (file-exists? (build-path "test-received" "testfile.txt"))))
     
   (test-case
    "file-equal? identical file"
    (check-true (file-equal? testfile testfile)))
     
   (test-case
    "file-equal? two copies"
    (let ((source testfile)
          (target (build-path "test-received" "testfile.txt")))
      (copy-file source target)
      (check-true (file-equal? source target))
      (delete-file target)))
     
   (test-case 
    "file-equal? files do not exist"
    (check-exn exn:fail? (lambda () (file-equal? (build-path "testfiles" "nonexistent")
                                                 (build-path "testfiles" "nonexistent")))))
     
   (test-case 
    "file-equal? different files, same size"
     (let ((source testfile)
          (target (build-path "test-received" "testfile.txt")))
      (copy-file source target)
       (let ((out (open-output-file target #:mode 'binary #:exists 'update)))
         (file-position out 10)
         (write-byte 72 out)
         (close-output-port out))
       (check-false (file-equal? source target))
       (delete-file target)))
   )))
        
(define (setup)
  (when (directory-exists? (build-path "test-received"))
    (delete-directory/files (build-path "test-received")))
  (make-directory (build-path "test-received")))

(define (test-all)
  (setup)
  (test/gui file-utils-tests))