private/tests/unzip.ss
(module unzip mzscheme
  (require (planet "file.ss" ("dherman" "io.plt" 1)))
  (require (planet "test.ss" ("schematics" "schemeunit.plt" 1)))
  (require (planet "test.ss" ("dherman" "test.plt" 1)))
  (require (lib "etc.ss"))
  (require (lib "list.ss"))
  (require "../../zip.ss")
  (require "../../unzip.ss")
  (require "util.ss")

  (define file-for-each
    (opt-lambda (proc [dir (current-directory)])
      (for-each proc (file-map proc dir))))

  (define file-map
    (opt-lambda (proc [dir (current-directory)])
      (filter (lambda (path)
                (file-exists? (build-path dir path)))
              (directory-list/all dir))))

  (define file-andmap
    (opt-lambda (proc [dir (current-directory)])
      (andmap proc (file-map proc dir))))

  (define (make-arch-test-case arch)
    (make-test-case (format "unzip file zipped in ~a" arch)
                    (in-new-directory "sandbox"
                      (with-input-from-file (build-path 'up "arch" (format "~a.zip" arch)) unzip)
                      (assert-true
                       (and (file-andmap gettysburg-address?)
                            (dir-tree=? "example" ex:arch))))))

  (define test:arch
    (make-test-suite
     "test unzip on OS-specific zip files"
     (make-arch-test-case "winxp")
     (make-arch-test-case "macosx")
     (make-arch-test-case "cygwin")
     (make-arch-test-case "unix")
     ))

  (define-simple-assertion (assert-unzip example)
    (in-new-directory "sandbox"
      (in-new-directory "expected"
        (build-dir-tree example))        
      (let ([zip-file-list (directory-list/all "expected")])
        (with-output-to-file "test.zip"
          (lambda ()
            (parameterize ([current-directory "expected"])
              (zip zip-file-list))))
        (in-new-directory "actual"
          (with-input-from-file (build-path 'up "test.zip") unzip)))
      (directory=? "expected" "actual")))

  (define-simple-assertion (assert-read-zip-file example)
    (in-new-directory "sandbox"
      (in-new-directory "expected"
        (build-dir-tree example))
      (let ([zip-file-list (directory-list/all "expected")])
        (with-output-to-file "test.zip"
          (lambda ()
            (parameterize ([current-directory "expected"])
              (zip zip-file-list))))
        (let ([zip-dir (read-zip-directory "test.zip")])
          (in-new-directory "actual"
            (for-each (lambda (file)
                        (when (zip-directory-contains? file zip-dir)
                          (unzip-entry (build-path 'up "test.zip") zip-dir (path->zip-path file))))
                      zip-file-list))))
      (directory=? "expected" "actual")))

  ;; TODO: test behavior on directory entries where:
  ;;   - both MS-DOS directory bit and trailing slash
  ;;   - only MS-DOS directory bit
  ;;   - only trailing slash

  (define test:unzip
    (make-test-suite
     "unzip tests"
     (make-test-case "single file, no subdirectories"
                     (assert-unzip ex:single-file/no-directories))
     (make-test-case "multiple files and no subdirectories"
                     (assert-unzip ex:multiple-files/no-directories))
     (make-test-case "multiple files and subdirectories"
                     (assert-unzip ex:multiple-files/subdirectories))
     (make-test-case "multiple files, subdirectories, some empty"
                     (assert-unzip ex:multiple-files/subdirectories/empty-directories))
     ))

  (define test:read-zip-file
    (make-test-suite
     "read-zip-file tests"
     (make-test-case "single file, no subdirectories"
                     (assert-read-zip-file ex:single-file/no-directories))
     (make-test-case "multiple files and no subdirectories"
                     (assert-read-zip-file ex:multiple-files/no-directories))
     (make-test-case "multiple files and subdirectories"
                     (assert-read-zip-file ex:multiple-files/subdirectories))
     (make-test-case "multiple files, subdirectories, some empty"
                     (assert-read-zip-file ex:multiple-files/subdirectories/empty-directories))
     ))

  (define unzip-tests
    (make-test-suite
     "All unzip.ss tests"
     test:arch
     test:unzip
     test:read-zip-file
     ))

  (provide unzip-tests))